es6+疑難解析

實(shí)際上 JavaScript 是 ECMAScript 的擴(kuò)展語言
ECMAScript 只提供了最基本的語法


瀏覽器端
服務(wù)器端

es6發(fā)布的特性可歸納為以下4類:

  1. 解決原有語法上的一些問題或者不足(如:let祭隔、const)
  2. 對原有語法進(jìn)行增強(qiáng)(如:解構(gòu)賦值)
  3. 全新的對象浦徊、全新的方法、全新的功能(如:promise)
  4. 全新的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)(如:symbol、set这嚣、get)

到目前為止煞躬,es6+中共有8種數(shù)據(jù)類型轻抱,分別是:
StringNumber嫌褪、Boolean呀枢、nullundefined笼痛、Symbol裙秋、BigIntObject
下面我們分別來對es6中的新特性來做下介紹缨伊。

1. let摘刑、const

首先來看var與let的區(qū)別

  1. var會變量提升,let不會
  2. let會形成塊級作用域刻坊,僅在塊級作用域內(nèi)有效
  3. let會形成暫時(shí)性死區(qū)泣侮,在作用域內(nèi),聲明前不可使用
  4. 同一個(gè)作用域內(nèi)紧唱,let不允許重復(fù)聲明

const和let作用類似,但是const在let基礎(chǔ)上多了只讀屬性(變量聲明過后不允許再被修改)隶校,另外const不允許修改是指不允許修改內(nèi)存地址漏益,而不是指不允許修改常量中的屬性。
來看下面代碼深胳,我們可以發(fā)現(xiàn)绰疤,i的輸出每次都為foo,而不是for循環(huán)中i的值舞终,

for (let i = 0; i < 3; i++) {
  let i = "foo";
  console.log(i); // foo
}

來對for循環(huán)做一下拆解轻庆,結(jié)合上面let的的功能,我們就明白了敛劝。

let i = 0;
if (i < 3) {
  let i = "foo";
  console.log(i);
}
i++;
if (i < 3) {
  let i = "foo";
  console.log(i);
}
i++;
if (i < 3) {
  let i = "foo";
  console.log(i);
}
i++;

我們可以看到余爆,let形成了塊級作用域,所以每次的i都為'foo',只有當(dāng)我們沒有在塊作用域中聲明i時(shí)夸盟,i的值才會取外部for循環(huán)中的i

總結(jié):建議主用const蛾方,輔助let,不用var

2. 賦值解構(gòu)

2.1 數(shù)組賦值解構(gòu)

來看下面這個(gè)例子上陕,當(dāng)我們需要獲取路徑時(shí)桩砰,es5中我們需要這么做

var path = '/foo/bar/baz'
var tmp = path.split('/')
var rootDir = tmp[1]

而在es6中使用賦值解構(gòu),我們只需要按如下寫法:

const [, rootDir] = path.split('/')
console.log(rootDir)

2.2 對象賦值解構(gòu)

我們來對對象做賦值解構(gòu)释簿,并為之設(shè)置別名和默認(rèn)值:

const obj = { name: "zxh", age: 18 };
const { name: objName = 'jack' } = obj;
console.log(objName);

應(yīng)用:簡化console.log()方法

const { log } = console
log(1)

3. 模版字符串

3.1 換行

在es5中亚隅,如果我們需要對字符串換行,那么我們需要在每行末尾使用\n庶溶,那么在es6中煮纵,就簡單多了懂鸵,來看下面例子:

const str = `
  this is first 
  this is second
`

3.2 轉(zhuǎn)義

如果字符串中含有** ` **,那么我們需要使用\來轉(zhuǎn)義

const str = `this is a \`string\``

3.3 帶標(biāo)簽的模版字符串

const name = "tom";
const gender = true;
function myTagFunc(strings, name, gender) {
  console.log(strings); // ['hey,', 'is a', '.']
  console.log(name); // tom
  console.log(gender); // true
  return 1;
}
const result = myTagFunc`hey, ${name} is a ${gender}.`;
console.log(result); // 1

4. 字符串?dāng)U展

startsWithendsWith醉途、includes

5. 函數(shù)擴(kuò)展

5.1 函數(shù)參數(shù)默認(rèn)值

如果函數(shù)某個(gè)參數(shù)有默認(rèn)值矾瑰,那么有默認(rèn)值的參數(shù)必須寫在尾部。如果非尾部的參數(shù)設(shè)置默認(rèn)值隘擎,那么該參數(shù)的實(shí)參是沒法省略的殴穴。

function f(x = 1, y) {
  return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined]
f(, 1) // 報(bào)錯(cuò)
f(undefined, 1) // [1, 1]

