一個常見的問題是,ECMAScript 和 JavaScript 究竟是什麼關係?javascript
要講清楚這個問題,須要回顧歷史。1996 年 11 月,JavaScript 的創造者 Netscape 公司,決定將 JavaScript 提交給標準化組織 ECMA,但願這種語言可以成爲國際標準。次年,ECMA 發佈 262 號標準文件(ECMA-262)的初版,規定了瀏覽器腳本語言的標準,並將這種語言稱爲 ECMAScript,這個版本就是 1.0 版。html
所以,ECMAScript 和 JavaScript 的關係是,前者是後者的規格,後者是前者的一種實現(另外的 ECMAScript 方言還有 Jscript 和 ActionScript)java
ECMAScript 2015(簡稱 ES2015)這個詞,也是常常能夠看到的。它與 ES6 是什麼關係呢?jquery
2011 年,ECMAScript 5.1 版發佈後,就開始制定 6.0 版了。所以,ES6 這個詞的原意,就是指 JavaScript 語言的下一個版本。es6
ES6 的第一個版本,在 2015 年 6 月發佈,正式名稱是《ECMAScript 2015 標準》(簡稱 ES2015)。ajax
2016 年 6 月,小幅修訂的《ECMAScript 2016 標準》(簡稱 ES2016)如期發佈,這個版本能夠看做是 ES6.1 版,由於二者的差別很是小,基本上是同一個標準。根據計劃,2017 年 6 月發佈 ES2017 標準。編程
所以,ES6 既是一個歷史名詞,也是一個泛指,含義是 5.1 版之後的 JavaScript 的下一代標準,涵蓋了 ES201五、ES201六、ES2017 等等,json
而 ES2015 則是正式名稱,特指該年發佈的正式版本的語言標準。本書中提到 ES6 的地方,通常是指 ES2015 標準,但有時也是泛指「下一代 JavaScript 語言」。api
// var 聲明的變量沒有局部做用域 // let 聲明的變量 有局部做用域 { var a = 0 let b = 1 } console.log(a) // 0 console.log(b) // ReferenceError: b is not defined
// var 能夠聲明屢次 // let 只能聲明一次 var m = 1 var m = 2 let n = 3 let n = 4 console.log(m) // 2 console.log(n) // Identifier 'n' has already been declared
// var 會變量提高 // let 不存在變量提高 console.log(x) //undefined var x = "apple" console.log(y) //ReferenceError: y is not defined let y = "banana"
// 一、聲明以後不容許改變 const PI = "3.1415926" PI = 3 // TypeError: Assignment to constant variable. // 二、一但聲明必須初始化,不然會報錯 const MY_AGE // SyntaxError: Missing initializer in const declaration
解構賦值是對賦值運算符的擴展。數組
他是一種針對數組或者對象進行模式匹配,而後對其中的變量進行賦值。
在代碼書寫上簡潔且易讀,語義更加清晰明瞭;也方便了複雜對象中數據字段獲取。
//一、數組解構 // 傳統 let a = 1, b = 2, c = 3 console.log(a, b, c) // ES6 let [x, y, z] = [1, 2, 3] console.log(x, y, z)
//二、對象解構 let user = {name: 'Helen', age: 18} // 傳統 let name1 = user.name let age1 = user.age console.log(name1, age1) // ES6 let { name, age } = user//注意:結構的變量必須是user中的屬性 console.log(name, age)
模板字符串至關於增強版的字符串,用反引號 `,除了做爲普通字符串,還能夠用來定義多行字符串,還能夠在字符串中加入變量和表達式。
// 一、多行字符串 let string1 = `Hey, can you stop angry now?` console.log(string1) // Hey, // can you stop angry now?
// 二、字符串插入變量和表達式。變量名寫在 ${} 中,${} 中能夠放入 JavaScript 表達式。 let name = "Mike" let age = 27 let info = `My Name is ${name},I am ${age+1} years old next year.` console.log(info) // My Name is Mike,I am 28 years old next year.
// 三、字符串中調用函數 function f(){ return "have fun!" } let string2 = `Game start,${f()}` console.log(string2); // Game start,have fun!
const age = 12 const name = "Amy" // 傳統 const person1 = {age: age, name: name} console.log(person1) // ES6 const person2 = {age, name} console.log(person2) //{age: 12, name: "Amy"}
// 傳統 const person1 = { sayHi:function(){ console.log("Hi") } } person1.sayHi();//"Hi" // ES6 const person2 = { sayHi(){ console.log("Hi") } } person2.sayHi() //"Hi"
拓展運算符(...)用於取出參數對象全部可遍歷屬性而後拷貝到當前對象。
<script> //對象拓展運算符 //一、複製對象 let user ={name:'zhangsan',age:18} let someone =user; console.log(someone) //age: 18 name: "zhangsan" let someone1 = {...user} console.log(someone1) //{name: "zhangsan", age: 18} /** * 這個與java使用內存的方法一致 * someone 是指向user的內存地址 * someone1 是從新複製了一個user,是一個新的內存地址 */ //二、合併對象{多個對象合併成一個對象} let name = {name:"lisi"} let age = {age:19} let someone3 = {...name,...age}; console.log(someone3) //{name: "lisi", age: 19} //合併字段,字段名不能一致,不然後面的覆蓋前面的 let someone4 = {...someone1,...someone3}; console.log(someone4)//{name: "lisi", age: 19} </script>
function showInfo(name, age = 17) { console.log(name + "," + age) } // 只有在未傳遞參數,或者參數爲 undefined 時,纔會使用默認參數 // null 值被認爲是有效的值傳遞。 showInfo("Amy", 18) // Amy,18 showInfo("Amy", "") // Amy, showInfo("Amy", null) // Amy, null showInfo("Amy") // Amy,17 showInfo("Amy", undefined) // Amy,17
不定參數用來表示不肯定參數個數,形如,...變量名,由...加上一個具名參數標識符組成。具名參數只能放在參數列表的最後,而且有且只有一個不定參數。
function f(...values) { console.log(values.length) } f(1, 2) //2 f(1, 2, 3, 4) //4
箭頭函數提供了一種更加簡潔的函數書寫方式。基本語法是: 參數 => 函數體
// 傳統 var f1 = function(a){ return a } console.log(f1(1)) // ES6 var f2 = a => a console.log(f2(1))
在JavaScript的世界中,全部代碼都是單線程執行的。因爲這個「缺陷」,致使JavaScript的全部網絡操做,瀏覽器事件,都必須是異步執行。
異步執行能夠用回調函數實現:
例一、定時器
// 一、timeout的定時器功能使用了回調函數 console.log('before setTimeout()') setTimeout(()=>{ console.log('Done') }, 1000) // 1秒鐘後調用callback函數 console.log('after setTimeout()')
例二、ajax
mock/user.json
{ "id": "1", "username":"helen", "age":18 }
html頁面引入jquery.js
<script src="jquery.min.js"></script>
// 二、ajax功能使用了回調函數 $.get('mock/user.json', (data)=>{ console.log(data) })
例三、1秒後執行ajax操做
// 一、timeout的定時器功能使用了回調函數 console.log('before setTimeout()') setTimeout(() => { console.log('Done') // 二、ajax功能使用了回調函數 $.get('mock/user.json', (data) => { console.log(data) }) }, 1000); // 1秒鐘後調用callback函數 console.log('after setTimeout()')
例四、1秒後獲取用戶數據,而後根據用戶id獲取用戶登陸日誌
mock/login-log-1.json
{ "items": [ { "date":"2018-12-01", "ip":"10.10.10.10" }, { "date":"2018-12-01", "ip":"10.10.10.10" } ] }
回調函數嵌套的噩夢
// 一、1秒後獲取用戶數據 console.log('before setTimeout()') setTimeout(() => { console.log('Done') // 二、獲取用戶數據 $.get('mock/user.json', (data) => { console.log(data) // 三、獲取當前用戶的登陸日誌 $.get(`mock/login-log-${data.id}.json`, (data) => { console.log(data) }) }) }, 1000) // 1秒鐘後調用callback函數 console.log('after setTimeout()')
Promise是異步編程的一種解決方案。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的響應消息。古人云:「君子一言既出;駟馬難追」,這種「承諾未來會執行」的對象在JavaScript中稱爲Promise對象。
<script src="jquery.min.js"></script> <script> var p1 = new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve()//成功後交給resolve去執行回調的內容 }, 1000) }) p1.then(()=>{//成功 console.log('Done') //還有後續動做,因此接着返回promise return new Promise((resolve, reject)=>{ $.get(`mock/user.json`, (data) => { resolve(data) }) }) }) .then((data)=>{//成功 console.log(data) $.get(`mock/login-log-${data.id}.json`, (data) => { console.log(data) }) //若是以後還有後續動做,那麼接着返回promise // return new Promise((resolve, reject)=>{ // $.get(`mock/login-log-${data.id}.json`, (data) => { // resolve(data) // }) // }) }) </script>
有錯誤處理的promise案例
<script src="jquery.min.js"></script> <script> var p1 = new Promise((resolve, reject)=>{ setTimeout(()=>{ resolve()//成功後交給resolve去執行回調的內容 }, 1000) }) p1.then(()=>{//成功 console.log('Done') //還有後續動做,因此接着返回promise return new Promise((resolve, reject)=>{ $.ajax({ url: 'mock/user.json', type: 'get', success(data){ resolve(data)//成功後交給resolve去執行回調的內容 }, error(){ reject()//失敗後交給reject去處理失敗 } }) }) }) .then((data)=>{//成功 console.log(data) $.get(`mock/login-log-${data.id}.json`, (data) => { console.log(data) }) //若是以後還有後續動做,那麼接着返回promise // return new Promise((resolve, reject)=>{ // $.get(`mock/login-log-${data.id}.json`, (data) => { // resolve(data); // } // }) }, ()=>{//處理失敗:then方法的第二個參數是失敗的回調 console.log('出錯啦!') }) </script>
也可使用catch處理失敗
.then((data)=>{//成功 }) .catch(()=>{//處理失敗:then方法的第二個參數是失敗的回調 console.log('出錯啦!') })
隨着網站逐漸變成"互聯網應用程序",嵌入網頁的Javascript代碼愈來愈龐大,愈來愈複雜。
Javascript模塊化編程,已經成爲一個迫切的需求。理想狀況下,開發者只須要實現核心的業務邏輯,其餘均可以加載別人已經寫好的模塊。
可是,Javascript不是一種模塊化編程語言,它不支持"類"(class),更遑論"模塊"(module)了。
在 ES6 前, 實現模塊化使用的是 RequireJS 或者 seaJS(分別是基於 AMD 規範的模塊化庫, 和基於 CMD 規範的模塊化庫)。 ES6 引入了模塊化,其設計思想是在編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。
ES6 的模塊化分爲導出(export) @與導入(import)兩個模塊。
建立api/user.js
let getList = () => { console.log('獲取數據列表') } let save = () => { console.log('保存數據') } export { getList, save }
建立component/user.js
(注意:瀏覽器不支持不少ES6的高級功能,咱們須要使用babel將其轉換成ES5,後面的課程將會介紹)
import { getList, save } from "../api/user.js"
console.log(getList())
console.log(save())