JavaScript系列—class(靜態方法和屬性、實例屬性、私有方法和屬性)

1.類的簡介

JavaScript 語言中,生成實例對象的傳統方法是通過構造函數。下面是一個例子。

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

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

上面的代碼用 ES6 的class改寫,就是下面這樣。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

 

  • 上面的constructor方法,稱爲構造方法,
  •  this代表實例對象
  • ES5 的構造函數Point,對應 ES6 的Point類的構造方法。
  • 類的所有方法都定義在類的prototype屬性上面。
  • 類必須使用new調用,否則會報錯。這是它跟普通構造函數的一個主要區別,後者不用new也可以執行。

類的所有方法都定義在類的prototype屬性上面。

class Point {
  constructor() {
    // ...
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同於

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

在類的實例上面調用方法,其實就是調用原型上的方法。bB類的實例,它的constructor方法就是B類原型的constructor方法。

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

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

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

//定義類
class Point {

  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }

}

var point = new Point(2, 3);

point.toString() // (2, 3)

point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true

類的所有實例共享一個原型對象。p1p2都是Point的實例,它們的原型都是Point.prototype,所以__proto__屬性是相等的。

var p1 = new Point(2,3);
var p2 = new Point(3,2);

p1.__proto__ === p2.__proto__
//true

類的方法內部如果含有this,它默認指向類的實例。

現在回憶一下原型鏈

2.靜態方法(類的方法。加static)

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

Foo類的classMethod方法前有static關鍵字,表明該方法是一個靜態方法,可以直接在Foo類上調用(Foo.classMethod()),而不是在Foo類的實例上調用。如果在實例上調用靜態方法,會拋出一個錯誤,表示不存在該方法。

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

Foo.classMethod() // 'hello'

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

注意,如果靜態方法包含this關鍵字,這個this指的是類,而不是實例。

靜態方法bar調用了this.baz,這裏的this指的是Foo類,而不是Foo的實例,等同於調用Foo.baz

class Foo {
  static bar() {
    this.baz();
  }
  static baz() {
    console.log('hello');
  }
  baz() {
    console.log('world');
  }
}

Foo.bar() // hello

3.靜態屬性(類的屬性,加static)

靜態屬性指的是 Class 本身的屬性,即Class.propName,而不是定義在實例對象(this)上的屬性。

因爲 ES6 明確規定,Class 內部只有靜態方法,沒有靜態屬性。

現在有一個提案提供了類的靜態屬性,寫法是在實例屬性法的前面,加上static關鍵字。

class MyClass {
  static myStaticProp = 42;

  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}

4.實例屬性

實例屬性除了定義在constructor()方法裏面的this上面,也可以定義在類的最頂層。

class IncreasingCounter {
  constructor() {
    this._count = 0;
  }
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}

上面代碼中,實例屬性this._count定義在constructor()方法裏面。另一種寫法是,這個屬性也可以定義在類的最頂層,其他都不變。

class IncreasingCounter {
  _count = 0;
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}

5.私有屬性和私有方法

私有方法和私有屬性,是隻能在類的內部訪問的方法和屬性,外部不能訪問。

class加了私有屬性。方法是在屬性名之前,使用#表示。

class IncreasingCounter {
  #count = 0;
  get value() {
    console.log('Getting the current value!');
    return this.#count;
  }
  increment() {
    this.#count++;
  }
}

上面代碼中,#count就是私有屬性,只能在類的內部使用(this.#count)。如果在類的外部使用,就會報錯。

這種寫法不僅可以寫私有屬性,還可以用來寫私有方法。

class Foo {
  #a;
  #b;
  constructor(a, b) {
    this.#a = a;
    this.#b = b;
  }
  #sum() {
    return #a + #b;
  }
  printSum() {
    console.log(this.#sum());
  }
}

上面代碼中,#sum()就是一個私有方法。

 

總結一下

類的所有方法都定義在類的prototype屬性上面。

靜態方法(類的方法。加static)

靜態屬性(類的屬性,加static)

實例屬性

 

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