一、内容概要
- ECMAScript 與 JavaScript
- ECMAScript 的發展過程
- ECMAScript 2015的新特性
- And more…
二、ECMAScript 概述
- JavaScript 是在 ECMAScript 的基礎上擴充的語言。
- JavaScript @ web端:ECMAScript和WebAPI(DOM、BOM)組成
- JavaScript @ node.js端:ECMAScript和 Node APIs (fs、net、etc)組成
三、ECMAScript 2015 (ES6)
1.ES6學習概要
- 解決原有文法上的一些問題或者不足
- 對原有文法進行增強
- 全新的對象、全新的方法、全新的功能
- 全新的資料類型和資料結構
2.準備工作(學習環境)
- 運作環境 : node(用) 和浏覽器都行
- 自動監聽 node 運作,用 nodemon 包:
/* 指令行輸入*/ npm init // 初始化 npm install -g nodemon // 安裝包 nodemon index.js // 啟動項目
3.ES2015 let 和 塊級作用域
作用域
- 全局作用域
- 函數作用域
- 塊級作用域(es2015 新增)
- var 聲明的變量會産生作用域提升。
- let 關鍵字聲明的變量不會提升,必須先聲明才能用,否則報錯:引用異常
4.ES2015 const 關鍵詞
- const 是用來定義 JavaScript 的常量(恒量)的。
- const 隻是在 let 的基礎上多了個隻讀的特性。
- const 隻有在聲明的同時指派,否則會報錯。
const obj = {}; obj.name = 'linxing'; // 不會報錯,因為沒有改變obj的引用位址,隻是增加了obj的屬性 obj = {}; // 錯誤,修改了obj的引用值
- 最佳實踐:不用 var , 主用 const,變量需要改變才用 let
5.ES2015 數組的解構
const arr = [100, 200, 300]
/* 不用解構的做法 */
// const foo = arr[0]
// const bar = arr[1]
// const baz = arr[2]
// console.log(foo, bar, baz) // 100 200 300
/*解構的做法*/
// const [foo, bar, baz] = arr
// console.log(foo, bar, baz) // 100 200 300
// const [, , baz] = arr // 不需要的參數可以用 , 分開
// console.log(baz) // 300
// const [foo, ...rest] = arr // 可以用 ...的文法擷取剩餘參數(隻能放在最後面)
// console.log(rest) // [ 200, 300 ]
// const [foo, bar, baz, more] = arr // 當左邊參數多于右邊 多餘的變成 undefined
// console.log(more) // undefined
// const [foo, bar, baz = 123, more = 'default value'] = arr // 給預設參數
// console.log(bar, more) // 200 default value
/*示例*/
const path = '/foo/bar/baz'
// const tmp = path.split('/')
// const rootdir = tmp[1]
const [, rootdir] = path.split('/')
console.log(rootdir)
5.ES2015 對象的解構
- 對象的解構采用的是 屬性比對
const obj = { name: 'zce', age: 18 } const { name } = obj console.log(name) // 'zce'
- 對象的解構重命名
const obj = { name: 'zce', age: 18 } const name = 'tom' const { name: objName } = obj console.log(objName) // 'zce'
- 對象的解構重命名+給預設值
const { log } = console; const obj = { name: 'zce', age: 18 } const name = 'tom' const { name: objName = 'linxing' } = obj log(objName) // 'zce'
6.ES2015 字元串模闆(``)
- 字元串模闆中間可以使用 ${變量名} 包裹變量
- 示例
const name = 'tom' const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}` console.log(msg) // hey, tom --- 3 ---- 0.15891994236543483
7.ES2015 帶标簽的模闆字元串(``)
- 模闆字元串的标簽就是一個特殊的函數,用來重新渲染處理模闆引擎。
- 使用這個标簽就是調用這個函數
const name = 'tom' const gender = false function myTagFunc (strings, name, gender) { // strings 是個以 ${} 切割的數組 // console.log(strings, name, gender) // return '123' const sex = gender ? 'man' : 'woman' return strings[0] + name + strings[1] + sex + strings[2] } const result = myTagFunc`hey, ${name} is a ${gender}.` console.log(result)
8.ES2015 字元串的擴充文法
- str.startsWith(params ) : 查找字元串中的開頭是否以 params 開頭,傳回 boolean 類型。
- str.endsWith(params ) : 查找字元串中的結尾是否以 params 開頭,傳回 boolean 類型。
- str.includes(params ) : 查找字元串中是否包含 params ,傳回 boolean 類型。
const message = 'Error: foo is not defined.' console.log( // message.startsWith('Error') // true // message.endsWith('.') // true message.includes('foo') // true )
9.ES2015 參數的預設值
- es2015 之前使用短路 (||)的方式設定預設參數,這是錯誤的做法
function foo (enable) { // 短路運算很多情況下是不适合判斷預設參數的,例如 0 '' false null // enable = enable || true enable = enable === undefined ? true : enable console.log('foo invoked - enable: ') console.log(enable) } foo(false)
- 預設參數一定是在形參清單的最後
function foo (enable = true) { console.log('foo invoked - enable: ') console.log(enable) } foo(false)
10.ES2015 剩餘參數
- es2015 之前是使用 arguments 的僞數組去接受參數。
- es2015 中使用 … 去接受 ,但是參數有多個的時候需要放在最後面
function foo (first, ...args) { console.log(args) } foo(1, 2, 3, 4)
11.ES2015 展開數組
const arr = ['foo', 'bar', 'baz']
// console.log( // 原始方法
// arr[0],
// arr[1],
// arr[2],
// )
// console.log.apply(console, arr) // es2015 之前的方法
console.log(...arr) // ...方式
12.ES2015 箭頭函數
- 使用箭頭函數 能使代碼更加簡單易讀。
const inc = n => n + 1 console.log(inc(100)) // 101
13.ES2015 箭頭函數和this指向
const person = {
name: 'tom',
// sayHi: function () {
// console.log(`hi, my name is ${this.name}`)
// }
sayHi: () => {
console.log(`hi, my name is ${this.name}`) // hi, my name is undefined
},
sayHiAsync: function () {
// const _this = this // 用變量儲存起來
// setTimeout(function () {
// console.log(_this.name)
// }, 1000)
console.log(this)
setTimeout(() => {
// console.log(this.name)
console.log(this)
}, 1000)
}
}
person.sayHiAsync()
14.ES1025 對象字面量的文法增強
const bar = '345'
const obj = {
foo: 123,
// bar: bar
// 屬性名與變量名相同,可以省略 : bar
bar,
// method1: function () {
// console.log('method111')
// }
// 方法可以省略 : function
method1 () {
console.log('method111')
// 這種方法就是普通的函數,同樣影響 this 指向。
console.log(this)
},
// Math.random(): 123 // 不允許
// 通過 [] 讓表達式的結果作為屬性名
[bar]: 123
}
// obj[Math.random()] = 123
console.log(obj)
obj.method1()
15.ES2015 Object.assign()
- object.assig()方法是把源對象裡的屬性來賦給目标對象。(有則覆寫,沒有則添加)。
const source1 = { a: 123, b: 123 } const source2 = { b: 789, d: 789 } const target = { a: 456, c: 456 } const result = Object.assign(target, source1, source2) // target為目标對象,其他的源對象 console.log(target) // { a: 123, c: 456, b: 789, d: 789 } console.log(result === target) // true
- 應用場景
function func (obj) { // obj.name = 'func obj' // console.log(obj) const funcObj = Object.assign({}, obj) funcObj.name = 'func obj' console.log(funcObj) } const obj = { name: 'global obj' } func(obj) console.log(obj)
16.ES2015 Object.is()
console.log(
// 0 == false // => true
// 0 === false // => false
// +0 === -0 // => true
// NaN === NaN // => false
// Object.is(+0, -0) // => false
// Object.is(NaN, NaN) // => true
)
17.ES2015 Proxy
- 這是vue.3 開始用 proxy 處理響應資料,vue3以前使用的是Object.defineProperty()方法響應資料。
-
const person = { name: 'zce', age: 20 } const personProxy = new Proxy(person, { // 監視屬性讀取 get (target, property) { return property in target ? target[property] : 'default' // console.log(target, property) // return 100 }, // 監視屬性設定 set (target, property, value) { if (property === 'age') { if (!Number.isInteger(value)) { throw new TypeError(`${value} is not an int`) } } target[property] = value // console.log(target, property, value) } }) personProxy.age = 100 personProxy.gender = true
18.ES2015 Proxy 對比 Object.defineProperty() 方法
- Proxy 是以非入侵的方式監管了對象的讀寫
const person = {} Object.defineProperty(person, 'name', { get () { console.log('name 被通路') return person._name }, set (value) { console.log('name 被設定') person._name = value } }) Object.defineProperty(person, 'age', { get () { console.log('age 被通路') return person._age }, set (value) { console.log('age 被設定') person._age = value } }) person.name = 'jack' console.log(person.name)
- Proxy 比 Object.defineProperty() 更加強大,可以直接監聽數組,而不需要對數組進行額外操作。
const list = [] const listProxy = new Proxy(list, { set (target, property, value) { console.log('set', property, value) target[property] = value return true // 表示設定成功 } }) listProxy.push(100) listProxy.push(100)
- Proxy 可以監視讀寫以外的操作
const person = { name: 'zce', age: 20 } const personProxy = new Proxy(person, { deleteProperty (target, property) { console.log('delete', property) delete target[property] } }) delete personProxy.age console.log(person)
- Proxy 方式更為合理
const person2 = { name: 'zce', age: 20 } const personProxy = new Proxy(person2, { get (target, property) { console.log('get', property) return target[property] }, set (target, property, value) { console.log('set', property, value) target[property] = value } }) personProxy.name = 'jack' console.log(personProxy.name)
19.ES2015 Reflect方法
- Reflect 内部封裝了一系列對對象的底層操作
const obj = {
name: 'zce',
age: 18
}
// console.log('name' in obj)
// console.log(delete obj['age'])
// console.log(Object.keys(obj))
console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))
20.ES2015 Promise
21.ES2015 Class類
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
}
const p = new Person('tom')
p.say()
22.ES2015 Class 類的靜态方法
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
static create (name) {
return new Person(name)
}
}
const tom = Person.create('tom')
tom.say()
23.ES2015 Class 類的繼承(extends super())
class Person {
constructor (name) {
this.name = name
}
say () {
console.log(`hi, my name is ${this.name}`)
}
}
class Student extends Person {
constructor (name, number) {
super(name) // 父類構造函數
this.number = number
}
hello () {
super.say() // 調用父類成員
console.log(`my school number is ${this.number}`)
}
}
const s = new Student('jack', '100')
s.hello()
24.Set()資料解構
- 确儲存儲在 Set 資料結構的唯一性。
- 添加方法:setData.add (params)
- 删除方法:setData.delete(params)
- 查找方法:setData.has(parsms)
- 清除方法:setData.clear()
const s = new Set() s.add(1).add(2).add(3).add(4).add(2) console.log(s) s.forEach(i => console.log(i)) for (let i of s) { console.log(i) } console.log(s.size) console.log(s.has(100)) console.log(s.delete(3)) console.log(s) s.clear() console.log(s)
- 經常用來給數組去重
const arr = [1, 2, 1, 3, 4, 1] // const result = Array.from(new Set(arr)) const result = [...new Set(arr)] console.log(result)
25.ES2015 Map()資料結構
- 可以運用任意類型的值作為鍵
- 鍵 =》值
const m = new Map()
const tom = { name: 'tom' }
m.set(tom, 90)
console.log(m)
console.log(m.get(tom))
// m.has()
// m.delete()
// m.clear()
m.forEach((value, key) => {
console.log(value, key)
})
26.ES2015 Symbol()資料結構
- 擴充對象,屬性名沖突問題
- 兩個 Symbol 永遠不會相等
- 使用 Symbol 為對象添加用不重複的鍵
- Symbol 模拟實作私有成員
- 最主要功能就是為對象添加獨一無二的屬性名
const name = Symbol()
const person = {
[name]: 'zce',
say () {
console.log(this[name])
}
}
27.ES2015 for…fo循環
const arr = [100, 200, 300, 400]
for (const item of arr) {
console.log(item) // 100 200 300 400
if (item > 100) {
break
}
}
28.ES2015 實作可疊代接口
const set = new Set(['foo', 'bar', 'baz'])
const iterator = set[Symbol.iterator]()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
while (true) {
const current = iterator.next()
if (current.done) {
break // 疊代已經結束了,沒必要繼續了
}
console.log(current.value)
}
29.疊代器模式
const todos = {
life: ['吃飯', '睡覺', '打豆豆'],
learn: ['國文', '數學', '外語'],
work: ['喝茶'],
// 提供統一周遊通路接口
each: function (callback) {
const all = [].concat(this.life, this.learn, this.work)
for (const item of all) {
callback(item)
}
},
// 提供疊代器(ES2015 統一周遊通路接口)
[Symbol.iterator]: function () {
const all = [...this.life, ...this.learn, ...this.work]
let index = 0
return {
next: function () {
return {
value: all[index],
done: index++ >= all.length
}
}
}
}
}
todos.each(function (item) {
console.log(item)
})
console.log('-------------------------------')
for (const item of todos) {
console.log(item)
}
29.ES2015 生成器函數(Generator)
- 通過在函數的前面加個* 生成一個生成器函數的函數體,函數體會執行直到遇到 yield 停止執行。等再次調用.next() 再往下執行。
// function * foo () {
// console.log('zce')
// return 100
// }
// const result = foo()
// console.log(result.next())
function * foo () {
console.log('1111')
yield 100
console.log('2222')
yield 200
console.log('3333')
yield 300
}
const generator = foo()
console.log(generator.next()) // 第一次調用,函數體開始執行,遇到第一個 yield 暫停
console.log(generator.next()) // 第二次調用,從暫停位置繼續,直到遇到下一個 yield 再次暫停
console.log(generator.next()) // 。。。
console.log(generator.next()) // 第四次調用,已經沒有需要執行的内容了,是以直接得到 undefined
29.ES2015 生成器應用
function * createIdMaker () {
let id = 1
while (true) {
yield id++
}
}
const idMaker = createIdMaker()
console.log(idMaker.next().value)
console.log(idMaker.next().value)
console.log(idMaker.next().value)
console.log(idMaker.next().value)
// 案例2:使用 Generator 函數實作 iterator 方法
const todos = {
life: ['吃飯', '睡覺', '打豆豆'],
learn: ['國文', '數學', '外語'],
work: ['喝茶'],
[Symbol.iterator]: function * () {
const all = [...this.life, ...this.learn, ...this.work]
for (const item of all) {
yield item
}
}
}
for (const item of todos) {
console.log(item)
}
四、ESMAScript 2016(ES7)
1.數組的includes 方法
- Array.property.includes 方法
const arr = ['foo', 1, NaN, false] console.log(arr.includes('foo')) // 傳回 Boolean 可以查找NaN
2.指數運算符
console.log(Math.pow(2, 10))
console.log(2 ** 10)