ES6學習筆記

Object對象方法

{
  // 用變量做對象的鍵
  let a = 'c'
  let obj = {
    [a]: 'b'
  }
  console.log(obj)// {c: "b"}
}
{
  let obj = {a: 1, b: 2}
  console.log(Object.keys(obj))// ["a", "b"]
  console.log(Object.values(obj))// [1, 2]
  console.log(Object.entries(obj))// [["a", 1], ["b", 2]]
  for(let [a, b] of Object.entries(obj)) {
    console.log(a, b)// a 1 b 2
  }
}

Array對象方法

{
  // 使用元素填充空數組
  console.log(new Array(5).fill(0))// [0, 0, 0, 0, 0]
}
{
  function foo(a, b, c) {
    let argu = Array.from(arguments)// 將僞數組轉換成數組(另外:[].slice.call(arguments)和[...arguments]也可以轉換)
    argu.forEach((val, key) => {
      console.log(val)// 4 5 6
    })
  }
  foo(4, 5, 6)
}
{
  let arr = [4, 5, 6]
  arr = arr.map((val, key) => {// 映射的使用
    return val * 2
  })
  console.log(arr)// [8, 10, 12]
}
{
  let arr = [4, 5, 6],
    findVal = arr.find((val) => {// 尋找val大於4的值
      return val > 4
    }),
    findIndex = arr.findIndex((val) => {// 尋找val大於4的值的下標
      return val > 4
    })
  console.log(findVal, findIndex)// 5 1
}
{
  // 在數組中尋找是否存在此值
  let arr = [4, 5, 6]
  console.log(arr.includes(5))// true
}
{
  let a = 1,
    d = 4
  function fun(a, b = a, c = d) {// 注意作用域的範圍
    console.log(a, b, c)// 2 2 4
  }
  fun(2)
}

Math對象方法

{
  // 0b開頭用來表示一個二進制數
  console.log(0b101)// 5
  // 0o開頭用來表示一個八進制數
  console.log(0o101)// 65
}
{
  // 判斷一個數、字符串是負數、零、正數還是非數字
  console.log(Math.sign(-5))// -1
  console.log(Math.sign(0))// 0
  console.log(Math.sign(5))// 1
  console.log(Math.sign('-5'))// -1
  console.log(Math.sign('hvb'))// NaN
}
{
  // 求3次立方根
  console.log(Math.cbrt(8))// 2
}

字符串方法

{
  let str = 'logo.png',
    a = str.includes('go'),// str是否包含'go'字符串
    b = str.startsWith('lo'),// str是否以'lo'字符串開頭
    c = str.endsWith('.png')// str是否以'.png'字符串結尾
  console.log(a, b, c)// true true true
}
{
  let str = 'abc',
    str2 = str.repeat(2)// 重複str字符串2次
  console.log(str2)// abcabc
}
{
  let str = '1',
    a = str.padStart(2, '0')// 當str的長度不足2時,在前面自動補'0'
    b = str.padEnd(2, '0')// 當str的長度不足2時,在後面自動補'0'
  console.log(a, b)// 01 10
}
{
  let month = `${(``+(new Date().getMonth()+1)).padStart(2, `0`)}月`// 獲取當前月份,不足2位數時,自動補0
  console.log(month)
}

解構賦值

{
  // 數組解構
  let a, b, rest
  [a, b, c=3, ...rest] = [1, 2, 4, 5, 6]
  console.log(a, b, c, rest)// 1 2 4 [5, 6]
}
{
  // 對象解構
  let a, b
  ({a, b: c} = {a: 1, b: 2})
  console.log(a, b, c)// 1 undefined 2
}
{
    let data = {
        name: 'hvb',
        course: [
            { title: 'chinese', score: 90 },
            { title: 'english', score: 80 }
        ]
    }
    for (let i = 0; i < data.course.length; i++) {
        let { [i]: { title, score } } = data.course// 通過i來定位當前要解構的是數組的哪一項
        console.log(title, score)// chinese 90 english 80
    }
}
{
  // 實現2個值的互換
  let a = 1,
    b = 2;
  [a, b] = [b, a]
  console.log(a, b)// 2 1
}
{
  // 通過解構函數的參數方便賦值
  function foo({a, b=2}) {
    console.log(a, b)// 1 2
  }
  foo({a: 1})
}

默認參數

// 檢查參數是否必填
function check() {
  throw new Error('該參數必填')
}
function foo(a=check(), b=2) {
  console.log(a + b)
}
foo(1)// 3
foo()// 拋出錯誤

塊級作用域{}

  • 塊級作用域易犯錯誤

    // 使用var聲明變量
    var funArr = []
    for(var i=0; i<2; i++) {// var聲明變量使i變量提升且由於循環,最終會變成2
      funArr.push(function() {// 這裏添加到數組中的匿名函數在執行的時候,拿到的i是變量提升的那個值
        console.log(i)
      })
    }
    funArr[0]()// 2
    funArr[1]()// 2
    
    // 使用let聲明變量
    let funArr2 = []
    for(let j=0; j<2; j++) {// let聲明變量,會在每次循環中都創建一個塊作用域,這個塊作用域中的i每次都能確定
      funArr2.push(function() {// 這裏添加到數組中的匿名函數在執行的時候,拿到的i是當前塊作用域中的i
        console.log(j)
      })
    }
    funArr2[0]()// 0
    funArr2[1]()// 1
  • es6中可以直接使用{}創建一個塊級作用域

    {
      let a = 1
      console.log(a)// 1
      {
        let a = 2
        console.log(a)// 2
      }
    }

