JS的ES6知識(shí)點(diǎn)詳解

1.let-const塊級(jí)作用域的補(bǔ)充

const names=["abc","cba","nba"];

for(let  i=0;i<names.length;i++){ //* 這個(gè)數(shù)組的元素有三個(gè),所以會(huì)形成3個(gè)塊級(jí)作用域
  console.log(names[i]);
}

以上for遍歷內(nèi)部的實(shí)現(xiàn)是以下這樣的:

因?yàn)閿?shù)組有3個(gè)元素,所以會(huì)產(chǎn)生3個(gè)塊級(jí)作用域。

//第一個(gè)塊級(jí)作用域
{
    let i=0;
    console.log(names[i])
}
//第二個(gè)塊級(jí)作用域
{
    把上次i++的結(jié)果賦值新定義的i //注意i++的i和let i不是同一個(gè),js引擎會(huì)在內(nèi)部做一些處理,這里為了方便讓我們理解內(nèi)部的實(shí)現(xiàn)
    let i=結(jié)果
    console.log(names[i]);
}
//第三個(gè)塊級(jí)作用域
{
    把上次i++的結(jié)果賦值給新定義的i
    let i=結(jié)果
    console.log(names[i]);
}

所以每個(gè)塊級(jí)作用域的i都不是同一個(gè)。

那使用const定義是不是可以實(shí)現(xiàn)呢?

如果將上面的代碼換一下:

const names=["abc","cba","nba"];

for(const  i=0;i<names.length;i++){ //* 這個(gè)數(shù)組的元素有三個(gè),所以會(huì)形成3個(gè)塊級(jí)作用域
  console.log(names[i]);
}

同樣地,因?yàn)閚ames有三個(gè)元素,所以還是會(huì)形成三個(gè)作用域。內(nèi)部實(shí)現(xiàn)是這樣的:

//第一個(gè)塊級(jí)作用域
{
    const i=0;
    console.log(names[i]);
}
//第二個(gè)塊級(jí)作用域 此時(shí)在i++的時(shí)候會(huì)報(bào)錯(cuò),因?yàn)閏onst本質(zhì)是值不能改變,所以就會(huì)拋出錯(cuò)誤
{
    //注意i++的i和const i不是同一個(gè),js引擎會(huì)在內(nèi)部做一些處理,這里為了方便讓我們理解內(nèi)部的實(shí)現(xiàn)
    將i++的結(jié)果賦值給新定義的i  //這一行就開始報(bào)錯(cuò)
    const i=結(jié)果
}

1.1 for...of 遍歷可迭代的數(shù)組(或?qū)ο?

const names=["abc","cba","nba"];

for(const item of names){ //* 這個(gè)數(shù)組的元素有三個(gè),所以會(huì)形成3個(gè)塊級(jí)作用域
  console.log(item);
}

for...of是將數(shù)組或?qū)ο竺總€(gè)元素取出來

內(nèi)部實(shí)現(xiàn):因?yàn)閿?shù)組有3個(gè)元素,所以還是會(huì)形成3個(gè)塊級(jí)作用域

//第一個(gè)塊級(jí)作用域
{
    const item="abc";
    console.log(item)
}
//第二個(gè)塊級(jí)作用域
{
    const item="cba";
    console.log(item)
}
//第三個(gè)塊級(jí)作用域
{
    const item="nba";
    console.log(item)
}

這里每個(gè)塊級(jí)作用域的item都不是同一個(gè)

2.暫時(shí)性死區(qū)

在ES6中,我們還有一個(gè)概念稱之為暫時(shí)性死區(qū):

  • 它表達(dá)的意思是在一個(gè)代碼塊中,使用let、const聲明的變量,在聲明之前不可以訪問的
  • 我們將這種現(xiàn)象稱之為 temporal dead zone(暫時(shí)性死區(qū),TDZ)(社區(qū))

以下兩段代碼都形成了暫時(shí)性死區(qū),在let、const聲明之前,不能進(jìn)行訪問。

var foo="foo";

if(true){
  console.log(foo);
  let foo="abc"; //* Cannot access 'foo' before initialization
}
var foo="foo";
function bar(){
  console.log(foo);
  let foo="abc";
}

bar()

3.var、let、const的選擇

對(duì)于var的使用:

  • var有其自身的特殊性:作用域提升、在window對(duì)象上添加屬性、沒有塊級(jí)作用域,這些都是歷史遺留問題
  • 其實(shí)這是javascript設(shè)計(jì)之初的一種語言缺陷
  • 目前市場(chǎng)上也在利用這種缺陷出一系列的面試題,來考察大家對(duì)JavaScript語言本身以及底層的理解
  • 但是在實(shí)際工作中,我們可以使用最新的規(guī)范來編寫,也就是不再使用var來定義變量了。

