我有这个构造函数Person
:
function Person(name) {
this.name = name;
}
我在其原型上添加了一个数组favorites
,以便Person
的所有实例都可以指向同一个数组:
Person.prototype.favorites = [];
var person1 = new Person("KimK");
var person2 = new Person("KhloeK");
person1.favorites = ["coke"];
person2.favorites = ["pepsi"];
console.log(person1.favorites); //["coke"]
console.log(person2.favorites); //["pepsi"]
我希望两个日志语句都打印["pepsi"]
,因为person1
和person2
都指向原型上相同的基本数组favorites
,因为{{1}最后将其修改为person2
,我预计两个输出都为["pepsi"]
。我错过了什么吗?
答案 0 :(得分:3)
读取对象属性可能涉及搜索继承链。
读取javascript对象属性首先搜索对象的本地属性名称。如果未找到本地或"own" property,则继续搜索继续依次查看继承链中的每个原型对象,直到找到属性名称或检查继承链中的所有对象。如果找到该名称,则从其找到的对象获取其值。如果未找到,则读取返回undefined
作为命名属性值。
始终编写对象属性*在本地写入属性值
写入命名值属性的值可创建或更新要写入的对象所持有的本地属性值。如果先前通过继承链继承它,它将停止继承:read优先返回本地值。请注意,从中继承的对象的继承属性值保持不变。
<强>因此强>
person1.favorites = ["coke"];
person2.favorites = ["pepsi"];
在编写favorites
之前,创建person1
的新本地["coke"]
属性,并在写favorites
之前创建person2
的新本地["pepsi"]
属性对它来说。
从favorites
,[]继承的先前Person.prototype
属性值在流程中隐藏。
Setter和getter函数将属性名称与对象相关联。以这种方式设置的属性名称缺少内部[[value]]槽,但可以作为getter和setter函数继承。特别是,如果同名的本地属性不存在,则写入对象会在继承链中搜索 setter 。
虽然调用getter和setter时对象被读取或写为this
值,但是它们存储和检索值的位置和方式不能一概而论,因为它取决于它们的编写方式。
答案 1 :(得分:2)
这会为person1的收藏夹属性分配一个新数组。它不会修改原型上的现有版本:
person1.favorites = ["coke"];
您可以使用push追加到数组,并且可以通过将其长度设置为0来清空数组。例如:
person1.favorites.push( 'coke' );
person2.favorites.length = 0;
person2.favorites.push( 'coke' );
答案 2 :(得分:1)
当您将["coke"]
分配给person1.favorites
时,您正在修改person1
的属性,而不是Person
原型。你可以通过console.log(Person.prototype.favorites)
轻松检查它 - 它仍然包含空数组。如果要更改所有实例的值,唯一的方法是直接修改原型,即:
Person.prototype.favorites = ["coke"];
但是,如果您未将favorites
属性设置为Person
个实例,则可以通过修改person1.favorites
来修改原型。例如:
function Person(name) {
this.name = name;
}
Person.prototype.favorites = [];
var person1 = new Person("KimK");
person1.favorites.push("coke", "pepsi")
console.log(person1.favorites); // ["coke", "pepsi"]
var person2 = new Person("KhloeK");
console.log(person2.favorites); // ["coke", "pepsi"]
console.log(Person.prototype.favorites); // ["coke", "pepsi"]