獨一無二的值Symbol

{
  let a = Symbol()
  let b = Symbol()
  let c = Symbol.for('e')// 用'e'來標記這個獨一無二的值
  let d = Symbol.for('e')
  console.log(a==b, c==d)// false true
}
{
  // 用Symbol做的鍵不會重複
  let a = Symbol.for('abc')
  let obj = {
    [a]: 1,
    abc: 2
  }
  console.log(obj)// {abc: 2, Symbol(abc): 1}
  // 直接遍歷obj無法得到Symbol類型的鍵
  for(let key in obj) {
    console.log(key)// abc
  }

  let symbol = Object.getOwnPropertySymbols(obj)// 通過這個方法只可以拿到Symbol數組,然後可以正常遍歷
  console.log(symbol)// [Symbol(abc)]

  let all = Reflect.ownKeys(obj)// 通過這個方法可以拿到既包含普通的鍵又包含Symbol鍵的數組,然後可以正常遍歷
  console.log(all)// ["abc", Symbol(abc)]
}

新增數據結構set和map

{
  // 聲明時直接傳入數組,用來生成組員
  let a = new Set([1, 2])
  // 通過add添加組員
  a.add(3)
  console.log(a)// Set(3) {1, 2, 3}
  // 通過has驗證是否含有此組員
  console.log(a.has(2))// true
  // 通過delete刪除組員
  a.delete(1)
  console.log(a)// Set(2) {2, 3}
  // 通過clear清空組員
  a.clear()
  console.log(a)// Set(0) {}
  // 實例:數組去重
  let arr = [1, 2, 3, 1]
  let res = [...new Set(arr)]
  console.log(res)// [1, 2, 3]
}
{
  // 聲明時直接傳入二維數組,用來生成組員
  let a = new Map([[1, 2], [3, 4]])
  // 通過set添加組員
  a.set('a', 'b')
  console.log(a)// Map(3) {1 => 2, 3 => 4, "a" => "b"}
  console.log(a.get(1))// 2
  // 通過has驗證是否含有此組員
  console.log(a.has(3))// true
}
{
  // obj set map作對比
  let item = {a: 1},// 緩存的對象
    obj = {},// 空對象(用來對比)
    set = new Set(),// 空set(用來對比)
    map = new Map()// 空map(用來對比)
  // 添加一個組員
  obj.a = 1
  set.add(item)
  map.set('a', 1)
  console.log(obj, set, map)// {a: 1} Set(1) {Object {a: 1}} Map(1) {"a" => 1}
  // 查看一個組員
  console.log('a' in obj, set.has(item), map.has('a'))// true true true
  // 修改一個組員
  obj.a = 2
  item.a = 2
  map.set('a', 2)
  console.log(obj, set, map)// {a: 2} Set(1) {Object {a: 2}} Map(1) {"a" => 2}
  // 刪除一個組員
  delete obj.a
  set.delete(item)
  map.delete('a')
  console.log(obj, set, map)// {} Set(0) {} Map(0) {}
  // 由此可看,map和set的操作比較方便,所以建議在開發過程中,優先使用map數據結構,如果數據要求唯一性,那麼使用set,放棄使用傳統的數組和對象
}

映射Reflect

{
  let obj = {a: 1}
  console.log(Reflect.get(obj, 'a'))// 1
  Reflect.set(obj, 'a', 2)
  console.log(obj)// {a: 2}
  console.log(Reflect.has(obj, 'a'))// true
}

對象代理new proxy()

  • 簡單示例

    // 原對象
    let Person = {
      name: 'hvb',
      sex: 'male'
    }
    
    // 代理對象
    let person = new Proxy(Person, {
      get(target, key) {
        return Reflect.get(target, key)// target[key]
      },
      set(target, key, value) {
        if(key == 'sex') {
          throw new Error('性別不允許修改')
        }else {
          return Reflect.set(target, key, value)
        }
      }
    })
    
    person.name = 'hwj'
    console.log(person.name)// hwj
    person.sex = 'female'// 拋出錯誤
  • 通過對象代理給類屬性增加驗證規則

    // 創建驗證代理
    function createValidator(target, rule) {
      return new Proxy(target, {
        set(target, key, value) {
          if(rule[key]) {
            if(rule[key].validate(value)) {
              return Reflect.set(target, key, value)
            }else {
              throw new Error(rule[key].message(key, value))
            }
          }else {
            throw new Error(`屬性${key}不存在`)
          }
        }
      })
    }
    
    // 定義驗證規則
    let rule = {
      age: {// 年齡只能爲數字
        validate(val) {
          return /\d/.test(val)
        },
        message(key, val) {
          return `屬性${key}是年齡,不能爲${val}`
        }
      }
    }
    
    class Person {
      constructor(name, age) {
        this.name = name
        this.age = age
        return createValidator(this, rule)
      }
    }
    
    let person = new Person('hvb', 22)
    person.age = 12
    console.log(person.age)// 12
    person.age = 'qwe'// 拋出錯誤

