<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • ES6-ES12部分簡單知識點總結,希望對大家有用~

    ES6-ES12簡單知識點總結

    1.ES6相關知識點

    1.1.對象字面量的增強

    ES6中對對象字面量的寫法進行了增強,主要包含以下三個方面的增強:

    • 屬性的簡寫:當給對象設置屬性時,如果希望變量名和屬性名一樣就可以直接寫該變量名;
    • 方法的簡寫:對象中的方法可直接寫成foo() {}的形式;
    • 計算屬性名:對象的屬性名可以動態傳入,將變量使用[]包裹即可;
    const obj = {
      // 1.屬性簡寫
      name,
      age,
      // 2.方法簡寫
      foo() {
        console.log('foo')
      },
      // 3.計算屬性名
      [key]: 'value'
    }
    

    1.2.解構

    為了方便從數組或對象中獲取數據,ES6給我們提供了解構的方案,可分為數組的解構和對象的解構。

    • 數組的解構:注意數組的解構是按元素順序來的。

      const names = ['curry', 'kobe', 'klay', 'james']
      
      // 1.基本的解構,解構出數組所有的元素
      var [name1, name2, name3, name4] = names
      console.log(name1, name2, name3, name4) // curry kobe klay james
      
      // 2.解構部分元素,只解構后面兩個元素
      var [, , name3, name4] = names
      console.log(name3, name4) // klay james
      
      // 3.解構出第一個元素,后面的元素放到一個新數組中
      var [name1, ...newNames] = names
      console.log(newNames) // [ 'kobe', 'klay', 'james' ]
      
      // 4.解構數組的同時,給元素指定默認值,如果數組中沒有該元素,就會使用默認值
      var [name1, name2, name3, name4, name5 = 'default'] = names
      console.log(name1, name2, name3, name4, name5) // curry kobe klay james default
      
    • 對象的解構:對象的解構是不按順序的,是根據key來賦值的。

      const obj = {
        name: 'curry',
        age: 30,
        team: '金州勇士'
      }
      
      // 1.基本的解構
      var { name, age, team } = obj
      console.log(name, age, team) // curry 30 金州勇士
      
      // 2.解構的同時重命名
      var { name: newName, age: newAge, team: newTeam } = obj
      console.log(newName, newAge, newTeam) // curry 30 金州勇士
      
      // 3.解構的同時指定默認值,當對象中沒有該屬性時,就會取默認值
      var { height = '1.83' } = obj
      console.log(height) // 1.83
      
      // 4.同時重命名和指定默認值
      var { height: newHeight = '1.83' } = obj
      console.log(newHeight) // 1.83
      
    • 解構的應用場景:一般開發中拿到一個變量,可以對其進行解構使用,比如對函數的參數進行解構。

      function fn({ name, age, team }) {
        console.log(name, age, team)
      }
      fn(obj) // curry 30 金州勇士
      

    1.3.let和const的使用

    在ES5中,聲明變量都是使用var,從ES6開始新增了兩個聲明變量的關鍵字let和const。

    • let關鍵字:從直觀的角度來說,let和var是沒有太大的區別的,都是用于聲明一個變量。

      let message = 'hello world'
      
    • const關鍵字:const聲明的變量稱為常量,表示保存的數據一旦被賦值就不能再被修改了,但是如果是引用類型的數據,還是可以通過引用找到對應的對象進行修改的。

      const obj = {
        name: 'curry',
        age: 30
      }
      const names = ['curry', 'kobe']
      
      obj.name = 'kobe'
      names.push('klay')
      
      console.log(obj) // { name: 'kobe', age: 30 }
      console.log(names) // [ 'curry', 'kobe', 'klay' ]
      
      // 注意:不能直接給引用類型重新賦值
      /*
        obj = {} // TypeError: Assignment to constant variable.
        names = [] // TypeError: Assignment to constant variable.
      */
      
    • 注意:與var不同的是,let和const是不允許重復聲明變量的。并且使用let和const聲明的變量是具有自己的塊級作用域的。var和let可以不設置初始值,const必須設置。

    有關作用域提升的問題:

    使用過var關鍵字的人都知道,var聲明的變量是會進行作用域提升的,如果使用let和const聲明的變量,是不允許在聲明之前對其進行訪問的,會直接報錯。

    console.log(message) // undefined
    var message = 'hello world'
    
    console.log(message) // ReferenceError: Cannot access 'message' before initialization
    let message = 'hello world'
    

    為什么var聲明的變量有作用域提升,而let和const沒有呢?

    • 作用域提升:在聲明變量的作用域中,如果這個變量可以在聲明之前被訪問,那么就可以稱之為作用域提升。
    • 在JavaScript執行之前,會先對我們聲明的變量進行收集創建,普通變量的默認值都為undefined,只有等到執行賦值代碼時,該變量才會被真正賦值,所以在聲明之前訪問就為undefined。
    • 那let和const不能訪問,是不是let和const聲明的變量沒有在代碼執行前被收集創建呢?到底let和const有沒有作用域提升?
      • 其實let和const聲明的變量在代碼執行前是有被收集創建的,只是不能訪問而已,所以就不能稱之為作用域提升,在ECMA262對let和const的描述中,這些變量會被創建在包含它們的詞法環境被實例化時,但是是不可以訪問它們的,直到詞法綁定被求值(也就是變量被賦值之后);
      • 在使用var聲明的變量,是會添加到window上的,而let和const聲明的變量是不會被添加到window上的,實際上是被添加到了變量環境中進行存儲;
      • 暫時性死區:在代碼中,使用let、const聲明的變量,在聲明之前變量是不可以被訪問的,這種現象稱之為temporal dead zone(TDZ);

    總結:在上面的代碼中,其實message在代碼執行前就已經被創建了,在用let進行修飾后,js底層會對其進行約束,以至于在聲明前不可以訪問。

    1.4.模板字符串

    ES6允許使用字符串模板來嵌入JS的變量或者表達式來進行拼接。

    使用``來編寫字符串,可以${expression}來嵌入動態內容,里面可以寫一個表達式。

    const name = 'curry'
    const age = 30
    
    console.log(`My name is ${name}\nMy age is ${age}`)
    

    標簽模板字符串:模板字符串另外一種用法,可以用來調用函數,如果使用標簽模板字符串,并且在調用的時候插入其他的變量。

    • 模板字符串被拆分了;
    • 第一個元素是數組,元素為被${}的字符串組合;
    • 后面的元素是一個個${}中傳入的變量值;
    function fn(x, y, z) {
      console.log(x, y, z)
    }
    
    const name = 'curry'
    const age = 30
    
    fn`sojfo${name}hghaooa${age}jgoajg` // [ 'sojfo', 'hghaooa', 'jgoajg' ] curry 30
    

    應用:在react中編寫css就有這么一個庫叫styled-components,其原理就是使用的標簽模塊字符串。

    1.5.函數的默認參數

    在ES6之前,我們編寫的函數參數是沒有默認值的,而ES6給我們提供了默認參數,如果傳入了該參數就使用傳入的值,沒有傳入就使用默認值。

    • 在ES6之前,如果想實現默認參數的效果,就必須編寫以下最終代碼。

      function fn() {
        var m = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'aaa'
        var n = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'bbb'
        console.log(m, n)
      }
      
      fn() // aaa bbb
      fn(111, 222) // 111 222
      
    • 在ES6中,可以在聲明函數時給其參數默認值。

      • 一般默認值寫法:

        function fn(m = 'aaa', n = 'bbb') {
          console.log(m, n)
        }
        
      • 默認值搭配解構的使用:

        // 1.寫法一:對象參數+解構
        function fn1({ name, age } = { name: 'curry', age: 30 }) {
          console.log(name, age)
        }
        fn1() // curry 30
        
        // 2.寫法二:解構+默認值
        function fn2({ name = 'curry', age = 30 } = {}) {
          console.log(name, age)
        }
        fn2() // curry 30
        

    注意:有默認值的參數一般會放到最后,在JS中函數都會有一個length屬性,length長度代表函數參數個數,但是有默認值的參數是不會被計算在內的。但是如果將有默認值的參數放在中間,那么后面的參數也不會被計算在內的。

    function fn1(x, y, z) {}
    console.log(fn1.length) // 3
    
    function fn2(x, y, z = 30) {}
    console.log(fn2.length) // 2
    
    function fn3(x, y = 30, z) {}
    console.log(fn3.length) // 1
    

    1.6.函數的剩余參數

    ES6中引用了剩余參數,可以將不定數量的參數放入到一個數組中,如果最后一個參數是以...為前綴的,那么它會將剩余的參數放入到該參數中,并且作為一個數組。

    剩余參數和arguments有什么區別呢?

    • 剩余參數只包含那些沒有對應形參的實參,而arguments對象包含了傳給函數的所有實參;
    • arguments對象不是一個真正的數組,而rest是一個真正的數組,可以進行數組的所有操作;
    • arguments是早期的ECMAScript中為了方便去獲取所有的參數提供的一個數據結構,而剩余參數是ES6中提供并且希望代替arguments的;
    function foo(m, n, ...args) {
      console.log(m, n, args)
      console.log(arguments) // [Arguments] { '0': 10, '1': 20, '2': 30, '3': 40, '4': 50 }
    }
    
    foo(10, 20, 30, 40, 50) // 10 20 [ 30, 40, 50 ]
    

    1.7.箭頭函數

    相比于普通函數,箭頭函數有一下幾個特殊點:

    • 箭頭函數內部是不綁定this的,會去它上一層作用域中找;
    • 箭頭函數是沒有顯示原型的,所以不能作為構造函數,使用new操作符來調用;
    • 箭頭函數沒有自己的argments;
    const fn = () => {
      console.log(this)
      // console.log(argments) // ReferenceError: argments is not defined
    }
    
    fn() // window對象
    console.log(fn.prototype) // undefined
    

    1.8.展開語法

    展開語法(spread syntax)可以在函數調用或數組構造是,將數組表示或者字符串在語法層面展開,還可以在構造字面量對象時,將對象表達式按鍵值對的方式展開。

    展開語法的主要使用場景:在函數調用時數組構造時使用:

    const nums = [1, 2, 3]
    const str = 'abc'
    
    function fn(x, y, z) {
      console.log(x, y, z)
    }
    
    // 函數調用時
    fn(...nums) // 1 2 3
    fn(...str) // a b c
    
    // 數組構造時
    const newNums1 = [...nums, 4, 5]
    const newNums2 = [...nums, ...str]
    console.log(newNums1) // [ 1, 2, 3, 4, 5 ]
    console.log(newNums2) // [ 1, 2, 3, 'a', 'b', 'c' ]
    

    1.9.數值的表示

    ES6中規范了二進制和八進制的寫法。

    const num1 = 188 // 十進制
    const num2 = 0b101 // 二進制
    const num3 = 0o567 // 八進制
    const num4 = 0x8cf // 十六進制
    
    // 打印轉成對應的十進制數
    console.log(num1, num2, num3, num4) // 188 5 375 2255
    

    1.10.Symbol的使用

    在ES6之前,對象屬性名都是字符串形式,很容易造成屬性名沖突,Symbol是ES6中新增的一個基本數據類型,可用來生成一個獨一無二的值。

    • 作為屬性名:

      const s1 = Symbol()
      const s2 = Symbol()
      const s3 = Symbol()
      
      // 對比調用Symbol生成的值
      console.log(s1 === s2) // false
      
      // Symbol值作為對象key
      // 寫法一:定義對象字面量時使用
      const obj = {
        [s1]: 'aaaa'
      }
      // 寫法二:對象新增屬性
      obj[s2] = 'bbbb'
      // 寫法三:通過Object.defineProperty()
      Object.defineProperty(obj, s3, {
        enumerable: true,
        configurable: true,
        writable: true,
        value: 'cccc'
      })
      
      console.log(obj) // { [Symbol()]: 'aaaa', [Symbol()]: 'bbbb', [Symbol()]: 'cccc' }
      
    • 作為屬性值:

      const s1 = Symbol()
      
      const obj = {
        name: 'curry',
        age: s1
      }
      
      console.log(obj) // { name: 'curry', age: Symbol() }
      
    • 注意:Symbol作為屬性名時,不能通過.方式來獲取,也就是obj.s1,只能通過obj[s1]的方式獲取。并且在通過Object.keys()獲取對象所有的key時,是獲取不到這些Symbol的,可以借助Object.getOwnPropertySymbols()來獲取所有類型為Symbol的key。

      console.log(obj.s1) // undefined
      
      console.log(obj[s1]) // aaaa
      console.log(obj[s2]) // bbbb
      
      // 使用Object.keys獲取對象所有key并打印,發現數組中是沒有Symbol的key
      console.log(Object.keys(obj)) // []
      
      // 使用Object.getOwnPropertySymbols(obj)獲取所有的Symbol的key
      console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(), Symbol(), Symbol() ]
      

    延伸:Symbol的作用就是給我們創建一個獨一無二的值,如果我們想創建一個相同的Symbol可以怎么做呢?

    • 可以使用Symbol.for()來做到這一點;
    • 并且可以通過Symbol.keyFor()方法來獲取對應的key;
    // 通過Symbol.for(描述)創建并傳入相同描述
    const s1 = Symbol.for('aaaa')
    const s2 = Symbol.for('aaaa')
    
    console.log(s1 === s2) // true
    
    // 拿到s1傳入的值
    const key = Symbol.keyFor(s1)
    console.log(key) // aaaa
    
    // 將拿到的值又傳給s3
    const s3 = Symbol.for(key)
    console.log(s3 === s1) // true
    console.log(s3 === s2) // true
    

    1.11.Set和WeakSet的使用

    在ES6之前,存儲數據的結構主要有兩種,分別是數組和對象。在ES6中新增了另外兩種數據結構:Set、Map,以及它們另外形式的WeakSet、WeakMap。下面就先來看看Set和WeakSet。

    (1)Set:用于保存數據,類似于數組,與數組不同的是Set中的元素是不能重復的。

    • Set的基本使用:

      // 1.創建一個Set結構
      const set = new Set()
      
      // 2.往set中添加元素
      set.add(30)
      set.add(30) // 相同的基本數據類型只會保留一個
      set.add('abc')
      set.add(undefined)
      set.add({})
      set.add({}) // 對象可以重復的原因是,對象存放的是內存地址
      set.add(NaN)
      set.add(NaN) // 為什么NaN也不能重復,因為在Set內部會視NaN為同一個東西
      
      console.log(set) // Set(6) { 30, 'abc', undefined, {}, {}, NaN }
      
    • Set常見的屬性:

      • size:返回Set中元素的個數;

        console.log(set.size) // 6
        
    • Set常見的方法:

      • add(value):添加一個元素,返回set對象本身;
      • delete(value):從set中刪除與value值相等的元素,返回boolean類型;
      • has(value):判斷set中是否存在value這個元素,返回boolean;
      • clear():清空set中所有的元素,無返回值;
      • forEach(callback,[thisArg]):遍歷set對象(Set的實例化對象是一個可迭代對象,所以也支持for...of遍歷);
      // add
      console.log(set.add(30)) // Set(1) { 30 }
      console.log(set.add(60)) // Set(2) { 30, 60 }
      console.log(set.add(90)) // Set(2) { 30, 60, 90 }
      // delete
      console.log(set.delete(40)) // 未找到40,返回false
      console.log(set.delete(30)) // true
      // has
      console.log(set.has(60)) // true
      console.log(set.has(30)) // false
      // forEach
      set.forEach(item => {
        console.log(item) // 60 90
      })
      // for...of
      for (const item of set) {
        console.log(item) // 60 90
      }
      // clear
      set.clear()
      console.log(set) // Set(0) {}
      

    (2)WeakSet:也要求內部元素不能重復。

    • WeakSet與Set的區別:

      • 區別一:WeakSet中只能存放對象類型,不能存放基本數據類型;
      • 區別二:WeakSet對元素的引用是弱引用,如果沒有其他引用對該元素進行引用,是可以被GC回收的;
      • 區別三:WeakSet由于是弱引用的原因,所以是不能進行遍歷的,存儲到WeakSet中的對象是沒辦法通過遍歷獲取的;
      • 什么是弱引用?:簡單理解就是對對象類型的引用是可以看成沒有的,但是卻可以訪問其對象內部的數據;
    • WeakSet常見方法:add(value)、delete(value)、has(value),沒有clear和forEach;

    • WeakSet的基本使用:

      const wSet = new WeakSet()
      // 只能存放對象類型
      // wSet.add(10) // TypeError: Invalid value used in weak set
      wSet.add({ name: 'curry', age: 30 })
      wSet.add([1, 2, 3])
      

    1.12.Map和WeakMap的使用

    下面來講講Map和WeakMap,主要用于存儲映射關系。

    (1)Map:對于普通對象存儲映射關系,只能使用字符串或者Symbol作為屬性名,如果普通對象使用對象來作為key的話,會自動將對象轉成字符串,但是Map允許我們使用對象作為key。

    const obj1 = { name: 'curry', age: 30 }
    
    const obj = {
      [obj1]: 'aaaa'
    }
    // 普通對象使用對象作為key,對象會自動轉成字符串[object Object]
    console.log(obj) // { '[object Object]': 'aaaa' }
    
    • Map的基本使用:

      const obj1 = { name: 'curry', age: 30 }
      const obj2 = { name: 'kobe', age: 24 }
      
      // 方式一:創建map后,通過set添加屬性
      const map1 = new Map()
      map1.set(obj1, 'aaaa')
      map1.set(obj2, 'bbbb')
      
      // 方式二:創建map時,傳入一個數組
      const map2 = new Map([
        [obj1, 'aaaa'],
        [obj2, 'bbbb']
      ])
      
      console.log(map1)
      console.log(map2)
      

    • Map常見的屬性:

      • size:返回Map中元素的個數;

        console.log(map1.size) // 2
        
    • Map常見的方法:與Set很相似,設置和獲取屬性不太一樣。

      • set(key, value):在Map中添加key和value,并且返回整個map對象;
      • get(key):根據key獲取map中的value;
      • has(key):判斷map中是否包含某一個key,返回boolean值;
      • delete(key):根據key刪除一個鍵值對,返回boolean值;
      • clear():清空所有的屬性;
      • forEach(callback, [thisArg]):遍歷map(也可使用for...of遍歷);
      const map = new Map()
      const obj = { name: 'curry', age: 30 }
      
      // set
      map.set(obj, 'aaaa')
      map.set('bbbb', 1234)
      map.set(11, 'cccc')
      // get
      console.log(map.get(obj)) // aaaa
      // delete
      console.log(map.delete(11)) // true
      console.log(map.delete(22)) // false
      // has
      console.log(map.has('bbbb')) // true
      console.log(map.has('abc')) // false
      // forEach
      map.forEach((value, key) => {
        console.log(key, value)
        /*
          { name: 'curry', age: 30 } aaaa
          bbbb 1234
        */
      })
      // clear
      map.clear()
      
      console.log(map) // Map(0) {}
      

      如果map使用for...of遍歷,看一下遍歷出來的值是什么樣子的:

      // 這里取出的item是一個個數組,數組第一個元素是key,第二個元素是value
      for (const item of map) {
        console.log(item)
      }
      
      // 所以可以在取值的時候對item進行解構
      for (const [key, value] of map) {
        console.log(key, value)
      }
      

    (2)WeakMap:也是以鍵值對的形式存在。

    • WeakMap和Map的區別:與Set和WeakSet的區別類似;
      • 區別一:WeakMap的key只能使用對象,不接受其他類型作為key;
      • 區別二:WeakMap的key對對象的引用是弱引用,如果沒有其他引用指向這個對象,那么GC可以回收該對象;
      • 區別三:WeakMap和WeakSet一樣也不能進行遍歷;
    • WeakMap常見的方法:set(key, value)、get(key)、has(key)、delete(key),沒有clear和forEach;

    2.ES7相關知識點

    2.1.數組的includes方法

    在ES7之前,判斷數組中包含某一個元素,一般可以用indexOf判斷是否為-1,ES7給我們提供了includes方法來判斷數組中是否包含指定元素,返回boolean類型;

    arr.includes(valueToFind[, fromIndex])
    
    • valueToFind:需要查找的元素;
    • fromIndex:從指定索引開始查找,如果from為負值,就從array.length + fromIndex的位置開始查找(默認值為0);
    const names = ['curry', 'kobe', NaN]
    
    console.log(names.includes('curry')) // true
    console.log(names.includes('klay')) // false
    console.log(names.includes('curry', 1)) // false
    
    console.log(names.indexOf(NaN)) // -1
    console.log(names.includes(NaN)) // true
    

    注意:includes方法是可以判斷NaN是否存在的,因為includes的內部實現對NaN采用isNaN方法進行判斷。

    2.2.指數運算符

    在ES7之前,計算數字的指數需要通過Math.pow方法來完成,在ES7中,增加了**運算符,可以來計算指數。

    計算2的3次方:

    const res1 = Math.pow(2, 3)
    const res2 = 2 ** 3
    
    console.log(res1, res2) // 8 8
    

    3.ES8相關知識點

    3.1.獲取對象所有的value

    我們知道可以使用Object.keys獲取一個對象的所有key,ES8給我們提供了Object.values來獲取所有的value值。

    const obj = {
      name: 'curry',
      age: 30,
      team: '勇士'
    }
    
    // 傳入一個對象
    console.log(Object.values(obj)) // [ 'curry', 30, '勇士' ]
    // 傳入一個字符串,達到split的效果
    console.log(Object.values('abc')) // [ 'a', 'b', 'c' ]
    

    3.2.Object的entries方法

    通過Object.entries()可以獲取到一個二維數組,數組中會存放可枚舉的鍵值對數組,數組元素分別為對象的key和value。

    const obj = {
      name: 'curry',
      age: 30,
      team: '勇士'
    }
    
    // 傳入一個對象
    console.log(Object.entries(obj)) // [ [ 'name', 'curry' ], [ 'age', 30 ], [ 'team', '勇士' ] ]
    
    for (const [key, value] of Object.entries(obj)) {
      console.log(key, value)
      /*
        name curry
        age 30
        team 勇士
      */
    }
    
    // 傳入一個數組,下標作為第一個元素
    console.log(Object.entries(['curry', 'kobe', 'klay'])) // [ [ '0', 'curry' ], [ '1', 'kobe' ], [ '2', 'klay' ] ]
    
    // 傳入一個字符串,下標作為第一個元素
    console.log(Object.entries('abc')) // [ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]
    
    

    3.3.字符串的填充

    如果需要對字符串進行前后填充,來實現某種展示格式,ES8中提供了padStart和padEnd方法,分別可以對字符串進行首位填充。

    const str = 'ssssssssss'
    
    // 如果指定填充的位數小于等于str的長度,就不會進行填充
    // 指定的位數需大于str的長度,就會填充str長度減去指定位數
    // 如下指定了15,最終填充的只有5位,因為str的長度為10
    console.log(str.padStart(15, '*')) // *****ssssssssss
    console.log(str.padEnd(15, '-')) // ssssssssss-----
    

    應用場景:字符串的填充可以用于對身份證、銀行卡進行位數隱藏。

    const bankCard = '2034399002125581'
    // 截取銀行卡后四位數組
    const lastFourNum = bankCard.slice(-4)
    // 將前面數組全部填充為*
    const finalBankCard = lastFourNum.padStart(bankCard.length, '*')
    console.log(finalBankCard) // ************5581
    

    3.4.Object的getOwnPropertyDescriptors方法

    Object.getOwnPropertyDescriptors()方法用來獲取一個對象的所有自身屬性的描述符。

    const obj = {}
    
    Object.defineProperties(obj, {
      name: {
        configurable: false,
        writable: false,
        enumerable: false,
        value: 'curry'
      },
      age: {
        configurable: true,
        writable: true,
        enumerable: true,
        value: 30
      }
    })
    
    console.log(Object.getOwnPropertyDescriptors(obj))
    

    4.ES9相關知識點

    4.1.對象的展開語法

    在前面講了,數組是可以使用展開語法的,在ES9中,在構建對象字面量時,也可以使用展開語法了。

    const obj1 = {
      name: 'curry',
      age: 30
    }
    
    const newObj1 = { ...obj1, team: '勇士' }
    console.log(newObj1) // { name: 'curry', age: 30, team: '勇士' }
    

    注意:對象的展開運算符只能實現淺拷貝,如果對象內部還包含引用類型的值,就會指向同一地址空間。

    const obj = {
      name: 'curry',
      age: 30,
      friends: ['kobe', 'klay']
    }
    
    const newObj = { ...obj }
    newObj.friends.push('james')
    console.log(newObj) // { name: 'curry', age: 30, team: '勇士' }
    console.log(obj) // { name: 'curry', age: 30, friends: [ 'kobe', 'klay', 'james' ] }
    

    5.ES10相關知識點

    5.1.flat和flatMap

    (1)flat方法

    按照一個可指定的深度遞歸遍歷數組,并將所有的元素和遍歷到的子數組合并為一個新數組返回。(可用于數組扁平化)

    const nums = [1, 2, [3, 3], [4, [5, 5]]]
    
    // 對數組進行降維處理
    console.log(nums.flat(1)) // [ 1, 2, 3, 3, 4, [ 5, 5 ] ]
    console.log(nums.flat(2)) // [ 1, 2, 3, 3, 4, 5, 5 ]
    // 如果不知道數組嵌套了多少層,可直接指定Infinity
    console.log(nums.flat(Infinity)) // [ 1, 2, 3, 3, 4, 5, 5 ]
    

    (2)flatMap方法

    首先使用映射函數映射每個元素,然后將結果壓縮成一個新數組。

    • flatMap先進行map操作,然后做flat操作;
    • flatMap中的flat操作深度為1;
    const arr = [[1, 2, 3, 4], ['a', 'b','c', 'd']]
    
    // 數組自動降一維
    const newArr = arr.flatMap(item => {
      return item
    })
    
    console.log(newArr) // [ 1, 2, 3, 4, 'a', 'b', 'c', 'd' ]
    

    5.2.Object的fromEntries方法

    在前面講了可以通過Object.entries()將一個對象轉換成鍵值對數組,而Object.fromEntries()可以將鍵值對列表轉換成對象。

    const entries = [
      ['name', 'curry'],
      ['age', 30]
    ]
    
    const obj = Object.fromEntries(entries)
    console.log(obj) // { name: 'curry', age: 30 }
    

    應用場景:解析url的query部分,將其轉成一個對象。

    const url = 'http://127.0.0.1:8000/search?name=curry&age=30'
    
    const queryStr = url.slice(url.indexOf('?') + 1, url.length)
    console.log(queryStr) // name=curry&age=30
    
    // URLSearchParams:可用于處理url的查詢字符串
    const queryParams = new URLSearchParams(queryStr)
    console.log(queryParams) // URLSearchParams { 'name' => 'curry', 'age' => '30' }
    
    const paramObj = Object.fromEntries(queryParams)
    console.log(paramObj) // { name: 'curry', age: '30' }
    

    5.3.去除字符串首尾空格

    去除一個字符串首尾空格可以通過trim()方法,而trimStart和trimEnd方法分別可以單獨去除字符串前或后的空格。

    // 這里以·代表空格
    const str = '····ssss···'
    console.log(str.trim()) // ssss
    console.log(str.trimStart()) // ssss···  
    console.log(str.trimEnd()) // ····ssss
    

    5.4.Symbol的description

    在前面講了Symbol類型,在創建一個Symbol類型的值時,還可以傳入指定的描述符。

    const s1 = Symbol('aaaa')
    const s2 = Symbol('bbbb')
    
    console.log(s1.description) // aaaa
    console.log(s2.description) // bbbb
    

    6.ES11相關知識點

    6.1.BigInt類型

    在JavaScript中,如果數字過大,可能是不正確的,先看看JavaScript提供給我們的最大值和最小值是多少。

    const maxNum = Number.MAX_SAFE_INTEGER
    const minNum = Number.MIN_SAFE_INTEGER
    
    console.log(maxNum) // 9007199254740991
    console.log(minNum) // -9007199254740991
    

    如果給最大值再加大數值,很明顯數值是不正確的:

    console.log(maxNum + 1) // 9007199254740992
    console.log(maxNum + 2) // 9007199254740992
    

    所以,ES11引入了新的數據類型BigInt,可用于表示很大的整數:

    • BigInt的寫法需要在數值后面加上n
    • 只有數值同為BigInt類型才能進行運算(不能進行隱式轉換),如果需要運算的數據不是BigInt類型就要加上n轉成BigInt;
    • 也可使用BigInt()方法進行轉類型;
    const bigInt = 9007199254740991n
    console.log(bigInt + 2n) // 9007199254740993n
    console.log(bigInt + bigInt) // 18014398509481982n
    

    6.2.空值合并操作符(??)

    如果||不能對空字符串和0進行很好的判斷,就可以使用??

    const test1 = ''
    const test2 = 0
    const test3 = null
    const test4 = undefined
    
    const res1 = test1 || 'default'
    const res2 = test2 || 'default'
    console.log(res1) // default
    console.log(res2) // default
    
    // ??認為空字符串和0是真值的
    const res3 = test1 ?? 'default'
    const res4 = test2 ?? 'default'
    console.log(res3) // ''
    console.log(res4) // 0
    
    // 只有當??前面的值為null或者undefined,才會使用后面的值
    const res5 = test3 ?? 'default'
    const res6 = test4 ?? 'default'
    console.log(res5) // default
    console.log(res6) // default
    

    6.3.可選鏈

    可選鏈(Optional Chaining)的主要作用就是讓代碼在進行null和undefined判斷時更加清晰和簡潔,確保我們訪問對象屬性是安全的(因為從undefined里面取值是會報錯的)。

    const obj = {
      name: 'curry',
      friend: {
        name: 'kobe',
        age: 24
      }
    }
    
    // 先判斷obj中是否有friend屬性,然后再判斷friend中是否有name屬性
    console.log(obj?.friend?.name) // kobe
    
    // console.log(obj.teammate.name) // TypeError: Cannot read property 'name' of undefined
    // obj中沒有teammate屬性,所以就直接返回undefined,不會再從undefined中取name了,不會報錯影響后面程序運行
    console.log(obj?.teammate?.name) // undefined
    

    6.4.globalThis

    在ES11之前獲取JavaScript的全局對象在不同的環境下的獲取方式不同:

    • 瀏覽器中:this、window獲取;
    • node中:global獲取;

    ES11中,對我們獲取全局對象進行統一規范:

    console.log(globalThis)
    

    瀏覽器中:

    node中:

    7.ES12相關知識點

    7.1.FinalizationRegistry

    FinalizationRegistry對象可以讓你在對象被垃圾回收時請求一個回調。

    • FinalizationRegistry提供了這樣的一種方法:當一個在注冊表中注冊的對象被回收時,請求在某個時間點上調用一個清理回調;(清理回調有時被稱為 finalizer )
    • FinalizationRegistry可實例化一個對象,可以借助該對象注冊想要清理回調的對象,傳入該對象和所含的值;
    let obj1 = { name: 'curry', age: 30 }
    let obj2 = { name: 'kobe', age: 24 }
    
    // 實例化注冊表
    const register = new FinalizationRegistry(value => {
      console.log(`${value}對象被銷毀了`)
    })
    
    // 注冊obj1和obj2,并指定其值
    register.register(obj1, 'obj1')
    register.register(obj2, 'obj2')
    
    // 將兩個對象銷毀
    obj1 = null
    obj2 = null
    

    需要借助瀏覽器的GC來進行測試,當兩個對象被真正回收了,就會調用清理回調,打印對應內容:

    7.2.WeakRef

    在前面講了WeakSet和WeakMap中的元素對對象的引用都是弱引用,WeakRef就可以專門實現對一個對象進行弱引用,也就是說該對象被GC回收時,是不會看它是否有弱引用的,有沒有弱引用一樣被回收。

    可以結合上面的FinalizationRegistry進行測試:

    • WeakRef創建的弱引用需通過deref()來訪問對象屬性;
    let obj = { name: 'curry', age: 30 }
    
    // 創建一個弱引用weakObj指向對象{ name: 'curry', age: 30 }
    let weakObj = new WeakRef(obj)
    
    // 拿到{ name: 'curry', age: 30 }對象
    // console.log(weakObj.deref())
    // console.log(weakObj.deref().name) // curry
    // console.log(weakObj.deref().age) // 30
    
    const register = new FinalizationRegistry(value => {
      console.log(`${value}對象被銷毀了`)
    })
    register.register(obj, 'obj')
    
    // 去掉obj對對象{ name: 'curry', age: 30 }的引用
    obj = null
    
    // 等對象回收后再打印
    setTimeout(() => {
      // 注意:當弱引用的對象被GC回收后,weakObj.deref()的值為undefined
      // 如果不想報錯,可以使用可選鏈或者邏輯與
      console.log(weakObj.deref()?.name)
      console.log(weakObj.deref() && weakObj.deref().name)
    }, 10000)
    

    7.3.邏輯賦值運算

    ES12為我們提供了三種邏輯賦值運算:

    • ||=:邏輯或賦值運算;

      let msg = undefined
      msg ||= 'default'
      console.log(msg) // default
      /*
        等同于:
        msg = msg || 'default'
      */
      
    • &&=:邏輯與賦值運算;

      let obj = {
        name: 'curry',
        age: 30
      }
      // 在obj有值的情況下,將obj賦值為obj.name
      obj &&= obj.name
      console.log(obj) // curry
      /*
        等同于:
        obj = obj && obj.name
      */
      
    • ??=:邏輯空賦值運算;

      let msg = 0
      // 當msg為null或undefined情況下,將msg賦值為default,這里為0,所以值還是0
      msg ??= 'default'
      console.log(msg) // 0
      /*
        等同于:
        msg = msg ?? 'default'
      */
      

    注意:該新增特性可能過新,可能出現node版本不支持的情況,可以在瀏覽器中打印查看。

    7.4.數值分隔符

    當數值過長時,ES12允許我們使用_進行連接,方便閱讀。

    const num = 100_000_000
    console.log(num) //100000000
    

    7.5.字符串替換

    ES12提供了一個replaceAll方法,該返回一個新字符串,新字符串所有滿足 pattern 的部分都已被replacement 替換。pattern可以是一個字符串或一個RegExpreplacement可以是一個字符串或一個在每次匹配被調用的函數。

    const newStr = str.replaceAll(regexp|substr, newSubstr|function)
    

    將所有的a替換為b:

    const str = 'ababababab'
    
    // 字符串
    const newStr1 = str.replaceAll('a', 'b')
    // 正則
    const regex = /a/g
    const newStr2 = str.replace(regex, 'b')
    
    console.log(newStr1) // bbbbbbbbbb
    console.log(newStr2) // bbbbbbbbbb
    

    注意:該新增特性可能過新,可能出現node版本不支持的情況,可以在瀏覽器中打印查看。

    總結:

    本篇文字只總結了ES6-ES12部分簡單知識點,還有一些其它ES6之后新增的特性,如Promise、迭代器、生成器、async、await等等,將會在后續的文章中進行整理。

    posted @ 2022-03-24 00:36  MomentYY  閱讀(394)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看