對(duì)于let、const來說

  • 對(duì)于let、const,是目前開發(fā)中推薦使用的
  • 我們優(yōu)先推薦使用const,這樣可以保證數(shù)據(jù)的安全性不會(huì)被隨意的篡改
  • 只有當(dāng)我們明確知道一個(gè)變量后續(xù)會(huì)需要被重新賦值時(shí),這個(gè)時(shí)候再使用let
  • 這種在很多其他語言里面也都是一種約定俗成的規(guī)范,盡量我們也遵守這種規(guī)范。

4.字符串模板基本使用

在ES6之前,如果我們想要使用字符串和動(dòng)態(tài)的變量(標(biāo)識(shí)符)拼接在一起,是非常麻煩和丑陋的(ugly)

ES6允許我們使用字符串模板來嵌入JS的變量或表達(dá)式來進(jìn)行拼接:

  • 首先,我們會(huì)使用``符號(hào)來編寫字符串,稱之為 模板字符串
  • 其次,在模板字符串中,我們可以通過${expresion}來嵌入動(dòng)態(tài)的內(nèi)容
// * 在ES6之前拼接字符串和動(dòng)態(tài)的變量在一起,是非常麻煩的
var name="wjy";
var age=18;
var height=1.6
console.log("我的名字是:"+name+" 年齡是:"+age+" 身高:"+height);

在ES6中提供了模板字符串 ``

如果需要引用動(dòng)態(tài)變量:${變量名}

// *在ES6當(dāng)中,提供了一個(gè)模板字符串 `` 引用動(dòng)態(tài)變量是:${變量名}
const name="wjy";
const age=18;
const height=1.66
console.log(`我的名字是${name} 年齡是:${age} 身高:${height}`)

5.標(biāo)簽?zāi)0遄址?/h3>

模板字符串還有另外一種用法:標(biāo)簽?zāi)0遄址?(Tagged Template Literals)

普通JavaScript的函數(shù)調(diào)用

function foo(m,n){
  console.log(m,n);
}
// * 函數(shù)調(diào)用最普通的方式
foo(20,39)

如果我們使用標(biāo)簽?zāi)0遄址?,并且在調(diào)用的時(shí)候插入其他的變量:

  • 模板字符串被拆分了
  • 第一個(gè)元素是數(shù)組,是被模板字符串拆分的字符串組合
  • 后面的元素是一個(gè)個(gè)模板字符串傳入的內(nèi)容
function foo(m,n){
  console.log(m,n);
}
// * 函數(shù)調(diào)用最普通的方式
foo(20,39)
// * 另外調(diào)用函數(shù)的方式:標(biāo)簽?zāi)0遄址?
foo``;//[ '' ] undefined
foo`hello World` //[ 'hello World' ] undefined
const name="wjy";
const age=20;
// * 第一個(gè)參數(shù)依然是模板字符串的完整字符串,只是被切成了多塊,放到了數(shù)組中   第二個(gè)參數(shù)是 模板字符串中,第一個(gè)${expression}的expression的值
foo`Hello${age}Wo${name}rld`;//[ 'Hello', 'Wo', 'rld' ] wjy

6.函數(shù)的默認(rèn)參數(shù)

在ES5的時(shí)候,可以給參數(shù)設(shè)置值,使用的是 邏輯或:如果前面為真,則返回前面的表達(dá)式的值,如果前面為false則將后面的表達(dá)式的值返回。

但是存在缺陷:

  • 寫起來比較麻煩,閱讀性差
  • 存在缺陷:如果傳入的值是0或者是"",但還是設(shè)置"aaa"或"bbb"
function foo(m,n){
  // * 如果沒有給函數(shù)傳參:那么m,n會(huì)是undefined,如果對(duì)m、n進(jìn)行操作時(shí),很容易產(chǎn)生錯(cuò)誤
  // * ES5之前是怎么給參數(shù)默認(rèn)值 邏輯或
  /**
   * 缺點(diǎn):
   * 1.寫起來很麻煩 ,并且代碼的閱讀性比較差
   * 2.這種寫起來是有bug 如果傳入的是 0 "" ,但是會(huì)被設(shè)置 為"aaa"或"bbb"
   * 
   */
 m=m|| "aaa";
 n=n||"bbb"
  console.log(m,n);
}
foo();
foo(100);
foo(100,200)

但在ES6中提供了給函數(shù)的參數(shù)設(shè)置默認(rèn)值,直接參數(shù)后面使用="值"

function foo(m="aaa",n="bbb"){
  console.log(m,n);
}

foo();//aaa bbb
foo(100);//100 bbb
foo(100,200);//100 200

上面的代碼,轉(zhuǎn)化為ES5是這樣的:

"use strict";