如果我們給函數(shù)傳入undefined,將觸發(fā)該參數(shù)等于默認(rèn)值货葬,null則沒有這個(gè)效果采幌。

function f(x, y = 5, z) {
  return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 報(bào)錯(cuò)
f(1, undefined, 2) // [1, 5, 2]

// -----------------------------------
function foo(x = 5, y = 6) {
  console.log(x, y);
}

foo(undefined, null)
// 5 null

5.2 剩余參數(shù)

剩余參數(shù)只能出現(xiàn)在尾部,并且只能使用一次

function getname(name, ...args) {}

5.3 函數(shù)length屬性

指定了默認(rèn)值以后震桶,函數(shù)的length屬性休傍,將返回沒有指定默認(rèn)值的參數(shù)個(gè)數(shù)。也就是說蹲姐,指定了默認(rèn)值后磨取,length屬性將失真。
length屬性的含義是柴墩,該函數(shù)預(yù)期傳入的參數(shù)個(gè)數(shù)忙厌。某個(gè)參數(shù)指定默認(rèn)值以后,預(yù)期傳入的參數(shù)個(gè)數(shù)就不包括這個(gè)參數(shù)了江咳。同理逢净,rest 參數(shù)也不會計(jì)入length屬性

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function(...args) {}).length // 0
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1

5.4 箭頭函數(shù)

我們通過篩選數(shù)組中的基數(shù)這個(gè)例子來看普通函數(shù)和箭頭函數(shù)區(qū)別

// 普通函數(shù)
const arr = [1, 2, 3, 4, 5, 6, 7];
arr.filter(function (item) {
  return item % 2;
});

// 箭頭函數(shù)
arr.filter(i => i % 2);

必包:

// 這也算一個(gè)必包歼指,setTimeout是在sayHiAsync函數(shù)外執(zhí)行的爹土,但是拿到了sayHiAsync函數(shù)的this
const person = { 
    name: 'tom',
    sayHiAsync() {
        const _this = this
        setTimeout(function () {
            console.log(_this.name)
        }, 1000)
    }
}

6. 對象

6.1 計(jì)算()動(dòng)態(tài)屬性名

const obj = {
  [Math.random]: 123
}

6.2 Object.is()

由于==會做隱式轉(zhuǎn)換,而===又無法判斷NaN踩身,因此我們可以使用Object.is()

console.log(0==false) // true
console.log(0===false) // false
console.log(+0===-0) // true
console.log(NaN===NaN) // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

7. proxy

7.1 Object.defineProperty與Proxy區(qū)別

  1. defineProperty只能監(jiān)視屬性的讀寫胀茵,而Proxy監(jiān)聽的更多對象操作。
    具體可參考下圖表格:


    image.png
  2. 支持?jǐn)?shù)組對象監(jiān)視
    ES5通過重寫數(shù)組方法來實(shí)現(xiàn)劫持惰赋,Proxy如下:
const list = []
const listProxy = new Proxy(list, {
    set(target, property, value) {
        console.log('set', property, value) // 0 100
        target[property] = value
        return true
    }
})
listProxy.push(100)
  1. 非侵入式監(jiān)聽宰掉,不需要對原對象做任何操作

8. Reflect

8.1 Reflect成員方法就是Proxy處理對象的默認(rèn)實(shí)現(xiàn)

const obj = {
  foo: "123",
  bar: "456",
};

const proxy = new Proxy(obj, {
  // 如果我們沒有定義get方法,那么Proxy會默認(rèn)一個(gè)get方法如下赁濒,返回Reflect
  get(target, property) {
    console.log(" watch logic~");
    return Reflect.get(target, property);
  },
});
console.log(proxy.foo);

8.2 Reflect最大作用是提供了一套完整的對象調(diào)用方法

它的內(nèi)部封裝了一系列對對象的底層操作轨奄,便于我們更方便的操作對象

const obj = {
  name: "zce",
  age: 18,
};
// es5
console.log("name" in obj);
console.log(delete obj["age"]);
console.log(Object.keys(obj));
// Reflect
console.log(Reflect.has(obj, "name"));
console.log(Reflect.deleteProperty(obj, "age"));
console.log(Reflect.ownKeys(obj));

Reflect共有13個(gè)api,具體查閱文檔

8. Promise

9. 類

9.1 靜態(tài)方法

es5中通過給函數(shù)掛載方法來實(shí)現(xiàn)靜態(tài)方法(函數(shù)也是一個(gè)對象拒炎,可以像對象一樣直接掛載)挪拟,在中es6,我們通過static關(guān)鍵詞來定義靜態(tài)方法
注意:靜態(tài)方法的this不指向?qū)嵗龑ο?/strong>

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();

