es6語(yǔ)言特性的總結(jié)(3)

es6語(yǔ)言特性的總結(jié)(1)在這里
es6語(yǔ)言特性的總結(jié)(2)在這里

在ES5中受啥,由于沒(méi)有類的概念,所以如果要使用面向?qū)ο缶幊痰姆绞秸买迹托枰迷屠^承的方式兜辞。通常是創(chuàng)建一個(gè)構(gòu)造器,然后將方法指派到該構(gòu)造器的原型上间螟。
就像這樣:

function Cat(name) {
  this.name = name;
}

Cat.prototype.speak = function() {
  console.log('Mew!');
}

ES6引入了class關(guān)鍵字后就不再需要這樣做了逗抑。不過(guò)需要明白的是ES6中的類僅僅是以上面這種方式作為基礎(chǔ)的一個(gè)語(yǔ)法糖而已。
ES6中類聲明已class關(guān)鍵字開(kāi)始寒亥,其后是類的名稱邮府;剩余部分的語(yǔ)法部分看起來(lái)就像對(duì)象字面量中的方法簡(jiǎn)寫(xiě),并且在方法之間不需要使用逗號(hào)溉奕。同時(shí)允許你在其中使用特殊的 constructor 方法名稱直接定義一個(gè)構(gòu)造器褂傀,而不需要先定義一個(gè)函數(shù)再把它當(dāng)作構(gòu)造器使用。

class Cat {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log('Mew!');
  }
}

類聲明與ES5仿類的區(qū)別

雖然ES6的類聲明是ES5方式的一個(gè)語(yǔ)法糖加勤,但是與之相比仙辟,還是存在一些區(qū)別的。

  1. 類聲明不會(huì)被提升鳄梅,這與函數(shù)定義不同叠国。類聲明的行為與 let 相似,因此在程序的執(zhí)行到達(dá)聲明處之前戴尸,類會(huì)存在于暫時(shí)性死區(qū)內(nèi)粟焊。
  2. 類聲明中的所有代碼會(huì)自動(dòng)運(yùn)行在嚴(yán)格模式下,并且也無(wú)法退出嚴(yán)格模式孙蒙。
  3. 類的所有方法都是不可枚舉的项棠,這是對(duì)于自定義類型的顯著變化,后者必須用 Object.defineProperty() 才能將方法改變?yōu)椴豢擅杜e挎峦。
  4. 類的所有方法內(nèi)部都沒(méi)有 [[Construct]] 香追,因此使用 new 來(lái)調(diào)用它們會(huì)拋出錯(cuò)誤。
  5. 調(diào)用類構(gòu)造器時(shí)不使用 new 坦胶,會(huì)拋出錯(cuò)誤透典。
  6. 試圖在類的方法內(nèi)部重寫(xiě)類名,會(huì)拋出錯(cuò)誤顿苇。

訪問(wèn)器屬性

自有屬性需要在類構(gòu)造器中創(chuàng)建峭咒,而類還允許你在原型上定義訪問(wèn)器屬性。

class Person {
  constructor(name, age) {
    this.age = age;
    this.name = name;
  }
  
  get firstName() {
    return this.name.split(' ')[0];
  }
  
  set firstName(value) {
    let lastName = this.name.split(' ')[1];
    this.name = value + ' ' + lastName;
  }
}

let person = new Person('Michael Jackson', 35);
console.log(person.firstName); //'Michael'
person.firstName = 'Marry';
console.log(person.name); // 'Marry Jackson'

在讀取訪問(wèn)器屬性的時(shí)候岖圈,會(huì)調(diào)用getter方法讹语,而寫(xiě)入值的時(shí)候,會(huì)調(diào)用setter方法蜂科。這類似于ES5中使用Object.definePropery的方法顽决。

靜態(tài)成員

靜態(tài)成員在ES5中一般是直接定義在構(gòu)造器上的短条,如:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.createAdult = function(name) {
  return new Person(name, 18);
};

而在ES6中提供了static關(guān)鍵字簡(jiǎn)化了聲明靜態(tài)成員的方式:

