实例属性 vs 原型属性

4
在下面的代码中,
function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

Person.prototype.planet = "Earth";

p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);

如果使用构造函数Person创建多个实例p1p2,那么如何理解属性planet和属性age之间的区别?在构造函数Person中添加属性this.planet会有什么不同的影响? 注:了解prototype属性

1
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty - Arun P Johny
https://jsfiddle.net/arunpjohny/8k5nmmqc/1/ - Arun P Johny
1
对于静态方法,您也可以使用Person.planet这样的语法 - 这样您就可以访问静态方法而无需创建新实例。就像Math.max()静态方法一样 - 您不需要新的Math来访问.max() - Krzysztof Safjanowski
3个回答

4

考虑这样一种情况,未来我们可能会更改原型属性,而此属性是所有实例共享的。

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

Person.prototype.planet = "Earth";

p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);

console.log(p1.planet) // Earth

Person.prototype.planet = "Mars"

console.log(p1.planet) // Mars
console.log(p1.planet === p2.planet) // true

在原型上更改一个属性会导致所有实例中的该属性都发生变化。


3
这实际上是内存使用量的问题。下面是我创建的一些图像,描述了每个问题。
在下面的图像中,每个人的实例都链接到同一个原型对象。如果创建多个指向相同对象的实例,则可以节省内存。但是,如果您将“Earth”更改为“Mars”,则每个实例都会发生相同的更改。

enter image description here


在下面的图片中,每个实例都将指向一个完全不同的属性,该属性专门与该实例相关联。如果您认为特定行星可以更改名称,则应执行此操作。否则,请使用原型,因为这将使用更多资源。

enter image description here


3

原型属性将成为从所谓的原型创建的任何对象的一部分,包括原型链。

实例属性将成为整个实例的一部分,在您的情况下,它将成为任何实例的一部分,因为您在构造函数中添加它:

function A() {
   this.x = 11;
}

var instance = new A();
instance.x = 11;

以上两种情况都是将属性添加到自身对象而不是原型中。

此外,向原型添加属性会产生副作用:

function A() {}
A.prototype.x = 11;

function B() {}
B.prototype = Object.create(A.prototype);

var instanceA = new A();
var instanceB = new B();

A.prototype.x = 12;

// Both "x" will hold 12
alert(instanceA.x);
alert(instanceB.x);

了解有关MDN上原型链的更多信息

关于一些OP的评论

因此,在Java术语中,年龄是实例成员,而星球是静态成员。要定义静态成员,我们使用原型属性,我是正确的吗? -

这是一个错误的说法。

原型属性不是静态的,因为原型是常规对象。只是JavaScript使用原型链来实现继承,并依赖于一个名为prototype的标准属性。

在JavaScript中没有静态成员。当您访问任何属性时,JavaScript运行时将通过原型链查找它:

function A() {};
A.prototype.x = 11;

function B() {};
B.prototype = Object.create(A.prototype);

function C() {};
C.prototype = Object.create(B.prototype);

var instanceC = new C();
var x = instanceC.x;
// Once you request a property "x", the runtime will do the following process:
// 1) Is "x" in the own object? No, then 2)
// 2) Is "x" in current object's prototype? No, then 3)
// 3) Is "x" in the parent prototype? No, then 4)
// 4) And so on, until it reaches the top-level prototype, and if this has no
//    "x" property, then runtime will return "undefined"

我几乎无法理解这个语句:原型属性将成为从所谓的原型创建的任何对象的一部分,包括原型链。而且剩下的答案是重复的。目前我只知道通过构造函数创建对象。 - overexchange
@overexchange 这就是为什么我给你提供了MDN的链接,让你更多地了解原型链。顺便说一下,我根据你在问题中添加的一些评论提供了更新,并总结了原型链... - Matías Fidemraizer
我开始使用MDN学习Javascript。我强烈认为,MDN是了解原型的最差资源。 - overexchange
如果你还在学习阶段,怎么能够做出这样大胆的声明呢?这并不是最糟糕的资源,而且它也很有效。只是因为你还在学习JS,需要熟悉很多概念。 - Matías Fidemraizer
@overexchange 你确定这是最糟糕的资源吗?它是一个完美的总结! - Matías Fidemraizer
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接