我写了如下两段代码:
function Person(){}
var p1 = new Person();
Person.prototype = {
constructor: Person,
name: "cxc",
age: 20,
sayName: function(){
console.log(this.name);
}
};
p1.sayName();
这一段的运行结果是:Uncaught TypeError: undefined is not a function
然后我又把它改写为下面的代码:
function Person(){}
Person.prototype = {
constructor: Person,
name: "cxc",
age: 20,
sayName: function(){
console.log(this.name);
}
};
var p1 = new Person();
p1.sayName();
运行结果却是没问题的,为什么会这样呢。
原型不是具有动态性吗,在它上面所做的任何修改不是都会反映到实例上吗。所以我就有些想不明白了,烦劳哪位大神能给解释一下。在此先行谢过了。
其实问题的核心只有一点
就算你重写构造函数的原型
后,实例
的指针仍然指向其当初构造函数的原型
你进行重写后
你新原型的constructor
属性指向Person
,但是实例p1
指向的原型仍然为Object.prototype
即p1
的[[prototype]]
隐式属性仍然为Object.prototype
,故不会存在相应的方法sayName()
你重写了构造函数的原型不等于实例也会和构造函数一起改变相应的指针
要知道关键字new
才是进行一系列原型传递的信号,你有兴趣可以看看
让我来给你解释一下吧。
看看下面这段代码
function Person(){}
var proto1 = Person.prototype;
var p1 = new Person();
Person.prototype = {
constructor: Person,
name: "cxc",
age: 20,
sayName: function(){
console.log(this.name);
}
};
console.log(Person.prototype.isPrototypeOf(p1)); //输出false
console.log(proto1.isPrototypeOf(p1)); //输出true
MDN Reference: Object.prototype.isPrototypeOf()
The isPrototypeOf() method tests for an object in another object's prototype chain.
意思就是:Object.isPrototypeOf(obj)
可以用来检测该原型是否处于obj
对象的原型链上。
在上面这段代码中,首先我将一开始Person.prototype
的引用指向proto1
。
最后我重新检验发现,Person.prototype
已经不是p1的原型了,而proto1
还是p1的原型。
其实罪魁祸首就是Person.prototype = {...}
这句话,因为它声明了一个新的对象,让Person.prototype
指向它。
要实现题主所需要的动态增加属性的功能可以这么写:
function Person(){}
var p1 = new Person();
Person.prototype.name = 'hi';
Person.prototype.sayName = function(){
console.log(this.name);
}
p1.sayName();
这样做就不是重新声明一个原型对象,而是对原来的原型对象进行扩展。
你先要理解你所说的“修改”指的是什么?对于你第一个例子中希望达到的效果正确的写法应该是:
function Person(){}
var p1 = new Person();
Person.prototype.name = 'cxc';
Person.prototype.sayName = function(){
console.log(this.name);
};
p1.sayName();
而题主所做的操作是:
Person.prototype = {
constructor: Person,
name: "cxc",
age: 20,
sayName: function(){
console.log(this.name);
}
};
这就相当于对 Person
的原型对象进行重新赋值,毫无疑问这是一种引用赋值,所以现在 Person
的原型对象已经指向了另外一片内存空间,而你之前建立的实例 p1
仍然指向的是原来的内存空间,所以肯定达不到题主想要的效果了。
对于原型对象 prototype
和 原型 __proto__
的理解,强烈推荐 @nightire 前辈的好文:
《理解 JavaScript(四)》
prototype才没有楼主认为的“动态”功能呢。
不然楼主的反例该如何解释呢,对吧。
你的空函数创建后,创建了一个原型对象P
,Person.prototype
会指向P
。
原型对象P
中,有constructor
属性,指向其构造函数Person
。
还有一个不可枚举的内部属性[[prototype]]
,chrome和firefox下可以用__proto__
属性来获取,该指针指向Object
对象的原型对象。
此时,原型对象P
中,并没有sayName
方法,所以,var p1 = new Person();
,p1
此时也不会拥有sayName
方法。