function foo() {
  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);
}

foo(); //aaa bbb

foo(100); //100 bbb

foo(100, 200); //100 200

6.1 函數(shù)的默認(rèn)值

// * 可以傳基本數(shù)據(jù)類型
function foo(m="aaa",n="bbb"){
  console.log(m,n);
}

foo();//aaa bbb
foo(100);//100 bbb
foo(100,200);//100 200

6.7 函數(shù)默認(rèn)值的補(bǔ)充

  1. 默認(rèn)值也可以和解構(gòu)一起使用

    function printInfo({name,age}={name:"wjy",age:18}){
      console.log(name,age);
    }
    printInfo()
    
    // * 另外一個(gè)寫法
    function printInfo({name="wjy",age=20}={}){
      console.log(name,age);
    }
    
    printInfo()
    
  2. 另外參數(shù)的默認(rèn)值我們通常會(huì)放到最后(在很多語言中,如果不放到最后其實(shí)會(huì)報(bào)錯(cuò)的)

    • 但是Javascript允許不將其放到最后,但是意味著還是會(huì)按照順序來匹配
  3. 另外默認(rèn)值會(huì)改變函數(shù)的length的個(gè)數(shù),默認(rèn)值以及后面的參數(shù)都不計(jì)算在length之內(nèi)的

// * 有默認(rèn)值的函數(shù)的length屬性
console.log(bar.length); //2

function baz(x=20,y,z){

}
console.log(baz.length);//0

7.函數(shù)的剩余參數(shù)

ES6中引用了rest parameter,可以將不定數(shù)量的參數(shù)放入到一個(gè)數(shù)組中:

如果最后一個(gè)參數(shù)是以...為前綴,那么它會(huì)將剩余的參數(shù)放到該參數(shù)中,并且作為一個(gè)數(shù)組

那么arguments和剩余參數(shù)有什么區(qū)別?

  • 剩余參數(shù)只包含沒有對(duì)應(yīng)形參的實(shí)參,而arguments包含傳遞給函數(shù)的所有實(shí)參
  • arguments對(duì)象不是一個(gè)真正的數(shù)組,而剩余參數(shù)是一個(gè)真正的數(shù)組,可以進(jìn)行數(shù)組的所有操作。
  • arguments是早期的ECMAScript中為了方便去獲取所有的參數(shù)提供的一個(gè)數(shù)據(jù)結(jié)構(gòu),而剩余參數(shù)是ES6提供的,并且希望以此替代arguments

剩余參數(shù)必須是 函數(shù)的參數(shù)的最后一個(gè)位置,否則會(huì)報(bào)錯(cuò)。

function foo(m,n,...args){
  console.log(m,n);//10 20
  console.log(args); //[ 30, 40, 50, 60, 70 ]
}

foo(10,20,30,40,50,60,70)
function bar(...args,m,n){ //*Rest parameter must be last formal parameter
  console.log(args);
  console.log(m);
  console.log(n);
}
bar(1,2,3,4)

8.函數(shù)箭頭函數(shù)的補(bǔ)充

  • 箭頭函數(shù)是沒有顯式原型的,所以不能作為構(gòu)造函數(shù)
  • 箭頭函數(shù)沒有this,箭頭函數(shù)的this會(huì)去上層作用域查找,如果還沒有找到,會(huì)繼續(xù)往上查找。直到全局作用域中
  • 箭頭函數(shù)沒有arguments
var bar=()=>{
  
}
console.log(bar.prototype);//undefined
console.log(new bar());//* bar is not a constructor

9.展開語法(Spread syntax)

  • 可以在函數(shù)調(diào)用/數(shù)組構(gòu)造時(shí),將數(shù)組表達(dá)式或者string在語法層面展開
  • 還可以在構(gòu)造字面量對(duì)象時(shí),將對(duì)象表達(dá)式按key-value的方式展開
const names=["abc","wjy","nba"];

// * 1.函數(shù)調(diào)用時(shí)
function foo(x,y,z){
  console.log(x,y,z);
}
foo.apply(null,names);//這種方式也可以,但是閱讀性非常差
foo(...names)
let str="wjy";
foo(...str)

// * 2.構(gòu)造數(shù)組時(shí)
const newNames=[...names]

//*  3. ES2018 (ES9)構(gòu)造 字面量對(duì)象
let info={
  name:"wjy",
  age:20,
  height:160
}
let newInfo={...info,...names}; //* 數(shù)組展開在對(duì)象中,key是對(duì)應(yīng)的索引值
console.log(newInfo);

// * 展開運(yùn)算符其實(shí)是一個(gè)淺拷貝

9.1 展開運(yùn)算符的淺拷貝