class Person {
  constructor(name, age) {
    this.age = age;
    this.name = name;
  }
  
  static createAdult(name) {
    return new Person(name, 18);
  }
   
}

繼承

ES5中實(shí)現(xiàn)繼承的方式有很多種,但是如果要實(shí)現(xiàn)嚴(yán)格的繼承才菠,步驟較為繁瑣茸时。為了簡(jiǎn)化繼承的關(guān)系,ES6中使用類讓這項(xiàng)工作變得更簡(jiǎn)單赋访。如果你熟悉面向?qū)ο笳Z(yǔ)言可都,如java等,那么extends這個(gè)關(guān)鍵你一定不會(huì)陌生蚓耽。同樣的渠牲,在ES6中使用extends 關(guān)鍵字來(lái)指定當(dāng)前類所需要繼承的函數(shù)即可。生成的類的原型會(huì)被自動(dòng)調(diào)整步悠,而你還能調(diào)用 super() 方法來(lái)訪問(wèn)基類的構(gòu)造器签杈。

class Person {
    constructor(country) {
      this.country = country;
    }
}

class Chinese extends Person{
    constructor() {
      super('China');
    }
    
    speak() {
      console.log('I come from ' + this.country);
    }
}

派生類中的方法總是會(huì)屏蔽基類中的同名方法,因此鼎兽,如果你需要使用父類中定義的方法的話答姥,可以使用super關(guān)鍵字來(lái)進(jìn)行訪問(wèn)。如:

class Person {
    constructor(country) {
      this.country = country;
    }
    
    speak() {
      console.log('I come from ' + this.country);
    }
}

class Chinese extends Person{
    constructor() {
      super('China');
    }
    
    speak() {
        super.speak();
        console.log('I am a Chinese');
    }
}

const chinese = new Chinese();
chinese.speak();
//I come from China.
//I am a Chinese.

從表達(dá)式中派生類

另一個(gè)在ES6中比較高級(jí)的地方是谚咬,可以從表達(dá)式中派生出類來(lái):

let SerializableMixin = {
    serialize() {
        return JSON.stringify(this);
    }
};

let AreaMixin = {
    getArea() {
        return this.length * this.width;
    }
};

//混入
function mixin(...mixins) {
    var base = function() {};
    Object.assign(base.prototype, ...mixins);
    return base;
}

class Square extends mixin(AreaMixin, SerializableMixin) {
    constructor(length) {
        super();
        this.length = length;
        this.width = length;
    }
}

var x = new Square(3);
console.log(x.getArea());               // 9
console.log(x.serialize());             // "{"length":3,"width":3}"

繼承內(nèi)置對(duì)象

利用extends繼承內(nèi)置對(duì)象的時(shí)候鹦付,容易出現(xiàn)的一個(gè)問(wèn)題是會(huì)返回內(nèi)置對(duì)象實(shí)例的方式,在繼承后會(huì)返回子類的實(shí)例择卦。如:

class SubArray extends Array {
  
}

const subArr = new SubArray(1,2,3);
const filteredArr = subArr.filter(value => value > 1); 
console.assert(filteredArr instanceof SubArray);  //true

如果需要想讓其返回實(shí)例類型是Array可以利用Symbol.species這個(gè)符號(hào)來(lái)處理:

class SubArray extends Array {
//這里使用static敲长,表明是靜態(tài)訪問(wèn)器屬性
  static get [Symbol.species]() {
    return Array;
  }
}

定義抽象類

利用之前介紹的new.target可以實(shí)現(xiàn)一個(gè)抽象類,原理就是當(dāng)用戶調(diào)用new直接創(chuàng)建實(shí)例的時(shí)候互捌,拋出錯(cuò)誤潘明。:

class BaseClass {
  constructor() {
    if(new.target === BaseClass) {
      throw new Error('該類不能直接實(shí)例化')
    }
  }
}

模塊

