使用 JavaScript 中的实例更新原型

Updating a prototype using an instance in JavaScript

本文关键字:更新 原型 实例 JavaScript 使用      更新时间:2024-02-26

我有这个构造函数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"]

我希望两个 log 语句都打印["pepsi"],因为 person1person2 都指向原型上的同一个基本数组favorites,并且由于person2最终将其修改为 ["pepsi"],我希望两个输出都["pepsi"]。我错过了什么吗?

读取对象属性可能涉及搜索继承链。

读取 javascript 对象属性首先搜索对象的本地属性名称。如果未找到本地或"own"属性,则通过依次查看继承链中的每个原型对象来继续搜索,直到找到属性名称或检查继承链中的所有对象。如果找到该名称,则从找到该名称的对象获取其值。如果未找到,读取将返回 undefined 作为命名属性值。

始终写入对象属性* 在本地写入属性值

写入命名值属性

的值将创建或更新由要写入的对象持有的本地属性值。如果它以前是通过继承链继承的,它将停止被继承:读取返回优先的本地值。请注意,从中继承对象的继承属性值保持不变。

所以

person1.favorites = ["coke"]; 
person2.favorites = ["pepsi"];

在写入["coke"]之前创建一个新的本地favorites属性 person1,并在写入["pepsi"]之前创建一个新的本地favorites属性 person2

Person.prototype 继承的前一个favorites属性值 [] 在进程中变为隐藏状态。


*不包括 ES5 中定义的定位器和设置器

Setter 和 getter 函数将属性名称与对象相关联。以这种方式设置的属性名称缺少内部 [[value]] 槽,但可作为 getter 和 setter 函数继承。特别是,如果不存在同名的本地属性,则写入对象确实会在继承链中搜索资源库

尽管调用 getter 和 setter 时读取或写入的对象作为其this值,但它们存储和检索值的位置和方式不能泛化,因为它取决于它们的写入方式。

这会将一个新数组分配给 person1 的收藏夹属性。它不会修改其原型上的现有原型:

person1.favorites = ["coke"];

您可以使用 push 追加到数组,也可以通过将数组长度设置为 0 来清空数组。举个例子:

person1.favorites.push( 'coke' );
person2.favorites.length = 0;        
person2.favorites.push( 'coke' );
当你将

["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"]