const info={
  name:"wjy",
  friend:{
    name:"kobe"
  }
}
// * 淺拷貝的是拷貝的對(duì)象的第一層屬性的值,如果拷貝的對(duì)象的屬性的值引用類型,其實(shí)在拷貝的對(duì)象中對(duì)應(yīng)的屬性的引用的是同一片內(nèi)存空間
const newInfo={...info}
newInfo.friend.name="hyz"
console.log(info);

10.數(shù)值的表示

在ES6中規(guī)范了二進(jìn)制和八進(jìn)制的寫法:

  • 二進(jìn)制:以0b開頭
  • 八進(jìn)制:以0O開頭
  • 十六進(jìn)制:以0x開頭
let num1=100;//默認(rèn)是10進(jìn)制
let num2=0b100;//二進(jìn)制
let num3=0O100;//八進(jìn)制
let num4=0x100;//十六進(jìn)制

console.log(num1,num2,num3,num4);//100 4 64 256


// * 大的數(shù)值(在ES2021 ES12中),允許使用下劃線進(jìn)行連接
// const num=10000000000;//這種可讀性非常差
const num=10_000_000_000;
console.log(num);

11.Symbol的基本使用

Symbol是ES6新增的一個(gè)基本的數(shù)據(jù)類型,翻譯為符號(hào)。

那么為什么需要Symbol呢?

  • 在ES6之前,對(duì)象的屬性都是字符串形式,那么很容易造成屬性名的沖突
  • 比如原來有一個(gè)對(duì)象,我們希望在其中添加一個(gè)新的屬性和值,但是在我們不確定它原來內(nèi)部有什么內(nèi)容的情況下,很容易造成沖突,從而覆蓋它內(nèi)部的某個(gè)屬性
  • 比如我們前面實(shí)現(xiàn)講apply、call、bind實(shí)現(xiàn)時(shí),我們給其中添加一個(gè)fn屬性,那么如果它內(nèi)部原來有一個(gè)fn屬性了呢?
  • 如果在開發(fā)中我們使用了混入,那么混入中出現(xiàn)了同名的屬性,必然有一個(gè)會(huì)被覆蓋掉。

Symbol就是為了解決上面的問題,用來生成一個(gè)獨(dú)一無二的值

  • Symbol的值是通過Symbol函數(shù)來生成的,生成后可以作為屬性名
  • 也就是在ES6中,對(duì)象的屬性名就可以使用字符串,也可以使用Symbol值

Symbol即使多次創(chuàng)建值,它們也是不同的:Symbol函數(shù)每次創(chuàng)建出來的值都是獨(dú)一無二的

我們也可以在創(chuàng)建Symbol值的時(shí)候傳入一個(gè)描述description:這個(gè)是ES2019(ES10)新增的特性

11.1 Symbol作為屬性名

// * 3.Symbol作為key
// * 寫法1
const obj2={
  [s1]:"abc",
  [s2]:"wjy"
}
console.log(obj2);

// * 新增:ES2019 ES10新增可以向Symbol傳入一個(gè)description
obj2[s3]="hyz"
console.log(obj2);

// * 新增
Object.defineProperty(obj2,Symbol("s4"),{
  value:"s4",
  configurable:true,
  enumerable:true,
  writable:true
})

// * 獲取:只能通過[]獲取,不能通過.語法獲取
console.log(obj2[s1]);
console.log(obj2.s1);//* undefined 這樣是獲取不到的,因?yàn)橥ㄟ^.獲取的時(shí)候,會(huì)根據(jù)后面的名字去對(duì)象找對(duì)象的屬性名為這個(gè)的值
// * 4.使用Symbol作為key,在遍歷/Object.keys是獲取不到Symbol屬性值的
// * 需要通過Object.getOwnPropertySymbols來獲取所有的Symbol的key
console.log(Object.keys(obj2));//[]
console.log(Object.getOwnPropertyNames(obj2));//[]
console.log(Object.getOwnPropertySymbols(obj2));//[ Symbol(), Symbol(), Symbol(hyz), Symbol(s4) ]

let sKeys=Object.getOwnPropertySymbols(obj2)

for(const item of sKeys ){
  console.log(obj2[item]);
}

11.2 相同的key生成相同的Symbol

如果想根據(jù)相同的key創(chuàng)建相同的Symbol可以使用Symbol.for(key)

可以通過Symbol.keyFor獲取對(duì)應(yīng)的key

// * 5. Symbol.for(key) :如果想要?jiǎng)?chuàng)建一樣的Symbol值:通過相同的key創(chuàng)建相同的Symbol
const sa=Symbol.for("aaa");
const sb=Symbol.for("aaa");
console.log(sa==sb);//true

// * 獲取key
const key=Symbol.keyFor(sa);
console.log(key);

12.總結(jié)

ES6知識(shí)點(diǎn)詳解.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容