隨著項(xiàng)目的規(guī)模越來(lái)越大行剂,現(xiàn)在模塊化已經(jīng)成為開(kāi)發(fā)過(guò)程中必備的流程秕噪。之前,我們可能借助RequireJS等工具進(jìn)行模塊化管理厚宰,而現(xiàn)在ES6已經(jīng)提供了模塊系統(tǒng)腌巾。

先來(lái)了解一下基本語(yǔ)法:

基本的導(dǎo)出導(dǎo)入

模塊( Modules )本質(zhì)上就是 包含JS 代碼的文件。在一個(gè)js文件中铲觉,你可以使用export關(guān)鍵字澈蝙,將代碼公開(kāi)給其他模塊。

// sayHello.js
export function sayHello() {
  console.log('hello');
}

// funcs.js
export function fun1() { .... }
export function func2() { .... }
export const value1 = 'value1';

如上面的例子中所示撵幽,你可以在文件中導(dǎo)出所有的最外層函數(shù)灯荧、以及varletconst聲明的變量盐杂。而這些導(dǎo)出的變量或公開(kāi)部分則可以被其他文件利用import語(yǔ)法進(jìn)行導(dǎo)入后引用逗载。

//單個(gè)導(dǎo)入
import {sayHello} from './sayHello.js';
//多個(gè)導(dǎo)入
import {func1, func2} from './funs.js';
sayHello(); // hello

為了確保瀏覽器與Node.js之間保持良好的兼容性哆窿,建議使用相對(duì)路徑的寫(xiě)法。

如果需要將整個(gè)模塊當(dāng)做單一的對(duì)象進(jìn)行導(dǎo)入厉斟,可以使用*通配符:

//使用as關(guān)鍵字為導(dǎo)出對(duì)象設(shè)置別名挚躯,模塊中所有導(dǎo)出都將作為屬性存在
import * as funcs from './funcs.js';

funcs.func1();
funsc.func2();

重命名導(dǎo)出與導(dǎo)入

如果不想用原來(lái)模塊中的命名,可以通過(guò)as關(guān)鍵字來(lái)指定別名擦秽。

//as前面為模塊原先的名稱码荔,后面是別名,使用別名后sayHello為undefined
import { sayHello as say } from './sayHello.js';

say();

默認(rèn)值

你可以使用export關(guān)鍵字來(lái)導(dǎo)出默認(rèn)模塊:

// sayHello.js
export default function() {
  console.log('hello');
}

// main.js
import sayHello from './sayHello.js';
sayHello();

可以注意到感挥,這里默認(rèn)導(dǎo)出的時(shí)候缩搅,不需要使用花括號(hào),而直接為其命名即可触幼。這種寫(xiě)法也較為簡(jiǎn)潔誉己。當(dāng)一個(gè)文件中,同時(shí)存在默認(rèn)導(dǎo)出模塊和非默認(rèn)導(dǎo)出模塊的時(shí)候域蜗,導(dǎo)出的時(shí)候巨双,默認(rèn)導(dǎo)出模塊需要寫(xiě)在前面,例如:

import sayHello,{ func1 } from './sayHello.js'; //此處略去導(dǎo)出過(guò)程
//或者使用如下方式
import {default as sayHello, func1} from './sayHello.js';

無(wú)綁定導(dǎo)出

當(dāng)一個(gè)文件中沒(méi)有使用export語(yǔ)句進(jìn)行導(dǎo)出的時(shí)候霉祸,其實(shí)我們還是可以import進(jìn)行導(dǎo)入的筑累。通常是被用于創(chuàng)建polyfill與shim的時(shí)候。

//sayHello.js
const name = 'scq000';
function sayHello() {
    console.log('hello');
}

// main.js
import './sayHello.js';

sayHello();
console.log(name);

加載模塊

雖然說(shuō)現(xiàn)在在項(xiàng)目中通常都使用webpack來(lái)處理模塊代碼丝蹭,但也需要知道其他加載模塊的方式慢宗。

你可以使用<script type="module">的方式進(jìn)行模塊的加載,默認(rèn)瀏覽器會(huì)采用defer屬性奔穿,一旦頁(yè)面文檔完全被解析后镜沽,模塊就會(huì)按次序執(zhí)行。如果需要異步加載的話贱田,可以加上async關(guān)鍵字缅茉。