類class

{
  class Person {
    constructor(name='hvb') {
      this.name = name
    }
    // getter
    get longName() {
      return 'long '+ this.name
    }
    // setter
    set longName(value) {
      return this.name = value
    }
    // 靜態方法
    static say() {
      console.log('I am '+ this.name)// I am Person
    }
  }
  // 靜態屬性
  Person.age = 22
  let person = new Person()
  console.log(person.longName)// long hvb
  person.longName = 'hwj'
  console.log(person.longName)// long hwj
  Person.say()
}

import from (詳見#12)

import a from 'a.js';// node會在node_modules文件夾下尋找相應的模塊
import a from './a.js;// node會在同級目錄文件夾下尋找相應的模塊

rest和spread使用的都是…,但是注意其區別 (詳見#3)

Object.assign是淺拷貝 (詳見#4)

  • 使用擴展運算符實現淺拷貝
var obj1 = {
  a: 1,
  b: 2
}
var obj2 = {
  a: 3,
  c: 4
}

var obj = { ...obj1, ...obj2 }
console.log(obj)// {a: 3, b: 2, c: 4}

使用let重複聲明同一個變量會報錯 (詳見#5)

箭頭函數=>(lambda表達式) (詳見#10)

  • this指向是不可改變的

    • 正常函數寫法

      var sex = 'male';
      function Foo() {
          console.log(this.sex);
      }
      Foo.call({sex: 'female'});// => female
    • 箭頭函數寫法

      var sex = 'male';
      var Foo = () => {console.log(this.sex)};
      Foo.call({sex: 'female'});// => male // Foo的this指向全局,由於函數使用箭頭函數寫法,所以使用call無法改變this指向,依然輸出male
  • 直接返回對象要加()

    var Foo = x => ({x: x});
    console.log(Foo(2).x);// => 2
  • 箭頭函數可以嵌套使用

    • 正常函數寫法

      function A(a) {
          return {
              B: function(b) {
                  return a+b;
              }
          }
      }
      console.log(A(1).B(2));// => 3
    • 箭頭函數寫法

      var A = a => ({B: b => a+b});
      console.log(A(1).B(2));// => 3
  • 函數簡寫 (詳見#11)

    var obj = {
        sex: 'male',
        say: () => {
            console.log(this.sex);
        }
    }
    obj.say();// => undefined // 箭頭函數的this指向它定義時所在的作用域,即全局
    var obj = {
        sex: 'male',
        say() {
            console.log(this.sex);
        }
    }
    obj.say();// => male // 簡寫函數的this指向對象obj本身
  • 其他

    • es6寫法

      var sex = 'male',
          age = 22,
          say = function(a, b) {
              return a+b;
          };
      
      var f1 = () => ({sex, age});
      var f2 = () => (sex, age);
      var f3 = () => (sex, age) => say(sex, age);
    • 編譯成es5寫法

      var sex = 'male',
          age = 22,
          say = function say(a, b) {
          return a + b;
      };
      
      var f1 = function f1() {
          return { sex: sex, age: age };
      };
      var f2 = function f2() {
          return sex, age;
      };
      var f3 = function f3() {
          return function (sex, age) {
              return say(sex, age);
          };
      };

      這裏寫圖片描述

參考文章

[#1] shim和polyfill有什麼區別
[#2] shim和polyfill有什麼區別?
[#3] ES6 Rest參數
[#4] ES2015系列(二) 理解Object.assign
[#5] 在JavaScript ES6中使用let和const定義變量
[#6] ES6詳解六:賦值語法糖 destructing & spread
[#7] ES6中新增的數據結構Set與Map
[#8] 深入解讀JavaScript中的Iterator和for-of循環
[#9] ES6詳解八:模塊(Module)!
[#10] ES6中箭頭函數的使用
[#11] es6對象方法簡寫?
[#12] 關於ES6的 模塊功能 Module 中export import的用法和注意之處
[#13] babel的polyfill和runtime的區別
[#14] 觸摸ES6 - 模板字符串

async/await流程控制

  • 給class添加異步方法
class Foo {
  log() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(111)
      }, 1000)
    })
  }
  async say() {
    return await this.log()
  }
}
let f = new Foo()
f.say()
.then(data => {
  console.log(data)
})
  • promise化

    var Promise = require('bluebird')
    var async = Promise.promisifyAll(require('async'))
    
    async.seriesAsync([(cb) => {
        cb(null, 1)
    }])
    .then((data) => {
        console.log(data, 11)
    })

caolan/async
Async使用簡介之流程控制
體驗異步的終極解決方案-ES7的Async/Await

發佈了221 篇原創文章 · 獲贊 155 · 訪問量 71萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章