为什么要在 JavaScript 中为实例变量的原型声明属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16751230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why declare properties on the prototype for instance variables in JavaScript
提问by DaveM
I'm trying to get my head around this black art called JavaScript - and, I must admit, pretty excited about it. I've been looking at code examples, mainly from "easeljs" since that is what I will be using mainly. And I'm a bit confused..
我正在尝试了解这种称为 JavaScript 的黑色艺术——而且,我必须承认,我对它感到非常兴奋。我一直在查看代码示例,主要来自“easeljs”,因为这是我将主要使用的。而且我有点困惑..
I (think I) understand the difference between using the prototype
for functions or properties that are class
variables and using this.someProp
for 'instance' variables (Yes, I understand that there are no classes in JavaScript.)
我(认为我)理解使用作为变量的prototype
函数或属性class
与使用this.someProp
“实例”变量之间的区别(是的,我知道 JavaScript 中没有类。)
The code I have looked at, and am using as templates for my own code, declare
prototype
variables and then refers to them with this i.e.
我看过的代码,并用作我自己的代码、declare
prototype
变量的模板,然后用这个 ie 引用它们
In the constructor:
在构造函数中:
this.name = name;
Then a declaration:
然后声明:
Object.prototype.name;
And later,
然后,
this.name = "Freddy";
This is within functions called with 'new' so in this case, as I understand it, this
refers to the current object. What puzzles me is what the prototype declaration is doing and why do we use it for instance variables?
这是在用“new”调用的函数中,所以在这种情况下,据我所知,this
指的是当前对象。让我感到困惑的是原型声明在做什么,为什么我们将它用于实例变量?
Clarification: In the following code, I don't see what the prototype declaration of radius is achieving:
澄清:在下面的代码中,我没有看到radius的原型声明实现了什么:
(function(){
// constructor
function MyCircle(radius){
this.radius = radius;
}
MyCircle.prototype.radius;
this.area = function(){
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle;
}());
回答by Stuart Wakefield
The value on a prototype has a key behaviour that is different from a property set directly on the instance. Try this:
原型上的值具有与直接在实例上设置的属性不同的关键行为。试试这个:
// Create a constructor
function A() {}
// Add a prototype property
A.prototype.name = "Freddy";
// Create two object instances from
// the constructor
var a = new A();
var b = new A();
// Both instances have the property
// that we created on the prototype
console.log(a.name); // Freddy
console.log(b.name); // Freddy
// Now change the property on the
// prototype
A.prototype.name = "George";
// Both instances inherit the change.
// Really they are just reading the
// same property from the prototype
// rather than their own property
console.log(a.name); // George
console.log(b.name); // George
This would not possible without prototypical inheritance.
如果没有原型继承,这是不可能的。
You can test whether the property is the instances property or the prototype property using the hasOwnProperty
method.
您可以使用该hasOwnProperty
方法测试该属性是实例属性还是原型属性。
console.log(a.hasOwnProperty("name")); // false
An instance can override the prototype
value.
实例可以覆盖该prototype
值。
b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris
And return to the prototype
value.
并返回prototype
值。
delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George
This is a powerful part of prototypical inheritance.
这是原型继承的一个强大部分。
In the other pattern:
在另一种模式中:
function A() {
this.name = "George";
}
The this.name
variable is declared again with every new instance.
this.name
每个新实例都会再次声明该变量。
It makes some sense to have methods as functions declared on the prototype. Rather than the function definition being re-declared on every instance, all instances can share a single function.
将方法作为在原型上声明的函数是有意义的。所有实例都可以共享一个函数,而不是在每个实例上重新声明函数定义。
In terms of variables, rather than functions, the prototype can possibly be used for default values in the case that an instance does not set its own value.
就变量而不是函数而言,原型可能用于在实例未设置自己的值的情况下的默认值。
回答by Alnitak
A value stored on the prototype provides a defaultvalue for that property.
存储在原型上的值为该属性提供了默认值。
If you subsequently write a value to that property, the instancewill acquire that new value, hiding the value that's on the prototype, which will be left intact.
如果您随后向该属性写入一个值,该实例将获取该新值,隐藏原型上的值,该值将保持不变。
In the context of the code you've now added to the question:
在您现在添加到问题的代码上下文中:
MyCircle.prototype.radius;
does absolutely nothing. It's a no-op - it attempts to readthat property and then discards the result.
什么都不做。这是一个空操作 - 它尝试读取该属性,然后丢弃结果。
回答by Michael R
Yeah, I agree the prototype can be used for default values of properties (variables). The constructor function doesn't need to declare a property; it may be done conditionally.
是的,我同意原型可用于属性(变量)的默认值。构造函数不需要声明属性;它可以有条件地完成。
function Person( name, age ) {
this.name = name;
if ( age ) {
this.age = age;
}
}
Person.prototype.sayHello = function() {
console.log( 'My name is ' + this.name + '.' );
};
Person.prototype.sayAge = function() {
if ( this.age ) {
console.log( 'I am ' + this.age + ' yrs old!' );
} else {
console.log( 'I do not know my age!' );
}
};
Person.prototype.age = 0.7;
//-----------
var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age ); // 0.7
person.sayAge(); // I am 0.7 yrs old!
See how Lucy's age
is conditionally declared and initialized.
看看 Lucy'sage
是如何有条件地声明和初始化的。
回答by linasmnew
Other answers have already explained the difference between prototype vs instance properties.
其他答案已经解释了原型与实例属性之间的区别。
But just to add to the answer, let's break down your code snippet:
但只是为了补充答案,让我们分解您的代码片段:
(function(){ // <------- 1
// constructor
function MyCircle(radius){ // <------- 2
this.radius = radius; // <------- 2.1
}
MyCircle.prototype.radius; // <------- 3
this.area = function(){ // <------- 4
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle; // <------- 5
}());
- Creating an
IIFE
which acts as a scope container for the inner code - Declaring a function called
MyCircle
using a constructor pattern (but observe that it never gets "constructed" so should probably get rid of the capital letter since it's misleading)- when invoked creates a
radius
instance property on the invoked object
- when invoked creates a
- Attempting to access a
radius
property onMyCircle
function'sprototype
which doesn't exist so evaluates toundefined
- Creating an
area
instance property on the global window object and assigning it a function expression - Creating a
MyCircle
instance property on awindow
object and assigning to it theMyCircle
function
- 创建一个
IIFE
充当内部代码的作用域容器 - 声明一个
MyCircle
使用构造函数模式调用的函数(但请注意它永远不会被“构造”,所以应该去掉大写字母,因为它具有误导性)- 当被调用时
radius
在被调用的对象上创建一个实例属性
- 当被调用时
- 尝试访问不存在的函数的
radius
属性,因此评估为MyCircle
prototype
undefined
area
在全局窗口对象上创建实例属性并为其分配函数表达式MyCircle
在window
对象上创建实例属性并为其分配MyCircle
函数
Summary:It seems like it's creating an area
and MyCircle
properties on the global window
object, and when MyCircle
is invoked it creates an additional radius
property.
总结:它似乎是在全局对象上创建一个area
andMyCircle
属性window
,当MyCircle
被调用时它会创建一个附加radius
属性。
Usage:MyCircle should be invoked before area since area relies on MyCircle initialising the radius:
用法:MyCircle 应该在 area 之前调用,因为 area 依赖于 MyCircle 初始化半径:
window.MyCircle(10);
window.area(); // evaluates to 314