另外,如果是使用Web Worker或Server Worker之類的worker的話男摧,可以通過(guò)下面這種方式加載模塊:

let worker = new Worker('module.js', { type: 'module' });

迭代器與生成器

迭代器和生成器通常是一起來(lái)使用的蔬墩。迭代器的目的是為了更加方便地遍歷對(duì)象,而生成器用來(lái)生成可迭代的對(duì)象耗拓。使用迭代器的過(guò)程中拇颅,你可以結(jié)合for...of語(yǔ)句以及...擴(kuò)展符來(lái)遍歷對(duì)象的值。

迭代器

在ES6中乔询,迭代器是專門用來(lái)設(shè)計(jì)迭代的對(duì)象樟插,帶有特殊的接口。所有的迭代器都帶有next方法,用來(lái)返回一個(gè)結(jié)果黄锤。這里我們來(lái)手工實(shí)現(xiàn)一個(gè)迭代器:

function createIterator() {
    var i = 0;

    return {
        next() {
            var done = false;
            var value;
            if (i < 3) {
                value = i * 2;
                i++;
            } else {
                done = true;
                value = undefined;
            }
            return { value: value, done: done }
        }
    }
}

let iterator = new createIterator();
iterator.next(); // {value: 0, done: false}
iterator.next(); // {value: 0, done: false}
iterator.next(); // {value: 4, done: false}
iterator.next(); // {value: undefined, done: true}

集合對(duì)象(Set麻献、Map、Array)提供了三種內(nèi)置的迭代器:entries,keys,values猜扮,這三個(gè)方法都會(huì)返回一個(gè)迭代器勉吻,用來(lái)方便地獲取鍵值對(duì)等信息。ES6中定義了可迭代對(duì)象(iterable object)旅赢,如Set齿桃、Map、Array以及字符串等都可以利用for...of語(yǔ)法來(lái)進(jìn)行遍歷操作煮盼。原理其實(shí)就是調(diào)用它們內(nèi)置的默認(rèn)迭代器短纵。對(duì)于用戶自定義的對(duì)象,如果也要讓它們支持for...of語(yǔ)法僵控,則需要去定義Symbol.iterator屬性香到。具體例子,可以查看符號(hào)那一部分的內(nèi)容报破。

生成器

生成器(generator)是能夠返回迭代器的函數(shù)悠就。通常定義的時(shí)候,我們會(huì)利用function關(guān)鍵字之后的(*)號(hào)表示充易,使用yield語(yǔ)句輸出每一次的數(shù)據(jù)梗脾。

function *getNum() {
  yield 1;
  yield 2;
  yield 3;
}

const nums = getNum();

for(let num of nums) {
  console.log(num);
}
//1,2,3

Promise與異步編程

這部分的內(nèi)容我在前端的異步解決方案之Promise和Await/Async中有詳細(xì)的闡述,如果感興趣的可以看一下盹靴。

代理與反射接口

為了讓開(kāi)發(fā)者能夠創(chuàng)建內(nèi)置對(duì)象炸茧,ES6通過(guò)代理proxy )的方式暴露了對(duì)象上的內(nèi)部工作。使用代理能夠攔截并改變 JS 引擎的底層操作稿静,如日志梭冠、對(duì)象虛擬化等。而反射reflect )則是反映了對(duì)底層的默認(rèn)行為操作改备。

接下來(lái)這個(gè)例子控漠,將演示如何利用代理和反射的方式對(duì)對(duì)象的內(nèi)置行為做修改:

//要修改的默認(rèn)對(duì)象
let target = {
    name: 'scq000',
    age: 23
};

//代理對(duì)象
let proxy = new Proxy(target, {
  has(trapTarget, key) {
    if(key === 'age') {
      return false;
    }else {
    //調(diào)用默認(rèn)的行為
      return Reflect.has(trapTarget, key);
    }
  }
});

console.log('value' in proxy); //true
console.log('age' in proxy); //false