2. 繼承

class Student extends Person {
  constructor(name, number) {
    super(name, number);
    this.number = number;
  }
  hello() {
    super.say();
    console.log(`my school number is ${this.number}`);
  }
}

const s = new Student("jack", " 100");
s.hello();

10. Set Map

10.1 Set

我們通過Array.from()或者展開運(yùn)算符可以將Set轉(zhuǎn)化為數(shù)組

const arr = [1, 2, 3, 4, 5]
const result = Array.from(new Set(arr))
// or
const result = [...new Set(arr)]

10.2 Map

與對象類似击你,是一個(gè)鍵值對集合玉组,目的是為了解決對象只能用字符串作鍵值
在es5中谎柄,普通對象如果鍵不是字符串,那么鍵就等于輸入鍵的toString()結(jié)果作為鍵惯雳,es6開始對象支持用字符串或Symbol來作為鍵值朝巫。而在Map中,任意類型數(shù)據(jù)都可作為鍵

// 普通對象
const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{ a: 1 }] = 'value'
// 如果鍵不是字符串石景,那么鍵就等于輸入鍵的toString()結(jié)果作為鍵
console.log(Object.keys(obj)) // ['true', '123', '[object Object]']

// Map 任意類型數(shù)據(jù)都可作為鍵
const m = new Map();
const tom = { name: "tom" };
m.set(tom, 90);
console.log(m);
console.log(m.get(tom));

11. Symbol

es6開始對象支持用字符串或Symbol來作為鍵值劈猿,symbol最主要的作用就是為對象添加獨(dú)一無二的屬性名

Symbol()===Symbol // false
// Symbol 描述符
Symbol('foo')
Symbol('bar')

11.1 利用Symbol來實(shí)現(xiàn)私有成員

// a.js ======================================
const name = Symbol();
const person = {
  [name]: "zce",
  say() {},
};

// b.js =======================================
// Symbol是唯一的,外面的Symbol與定義時(shí)的不一樣
// person[Symbol()]
person.say();

11.2 如何獲取Symbol

  1. 通過Symbol.for()傳入標(biāo)識符獲取
const s1 = Symbol.for('foo') // 傳入標(biāo)識符
const s2 = Symbol.for('foo')
console.log(s1 === s2) // true
Symbol('foo') === Symbol('foo') // false

注意潮孽,傳入的標(biāo)識符應(yīng)該是字符串揪荣,如果不是字符串,會默認(rèn)轉(zhuǎn)為字符串往史,所以以下代碼是相等的

Symbol.for(true) === Symbol.for('true')

11.3 擴(kuò)展方法

const obj0 = {};
console.log(obj0.toString()); // [object Object]

const obj1 = {
  [Symbol.toStringTag]: "Xobject",
};
console.log(obj1.toString()); // [object Xobject]

11.4 獲取Symbol鍵值

普通的for in仗颈、Object.keys()JSON.stringify()是獲取不到Symbol的鍵值的椎例,我們需要通過Object.getOwnPropertySymbols獲取挨决,所以Symbol特別適合設(shè)置對象私有成員

const obj = {
  [Symbol()]: "symbol value",
  foo: "normal value",
};

for (var key in obj) {
  console.log(key); // foo
}
console.log(Object.keys(obj)); //  'foo' ]
console.log(JSON.stringify(obj)); // {"foo":"normal value"}
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol() ]

12. for of

for of可以通過break跳出循環(huán),在代碼中建議使用for of订歪。但是我們可以發(fā)現(xiàn)凰棉,for of不支持對象,因?yàn)閷ο鬀]有實(shí)現(xiàn)Iterable接口陌粹,我們在Iterable會詳細(xì)講解。
實(shí)現(xiàn)Iterable接口就是for..of的前提,也就是說福压,只要該種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)了(可迭代接口)Iterable,那么就可以使用for of

const arr = [1, 2, 3, 4, 5];
for (const item of arr) {
  console.log(item); // 1,2,3,4,5
  if (item > 100) {
    break;
  }
}

const m = new Map();
m.set("foo", "123");
m.set("bar", " 345");
for (const [key, value] of m) {
  console.log(key, value);
}

13. Iterable(迭代器)

13.1 每一個(gè)可迭代數(shù)據(jù)原型上都有一個(gè)Symbol.iterator方法

const set = new Set(["foo", "bar", "baz"]);
const iterator = set[Symbol.iterator]();
console.log(iterator.next()); // { value: 'foo', done: false }
console.log(iterator.next()); // { value: 'bar', done: false }
console.log(iterator.next()); // { value: 'baz ', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
console.log(iterator.next()); // { value: undefined, done: true }

