字面量创建原型对象的注意事项

Author Avatar
cowboy 8月 26, 2017
  • 在其它设备中阅读本文章

constructor指向

mdn上对于constructor的定义

返回一个指向创建了该对象原型的函数引用。需要注意的是,该属性的值是那个函数本身,而不是一个包含函数名称的字符串

我们知道无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性是一个指向prototype属性所在函数的指针。

因此当创建一个函数后,constructor指向这个函数
Alt text

但是在原型对象上添加属性时,如果每添加属性和方法就要敲一遍Person.protype就有些麻烦。因此可以用一个包含所有属性和方法的对象字面量来重写整个原型对象,但是这样就会有一个问题,constructor不再指向Person

function Person() {
}

Person.prototype = {
  name : "Nicholas",
  age : 29,
  job : "Software Engineer",
  sayName : function () {
    alert(this.name);
  } 
};
var friend = new person();

console.log(friend.constructor == Person); //false
console.log(friend.constructor == Object); //true

这是因为当我们使用对象字面量重写原型对象时,实际上完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数),我们可以手动设置constructor : Person。但是以这种方式重设constructor属性会导致它的[[Enumerable]]特性设置为true,默认情况下,原生的constructor属性时不可枚举的。可以再通过Object.defineProperty重设构造函数。

原型的动态性

我们可以在创建实例后,再在原型对象上添加属性方法

var friend = new Person();

Person.prototype.sayHi = function() {
  console.log("hi");
};

friend.sayHi();  //"hi"

尽管可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反映出来,但如果使用对象字面量重写整个原型对象,情况就不一样了。
Alt text
此时报错并没有找到friend的sayName方法,因为当我们使用对象字面量重写原型对象,实际上是创建了一个新的原型对象(通过Object构造函数),并将contructor手动指向Person,而实例中的[[Prototype]]指针仅指向原型,而不指向构造函数(即指向最初的原型)。而把原型修改为零一个对象就等于切断了构造函数与最初原型之间的联系。
关系如图所示
Alt text
因此最好是在创建实例之前修改原型