可以看到,上面這個(gè)例子使用代理對(duì)象攔截了in操作符的默認(rèn)行為并作出了修改绍妨。has這個(gè)方法稱作陷阱函數(shù)润脸,它能夠響應(yīng)對(duì)in操作的訪問(wèn)操作。trapTarget則是這個(gè)函數(shù)的目標(biāo)對(duì)象他去,has方法接受一個(gè)額外的參數(shù)key是對(duì)應(yīng)著需要檢查的屬性。一旦檢查到屬性名為age倒堕,則返回false,這樣就能隱藏這個(gè)屬性灾测。

以下是一些常用的代理陷阱以及反射所對(duì)應(yīng)的默認(rèn)行為:

代理陷阱 被重寫(xiě)的行為 默認(rèn)行為
get/set 讀取/寫(xiě)入一個(gè)屬性值 Reflect.get/Reflect.set
has in運(yùn)算符 Reflect.has
deleteProperty delete運(yùn)算符 Reflect.deleteProperty
getPropertyOf/setPropertyOf Object.getPropertyOf/setPropertyOf Reflefct.getPropertyOf/setPropertyOf

目前,反射和代理在瀏覽器上還不支持,主要還是用在NodeJS編程上媳搪。這一部分的功能在實(shí)際開(kāi)發(fā)中并不是特別常用铭段,因此,這里不做過(guò)多介紹秦爆。如果感興趣的話序愚,可以自行查找相關(guān)文檔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末等限,一起剝皮案震驚了整個(gè)濱河市爸吮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌望门,老刑警劉巖形娇,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異筹误,居然都是意外死亡桐早,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門厨剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哄酝,“玉大人,你說(shuō)我怎么就攤上這事祷膳§牌撸” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵钾唬,是天一觀的道長(zhǎng)万哪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)抡秆,這世上最難降的妖魔是什么雕凹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮翠语,結(jié)果婚禮上韵卤,老公的妹妹穿的比我還像新娘。我一直安慰自己着撩,他們只是感情好诅福,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著拖叙,像睡著了一般氓润。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上薯鳍,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天咖气,我揣著相機(jī)與錄音,去河邊找鬼。 笑死崩溪,一個(gè)胖子當(dāng)著我的面吹牛浅役,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伶唯,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼觉既,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了乳幸?” 一聲冷哼從身側(cè)響起瞪讼,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎反惕,沒(méi)想到半個(gè)月后尝艘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姿染,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年背亥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悬赏。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狡汉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闽颇,到底是詐尸還是另有隱情盾戴,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布兵多,位于F島的核電站尖啡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剩膘。R本人自食惡果不足惜衅斩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怠褐。 院中可真熱鬧畏梆,春花似錦、人聲如沸奈懒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)磷杏。三九已至溜畅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茴丰,已是汗流浹背达皿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工天吓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贿肩,地道東北人峦椰。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像汰规,于是被迫代替她去往敵國(guó)和親汤功。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一溜哮、ES6簡(jiǎn)介 ? 歷時(shí)將近6年的時(shí)間來(lái)制定的新 ECMAScript 標(biāo)準(zhǔn) ECMAScript 6(亦稱 ...
    一歲一枯榮_閱讀 6,071評(píng)論 8 25
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理滔金,服務(wù)發(fā)現(xiàn),斷路器茂嗓,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持餐茵,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠述吸,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 3,657評(píng)論 2 27
  • 以下內(nèi)容是我在學(xué)習(xí)和研究ES6時(shí)忿族,對(duì)ES6的特性、重點(diǎn)和注意事項(xiàng)的提取蝌矛、精練和總結(jié)道批,可以做為ES6特性的字典;在本...
    科研者閱讀 3,126評(píng)論 2 9
  • 無(wú)邊的黑夜里入撒,只有角落木柜旁有一束手機(jī)的光亮隆豹,男人靠在那,用無(wú)比沙啞難以追溯根源的縹緲的聲音一邊又一遍唱著那首歌茅逮。...
    楠?dú)e閱讀 413評(píng)論 4 3