function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); };
前面例子中每添加一个属性和方法就要敲一遍 Person.prototype。为减少不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的对象字面量来重写整个原型对象,如下面的例子所示。
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
我们将 Person.prototype 设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但有一个例外:constructor 属性不再指向 Person 了。
本质上完全重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),不再指向 Person 函数。此时,尽管 instanceof操作符还能返回正确的结果,但通过 constructor 已经无法确定对象的类型了,如下所示。
var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
constructor 属性则等于 Object 而不等于 Person 了。如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值:
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
以上代码特意包含了一个 constructor 属性,并将它的值设置为 Person,从而确保了通过该属性能够访问到适当的值。
注意:以这种方式重设 constructor 属性会导致它的[[Enumerable]]->可枚举特性被设置为 true。默认情况下,原生的 constructor 属性是不可枚举的,可以试一试 Object.defineProperty():
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job : "Software Engineer", sayName : function () { alert(this.name); } };
//重设构造函数,让其重新指向Person;只适用于 ECMAScript 5 兼容的浏览器 Object.defineProperty(Person.prototype, "constructor", { enumerable: false, //是否可枚举,false不可枚举 value: Person });
这回,cunstructor的指向指回了构造函数,cunstructor属性也变成了不可枚举的属性了,为了验证,如下所示:
var keys = Object.keys(Person.prototype); alert(keys); //"name,age,job,sayName"
此时,所有可枚举属性中不包含cunstructor了。