1. 程式人生 > >ES6中class的getter和setter在繼承中踩坑

ES6中class的getter和setter在繼承中踩坑

在 Class 內部可以使用get和set關鍵字, 對某個屬性設定存值函式和取值函式, 攔截該屬性的存取行為。
在 Class 內部的get、set用法,看起來比較舒服,而且可以寫同名函數了。

class MyClass {
	constructor() {}
	get prop() {
		return 'getter';
	}
	set prop(value) {
		console.log('setter: ' + value);
	}
}
let inst = new MyClass();
inst.prop = 123; // setter: 123
inst.prop  // setter:123

但是在繼承中:

class Parents {
constructor(props) {
}
get myTest() {
    return this._test;
}
}

class Child extends Parents {
constructor(props) {
    super(props);// ES6 要求,子類的建構函式必須執行一次 super 函式,否則會報錯。
}
set myTest(val) {
    this._test = val;
}
}
let a = new Child();
a.myTest = 123;
console.log(a.myTest);

按正常的面向物件邏輯,子類裡通過setter賦值了this._test,之後,自己應該可以通過getter拿回來。
但實際上並未如此,得到的結果是undefined。

換個順序,如果子類裡是getter而父類裡是setter,得到的結果也一樣。
而如果把getter或setter同時都放在父類,或者同時都放在子類時。我們是可以得到預期的值的。

class Base {
  constructor(props) {
  }
  get myTest() {
    return this._test;
  }
  set myTest(val) {
    this._test = val;
  }
}

class Child extends Base {
  constructor(props) {
    super(props);
  }
}

簡單地說,就是要getter與setter都在同一級的時候才會生效。
這邊探索了一下原因,大概原因是這樣的:
ES6的Class和其它面嚮物件語言並不相同。它僅僅是一個語法糖,其實上還是基於原型鏈的。
在第一個例子中,我們給Child加了一個setter方法後,實際上它是會產生一個偽屬性的。

Child.myTest = {
  set: function(val) {
    this._test = val;
  }
};

它是ES5的setter,但它僅有set,沒有get。
這個時候去訪問Child的getter時,實際上訪問到了Child.myTest.get。得到的是undefined。
而第二例子裡面,Child並沒有創建出myTest這個偽屬性。所以訪問Child的getter時,它會去原型鏈上找,最後找到了Base上的myTest