13.2 給對象添加迭代器

給對象添加迭代器以后掏秩,就可以使用for of循環(huán)了

const obj = {
    store: ['foo', 'bar', 'baz'],
    [Symbol.iterator]: function () {
        let index = 0
        const _self = this
        return {
            next: function () {
                const result = {
                    value: _self.store[index],
                    done: index >= _self.store.length
                }
                index++
                return result
            }
        }
    }
}

13.3 迭代器應(yīng)用

遍歷結(jié)構(gòu)

const todos = {
    life: ['吃皈', '睡覺', '打豆豆'],
    learn: ['語文', '數(shù)學(xué)', '外語'],
    work: ['喝茶'],
    // 普通模式,通過each模式
    each: function (callback) {
        const all = [].concat(this.life, this.learn, this.work)
        for (const item of all) {
            callback(item)
        }
    },
    // 迭代器模式
    [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
                }
            }
        }
    }
}

// 使用each
todos.each(function (item) {
    console.log(item)
})

// 使用迭代器
for(const item of todos) {
  console.log(item)
}

14. Generator(生成器)

解決異步嵌套

14.1 應(yīng)用

  1. 使用Generator實(shí)現(xiàn)迭代器
// 以上一節(jié)例子為例
[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
        //         }
        //     }
        // }
        for (const item of all) {
            yield item
        }
    }
  1. 發(fā)號器
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)

15. es2016

15.1 includes

indexof不能查找數(shù)組中的NaN(掘金遍歷數(shù)組的文章)

15.2 指數(shù)運(yùn)算

計(jì)算2的10次方

// es5: 
Math.pow(2, 10)
// es7: 
2 ** 10

16. es2017

16.1 對象擴(kuò)展

Object.values() // 對象值的數(shù)組
Objece.entries // 對象鍵值對數(shù)組

  1. 通過Objece.entries 可以使對象用for of 循環(huán)
const obj = {
    foo: 'foo',
    bar: 'bar'
}
for (const [item, index] of Object.entries(obj)) { 
    console.log(index, item)
}
  1. 將對象轉(zhuǎn)為Map形式對象
new Map(Object.entries(obj))
  1. Object.getOwnPropertyDescriptors
    以下問題荆姆,當(dāng)拷貝一個(gè)對象時(shí)蒙幻,對象中的getter屬性被當(dāng)作了普通屬性,所以修改p2中firstName的值胆筒,fullName沒有變化邮破,這時(shí)我們可以通過Object.getOwnPropertyDescriptors解決
const p1 = {
    firstName: 'Lei',
    lastName: 'Wang',
    get fullName() {
        return this.firstName + ' ' + this.lastName
    }
}
console.log(p1.fullName) // Lei Wang

const p2 = Object.assign({}, p1)
p2.firstName = 'Zhao'
console.log(p2.fullName) // Lei wang

const descriptors = Object.getOwnPropertyDescriptors(p1)
const p2 = Object.defineProperties({}, descriptors)
p2.firstName = 'Zhao'
console.log(p2.fullName) // zhao wang

16.2 padStart、padEnd

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仆救,一起剝皮案震驚了整個(gè)濱河市抒和,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彤蔽,老刑警劉巖摧莽,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異顿痪,居然都是意外死亡镊辕,警方通過查閱死者的電腦和手機(jī)油够,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來征懈,“玉大人石咬,你說我怎么就攤上這事÷舭ィ” “怎么了鬼悠?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長棉饶。 經(jīng)常有香客問我厦章,道長,這世上最難降的妖魔是什么照藻? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任袜啃,我火速辦了婚禮,結(jié)果婚禮上幸缕,老公的妹妹穿的比我還像新娘群发。我一直安慰自己,他們只是感情好发乔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布熟妓。 她就那樣靜靜地躺著,像睡著了一般栏尚。 火紅的嫁衣襯著肌膚如雪起愈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天译仗,我揣著相機(jī)與錄音抬虽,去河邊找鬼。 笑死纵菌,一個(gè)胖子當(dāng)著我的面吹牛阐污,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咱圆,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼笛辟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了序苏?” 一聲冷哼從身側(cè)響起手幢,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忱详,沒想到半個(gè)月后弯菊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年管钳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钦铁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡才漆,死狀恐怖牛曹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情醇滥,我是刑警寧澤黎比,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鸳玩,受9級特大地震影響阅虫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜不跟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一颓帝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窝革,春花似錦购城、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漆诽,卻和暖如春侮攀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厢拭。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工魏身, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚪腐。 一個(gè)月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像税朴,于是被迫代替她去往敵國和親回季。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355