昨天有说明到函式与建构式的原型,及指定建构式函式原型为另一个建构式函式,但其实这会造成复写constructor的问题。

 

复写constructor的问题(vmwork)

我们昨天有提到「建构式函式可以透过.constructor来存取建立物件的函式以此来作类型检查。」,但是这个例子却会导致trickyMan的建构式的原型被复写,无法去判断。

 

function Person(){};

Person.prototype.say =“Hi”;

 

function trickyMan(){};

trickyMan.prototype = new Person();

 

var Jason = new trickyMan();

trickyMan.constructor === trickyMan;//false

所以如果在Jason物件上呼叫.constructor,会无法找到直到在Person上找到参照Person函式的constructor。

但是,这事实上是错误的,如果我问是哪个函式建立了Jason物件,会得到Person这可能会产生一些Bug。

 

幸好在JS中,物件的每个属性都有一个属性描述子(property desciptor),可以够过它设定以下键值:

 

configurable设定

true -表属性描述子可被修改及删除

false -上述两个动作都将被禁止

enumerable列举

true -属性能在物件的for-in循环操作中出现

value

设定属性的键值

writable写入

true -表可以透过设值叙述来修改属性值

get

定义取值(getter)函式,可用来取得属性值。无法与value及writable一起设定

set

定义设值(setter)函式,可以用来对属性指派一个值。无法与value及writable一起设定

先来个简单的例子:

 

Jason.age = 29;

age这个属性会是可设定、可列举并且可写入的,它的值被设为29,get和set函式则会是undefined。

 

如果要对上述设定值做更动的话,可以用Object.defineProperty:

 

var Jason = {};

Jason.say =“R~”;

 

Object.defineProperty(Jason,“age”,{

configurable:false,

enumerable:false,

value:29,

writable:true

});

console.log(“age”in Jason);

 

for(let key in Jason){

console.log(key);

}

好,现在我知道有这东西了,但这跟一开始说的constructor有关系吗?

 

当然有!我们试着用trickyMan扩展(extend)Person时(也可以说是让trickyMan成为Person的子类别),就失去原本保存在constructor属性上的trickyMan原型。

 

我们可以用Object.defineProperty在新的trickyMan.prototype上定义一个新的constructor属性。

 

function Person(){};

Person.prototype.say =“Hi”;

 

function trickyMan(){};

trickyMan.prototype = new Person();

 

Object.defineProperty(trickyMan,“constructor”,{

enumerable:false,

value:trickyMan,

writable:true

});

 

var Jason = new trickyMan();

trickyMan.constructor === trickyMan;//true

那么,今天就到这边,一样如果有错误及来源未附上也欢迎留言指正,那么我们明天见(leafor)。