标签:color 语句 构造 ble 程序 自己 定义 name 原因
首先,对constructor属性有以下几点了解:
对于一些公共的属性和方法,我么可以通过原型对象,把它们定义在构造函数的外部,使构造函数成为一个空函数:
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了==
var friend = new Person();
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
我们可以看到,instanceof表示friend仍然是Person的实例,但是constructor却表明friend的构造函数(父类)不再是Person了,constructor与instanceof的结果不一致这就造成了instanceof的失真。那么对象的constructor到底指向谁呢?
var friend = new Person();
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true
==没错,constructor 属性指向了Object== ,也就是说通过这种对象字面量方式改变原型对象之后,原型/实例对象的constructor属性指向了Object,它们的构造函数(父类)变成了Object。
这是为什么呢?
每创建一个函数就会同时创建它的prototype对象,这个对象也会自动获得constructor属性。而通过对象字面量形式改写原型对象,本质上算是完全重写了默认的原型对象,也即是说我们写了一个新的对象,它是个新对象,因此它的constructor属性也就变成了新对象的constructor属性,指向Object构造函数,不再指向Person函数了。
因此,通过constructor操作符还能返回正确的结果,但是通过instanceof不能准确确定对象的类型
var friend = new Person();
alert(friend instanceof Object); //true
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
alert(friend.constructor == Object); //true
通过改写原型对象的方式改变属性和方法,不仅使instanceof操作符失真,如果实例对象定义在修改之前,还会导致实例对象无法访问新加的属性和方法:
var friend = new Person();
Person.prototype.sayHi = function(){
alert("hi");
};
friend.sayHi(); //"hi"(没有问题!)
这段代码显示,通过使用Person.prototype.……
的方式逐个向原型对象上添加的属性,可以被实例对象成果访问;但是,通过改写原型对象的形式添加新属性和方法并非如此:
function Person(){}
var friend = new Person();
Person.prototype = {
constructor: Person,
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function () {
alert(this.name);
}
};
friend.sayName(); //error
显然,通过改写原型对象的方式,实例对象不能访问新添加的属性和方法。导致这一现象的根本原因和instanceof
操作符失真的原因一致:constructor
的指向发生了变化
请参考以下图示:
简单来讲,调用构造函数时,会为实例添加一个指向最初原型的_proto_
指针,重写原型对象成为一个新对象,就等于:
_proto_
属性指向的仍然是原有的原型对象。1.常规写法,但是比较啰嗦,每次都要重复写Person.prototype
function Person(){}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
//...
2.使用对象字面量方式改写原型对象,但是这样会改变constructor的指向
function Person(){}
Person.prototype = {
name : "Nicholas",
age : 29,
//...
};
3.如果 constructor 的值真的很重要,可以像下面这样特意将它设置回适当的值。
function Person(){}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
//...
};
在代码中特意包含一个 constructor属性,并将它的值设置为Person,从而确保了通过该属性能够访问到适当的值
4.但是以上述形式重新指定constructor属性,会使得constructor属性的[[Enumerable]]特性被设置为 true,也就是变成了可枚举类型的属性,但是原生的constructor属性是不可枚举类型,[[Enumerable]]特性为 false,因此可使用下列语句修改它的[[Enumerable]]属性,仍符合原生的设定:
function Person(){}
Person.prototype = {
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function () {
alert(this.name);
}
};
//重设构造函数,只适用于 ECMAScript 5 兼容的浏览器
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
});
标签:color 语句 构造 ble 程序 自己 定义 name 原因
原文地址:https://www.cnblogs.com/ch206265/p/10629519.html