ES6語(yǔ)法總結(jié)

摘要 阮一峰《 ECMAScript 6 入門(mén) 》

1. Class

1.1 class的定義

// 定義一個(gè)Animal的類(lèi)(構(gòu)造函數(shù))
class Animal{
  constructor(){
    this.type = 'animal';
  }
  says(say){
    console.log(this.type + ' says ' + say);      
  }  
}
let animal = new Animal();
animal.says('hello'); // animal says hello

class Cat extends Animal{
  constructor(){
    super();
    this.type = 'cat';
  }
}
let cat = new Cat();
cat.says('hello'); // cat says hello

上面的代碼首先用class定義了一個(gè)"類(lèi)"(構(gòu)造函數(shù)),可以看到里面有個(gè)constructor方法,這就是構(gòu)造方法,而this則代表實(shí)例對(duì)象。簡(jiǎn)單的說(shuō),constructor里面的屬性和方法是實(shí)例對(duì)象自己的,而constructor外定義的方法和屬性則是所有實(shí)例對(duì)象所共享的。另外,方法之間不需要逗號(hào)分隔,加了會(huì)報(bào)錯(cuò)。

class之間是可以通過(guò)extends關(guān)鍵字實(shí)現(xiàn)繼承,這比ES5通過(guò)修改原型而清晰和方便很多。上面定義了一個(gè)Cat類(lèi),該類(lèi)通過(guò)extends關(guān)鍵字,繼承了Animal的所有方法和屬性。

super關(guān)鍵字,它代表父類(lèi)的實(shí)例,(即父類(lèi)的this對(duì)象)。子類(lèi)必須在constructor方法中調(diào)用super方法,否則新建的實(shí)例會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇?lèi)沒(méi)有自己的實(shí)例對(duì)象,而是繼承父類(lèi)的實(shí)例對(duì)象,然后對(duì)其進(jìn)行加工。如果不調(diào)用super方法,子類(lèi)就得不到this對(duì)象。

ES6的繼承機(jī)制,實(shí)質(zhì)是先構(gòu)建父類(lèi)的實(shí)例對(duì)象this(所以必須要有super方法),然后再用子類(lèi)的構(gòu)造函數(shù)修改this。

ES6的類(lèi),完全可以看作構(gòu)造函數(shù)的另一種寫(xiě)法。

class Animal{
  // ...
}
typeof Animal // "function"
Animale === Animal.prototype.constructor // true

上面的代碼表明,類(lèi)本身就是構(gòu)造函數(shù)。

與ES5一樣,實(shí)例的屬性除非顯示定義在本身(即定義在this上),否則都是定義在原型上。(即定義在class上)。

animal.hasOwnProperty('type'); // true
animal.hasOwnProperty('says'); // false
animal.__proto__.hasOwnProperty('says'); // true

1.2. class表達(dá)式

