ES6——class類繼承(讀書筆記)

前言

  我一定是一個傻子,昨天這篇文章其實我已經寫好了一半了,但是我沒有保存

  這是學習ES6的過程,我沒有系統的看完阮大大的書。零零散散的,很多功能知道,但是沒有實際的用過

  看了幾遍,總是看前面幾章,所以這次我要立下flag 一定從頭到尾學一遍ES6(有點諷刺 現在好像都有ES9了)

  ES5與ES6 相差還是很大的

一、類

  ES5 沒有類這個說法,但是是可以實現類這樣功能的,那就是構造函數 

function Point (x,y){
  this.x = x
  this.y = y    
}

var a  = new Point(1,2)
console.log(a.x) //1

  然後我在mdn上找到一個例子 詳細的說了構造函數的原型 原型鏈

  

// 讓我們從一個自身擁有屬性a和b的函數裏創建一個對象o:
let f = function () {
   this.a = 1;
   this.b = 2;
}
/* 這麼寫也一樣
function f() {
  this.a = 1;
  this.b = 2;
}
*/
let o = new f(); // {a: 1, b: 2}

// 在f函數的原型上定義屬性
f.prototype.b = 3;
f.prototype.c = 4;

// 不要在 f 函數的原型上直接定義 f.prototype = {b:3,c:4};這樣會直接打破原型鏈
// o.[[Prototype]] 有屬性 b 和 c
//  (其實就是 o.__proto__ 或者 o.constructor.prototype)
// o.[[Prototype]].[[Prototype]] 是 Object.prototype.
// 最後o.[[Prototype]].[[Prototype]].[[Prototype]]是null
// 這就是原型鏈的末尾,即 null,
// 根據定義,null 就是沒有 [[Prototype]]。

// 綜上,整個原型鏈如下: 

// {a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null

console.log(o.a); // 1
// a是o的自身屬性嗎?是的,該屬性的值爲 1

console.log(o.b); // 2
// b是o的自身屬性嗎?是的,該屬性的值爲 2
// 原型上也有一個'b'屬性,但是它不會被訪問到。
// 這種情況被稱爲"屬性遮蔽 (property shadowing)"

console.log(o.c); // 4
// c是o的自身屬性嗎?不是,那看看它的原型上有沒有
// c是o.[[Prototype]]的屬性嗎?是的,該屬性的值爲 4

console.log(o.d); // undefined
// d 是 o 的自身屬性嗎?不是,那看看它的原型上有沒有
// d 是 o.[[Prototype]] 的屬性嗎?不是,那看看它的原型上有沒有
// o.[[Prototype]].[[Prototype]] 爲 null,停止搜索
// 找不到 d 屬性,返回 undefined

  看完這個例子,就大概知道原型 原型鏈 是怎樣一層一層的找的(又有靈感 寫一篇古風版的原型鏈了)

  然後ES6 是怎麼樣的呢

class Point{
        constructor(x,y){
            this.x = x;
            this.y = y;
      }
    toString(){
        return "("+this.x+","+this.y+")"
    }
}           

 上面代碼定義了一個“類”,可以看到裏面有一個constructor方法,這就是構造方法 

   而this關鍵字則代表實例對象。也就是說,ES5 的構造函數Point,對應 ES6 的Point類的構造方法。

 

 使用的時候,也是直接對類使用new命令,跟構造函數的用法完全一致。

class Bar {
  doStuff() {
    console.log('stuff');
  }
}

var b = new Bar();
b.doStuff() // "stuff"

 類的所有方法都定義在類的prototype屬性上面。(繼承) 在類的實例上面調用方法,其實就是調用原型上的方法。

class B {}
let b = new B();

b.constructor === B.prototype.constructor // true

  prototype對象的constructor屬性,直接指向“類”的本身,這與 ES5 的行爲是一致的。

 Point.prototype.constructor === Point // true

toString方法是Point類內部定義的方法,它是不可枚舉的。這一點與 ES5 的行爲不一致。

constructor方法

  constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,如果沒有顯式定義,一個空的constructor方法會被默認添加。

class Point {
}

// 等同於
class Point {
  constructor() {}
}
  1. 類必須使用new調用,否則會報錯。這是它跟普通構造函數的一個主要區別,後者不用new也可以執行
  2. constructor函數返回一個全新的對象,結果導致實例對象不是Foo類的實例。
  3. class Foo {
      constructor() {
        return Object.create(null);
      }
    }
    
    new Foo() instanceof Foo
    // false

     

  4. 類不存在變量提升(hoist),這一點與 ES5 完全不同。
  5. {
      let Foo = class {};
      class Bar extends Foo {
      }
    }

    上面的代碼不會報錯,因爲Bar繼承Foo的時候,Foo已經有定義了。但是,如果存在class的提升,上面代碼就會報錯,因爲class會被提升到代碼頭部,而let命令是不提升的,所以導致Bar繼承Foo的時候,Foo還沒有定義。

  6. 由於本質上,ES6 的類只是 ES5 的構造函數的一層包裝,所以函數的許多特性都被Class繼承,包括name屬性  name屬性總是返回緊跟在class關鍵字後面的類名。
    class Point {}
    Point.name // "Point"
  7. 如果某個方法之前加上星號(*),就表示該方法是一個 Generator 函數。
  8. class Foo {
      constructor(...args) {
        this.args = args;
      }
      * [Symbol.iterator]() {
        for (let arg of this.args) {
          yield arg;
        }
      }
    }
    
    for (let x of new Foo('hello', 'world')) {
      console.log(x);
    }
    // hello
    // world

    上面代碼中,Foo類的Symbol.iterator方法前有一個星號,表示該方法是一個 Generator 函數。Symbol.iterator方法返回一個Foo類的默認遍歷器,for...of循環會自動調用這個遍歷器。

  9. 在構造方法中綁定this,這樣就不會找不到print方法了。 不然就會this會指向該方法運行時所在的環境(由於 class 內部是嚴格模式,所以 this 實際指向的是undefined),從而導致找不到print方法而報錯。
  10. 另一種解決方法是使用箭頭函數。
  11. class Obj {
      constructor() {
        this.getThis = () => this;
      }
    }
    
    const myObj = new Obj();
    myObj.getThis() === myObj // true

     

二、靜態方法

  類相當於實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱爲“靜態方法”。

  

class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

 

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章