天天看點

ECMAScript新特性一、内容概要二、ECMAScript 概述三、ECMAScript 2015 (ES6)四、ESMAScript 2016(ES7)

一、内容概要

  • ECMAScript 與 JavaScript
  • ECMAScript 的發展過程
  • ECMAScript 2015的新特性
  • And more…

二、ECMAScript 概述

  1. JavaScript 是在 ECMAScript 的基礎上擴充的語言。
  2. JavaScript @ web端:ECMAScript和WebAPI(DOM、BOM)組成
  3. JavaScript @ node.js端:ECMAScript和 Node APIs (fs、net、etc)組成

三、ECMAScript 2015 (ES6)

1.ES6學習概要

  1. 解決原有文法上的一些問題或者不足
  2. 對原有文法進行增強
  3. 全新的對象、全新的方法、全新的功能
  4. 全新的資料類型和資料結構

2.準備工作(學習環境)

  1. 運作環境 : node(用) 和浏覽器都行
  2. 自動監聽 node 運作,用 nodemon 包:
    /* 指令行輸入*/
    npm init  				// 初始化
    npm install -g nodemon	// 安裝包
    nodemon index.js 		// 啟動項目
               

3.ES2015 let 和 塊級作用域

作用域

  1. 全局作用域
  2. 函數作用域
  3. 塊級作用域(es2015 新增)
    1. var 聲明的變量會産生作用域提升。
    2. let 關鍵字聲明的變量不會提升,必須先聲明才能用,否則報錯:引用異常

4.ES2015 const 關鍵詞

  1. const 是用來定義 JavaScript 的常量(恒量)的。
  2. const 隻是在 let 的基礎上多了個隻讀的特性。
  3. const 隻有在聲明的同時指派,否則會報錯。
    const obj = {};
    obj.name = 'linxing';		// 不會報錯,因為沒有改變obj的引用位址,隻是增加了obj的屬性
    obj = {};					// 錯誤,修改了obj的引用值
               
  4. 最佳實踐:不用 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 對象的解構

  1. 對象的解構采用的是 屬性比對
    const obj = { name: 'zce', age: 18 }
    const { name } = obj
    console.log(name)				// 'zce'
               
  2. 對象的解構重命名
    const obj = { name: 'zce', age: 18 }
    const name = 'tom'
    const { name: objName } = obj
    console.log(objName)			// 'zce'
               
  3. 對象的解構重命名+給預設值
    const { log } = console;
    const obj = { name: 'zce', age: 18 }
    const name = 'tom'
    const { name: objName = 'linxing' } = obj
    log(objName)			// 'zce'
               

6.ES2015 字元串模闆(``)

  1. 字元串模闆中間可以使用 ${變量名} 包裹變量
  2. 示例
    const name = 'tom'
    const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}`
    console.log(msg)		// hey, tom --- 3 ---- 0.15891994236543483
               

7.ES2015 帶标簽的模闆字元串(``)

  1. 模闆字元串的标簽就是一個特殊的函數,用來重新渲染處理模闆引擎。
  2. 使用這個标簽就是調用這個函數
    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 字元串的擴充文法

  1. str.startsWith(params ) : 查找字元串中的開頭是否以 params 開頭,傳回 boolean 類型。
  2. str.endsWith(params ) : 查找字元串中的結尾是否以 params 開頭,傳回 boolean 類型。
  3. 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 參數的預設值

  1. 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)
               
  2. 預設參數一定是在形參清單的最後
    function foo (enable = true) {
      console.log('foo invoked - enable: ')
      console.log(enable)
    }
    
    foo(false)
               

10.ES2015 剩餘參數

  1. es2015 之前是使用 arguments 的僞數組去接受參數。
  2. 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 箭頭函數

  1. 使用箭頭函數 能使代碼更加簡單易讀。
    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()

  1. 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
               
  2. 應用場景
    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

  1. 這是vue.3 開始用 proxy 處理響應資料,vue3以前使用的是Object.defineProperty()方法響應資料。
  2. 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() 方法

  1. 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)
    
               
  2. 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)
    
               
  3. 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)
               
  4. 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方法

  1. 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()資料解構

  1. 确儲存儲在 Set 資料結構的唯一性。
    1. 添加方法:setData.add (params)
    2. 删除方法:setData.delete(params)
    3. 查找方法:setData.has(parsms)
    4. 清除方法: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)
               
  2. 經常用來給數組去重
    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()資料結構

  1. 可以運用任意類型的值作為鍵
  2. 鍵 =》值
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()資料結構

  1. 擴充對象,屬性名沖突問題
  2. 兩個 Symbol 永遠不會相等
  3. 使用 Symbol 為對象添加用不重複的鍵
  4. Symbol 模拟實作私有成員
  5. 最主要功能就是為對象添加獨一無二的屬性名
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)

  1. 通過在函數的前面加個* 生成一個生成器函數的函數體,函數體會執行直到遇到 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 方法

  1. 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)
           

繼續閱讀