const MyClass = class Me{
  getClassName(){
    return Me.name;
}

上面代碼使用了表達(dá)式定義了一個(gè)類(lèi)。需要特別指出的是,這個(gè)類(lèi)的名字是MyClass而不是MeMe只能在內(nèi)部使用,代指當(dāng)前類(lèi)。

let inst = new MyClass();
inst.getClassName(); // Me
Me.name; // ReferenceError: Me is not defined

1.3. super關(guān)鍵字的詳解(繼承)

super這個(gè)關(guān)鍵字,既可以當(dāng)做函數(shù)使用,也可以當(dāng)做對(duì)象使用。這兩種情況的使用完全不同。

第一種情況,super當(dāng)做函數(shù)調(diào)用時(shí),代表的是父類(lèi)的構(gòu)造函數(shù)。ES6要求,子類(lèi)的構(gòu)造函數(shù)必須執(zhí)行一次super()函數(shù)。

class A {}
class B extends A{
  constructor(){
    super();
  }
}

上面代碼中,子類(lèi)B的構(gòu)造函數(shù)中的super(),代表調(diào)用父類(lèi)的構(gòu)造函數(shù)。這是必須的,否則報(bào)錯(cuò)。
注意:super雖然代表了父類(lèi)的構(gòu)造函數(shù)A,但是返回的是子類(lèi)的實(shí)例,即super內(nèi)部的this指向B,因此super()在這里就相當(dāng)于A.prototype.constructor.call(this)。

class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A() // A
new B() // B

上面代碼中,new.target指向當(dāng)前正在執(zhí)行的函數(shù)??梢钥吹?,在super()執(zhí)行時(shí),它指向的是子類(lèi)B的構(gòu)造函數(shù),而不是父類(lèi)A的構(gòu)造函數(shù)。也就是說(shuō),super()內(nèi)部的this指向B。

第二種情況,super作為對(duì)象時(shí),在普通的方法中,指向父類(lèi)的原型對(duì)象;在靜態(tài)方法中,指向父類(lèi)。

class A {
  p(){
    return 2;  
  }
}
class B extends A{
  constructor(){
    super();
    console.log(super.p()); // 2
  }
}

上面代碼中,子類(lèi)B中super.p(),就相當(dāng)于一個(gè)對(duì)象使用。這時(shí),super在普通方法中,指向A.prototype,super.p()就相當(dāng)于A.prototype.p()。
這里需要注意,由于super指向父類(lèi)的原型對(duì)象,所以定義在父類(lèi)實(shí)例上的方法或?qū)傩?,是無(wú)法通過(guò)super調(diào)用的。

class A {
  constructor() {
    this.p = 2;
  }
}

class B extends A {
  get m() {
    return super.p;
  }
}

let b = new B();
b.m // undefined

上面代碼中,p是父類(lèi)A實(shí)例的屬性,super.p就引用不到它。
如果屬性定義在父類(lèi)的原型對(duì)象上,super就可以取到。

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3;
    console.log(super.x); // undefined
    console.log(this.x); // 3
  }
}

let b = new B();

上面代碼中,由于綁定子類(lèi)的this,所以如果通過(guò)super對(duì)某個(gè)屬性賦值,這時(shí)super就是this,賦值的屬性會(huì)變成子類(lèi)實(shí)例的屬性。super.x賦值為3,這時(shí)等同于對(duì)this.x賦值為3。而當(dāng)讀取super.x的時(shí)候,讀的是A.prototype.x,所以返回undefined。

如果super作為對(duì)象,用在靜態(tài)方法之中,這時(shí)super將指向父類(lèi),而不是父類(lèi)的原型對(duì)象。

class Parent {
  static myMethod(msg) {
    console.log('static', msg);
  }

  myMethod(msg) {
    console.log('instance', msg);
  }
}

class Child extends Parent {
  static myMethod(msg) {
    super.myMethod(msg);
  }

  myMethod(msg) {
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2

上面代碼中,super在靜態(tài)方法之中指向父類(lèi),在普通方法之中指向父類(lèi)的原型對(duì)象。

2. 字符串的擴(kuò)展

2.1 for of

for(let k of 'abc'){
  console.log(k); // a b c
}

2.2 includes(),startsWith(),endsWith()

傳統(tǒng)上,JS之后indexof,可以用來(lái)確定一個(gè)字符串是否在另一個(gè)字符串中。ES6又提供了三種方法。

includes():返回布爾值,表示是否找到了參數(shù)字符串。
startsWith():返回布爾值,表示參數(shù)字符串是否在源字符串的開(kāi)頭。
endsWith():返回布爾值,表示參數(shù)字符串是否在源字符串的結(jié)尾。

這三個(gè)方法都支持第二個(gè)參數(shù),表示開(kāi)始搜索的位置。

var s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

上面代碼表示,使用第二個(gè)參數(shù)n時(shí),endsWith的行為與其他兩個(gè)方法有所不同。它針對(duì)前n個(gè)字符,而其他兩個(gè)方法針對(duì)從第n個(gè)位置直到字符串結(jié)束。

最后編輯于
?著作權(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),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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