为什么要在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 05:50:50  来源:igfitidea点击:

Why declare properties on the prototype for instance variables in JavaScript

javascriptprototypethis

提问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 prototypefor functions or properties that are classvariables and using this.somePropfor '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, declareprototypevariables and then refers to them with this i.e.

我看过的代码,并用作我自己的代码、declareprototype变量的模板,然后用这个 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, thisrefers 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 hasOwnPropertymethod.

您可以使用该hasOwnProperty方法测试该属性是实例属性还是原型属性。

console.log(a.hasOwnProperty("name")); // false

An instance can override the prototypevalue.

实例可以覆盖该prototype值。

b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris

And return to the prototypevalue.

并返回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.namevariable 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.

就变量而不是函数而言,原型可能用于在实例未设置自己的值的情况下的默认值。

The code in a fiddle

小提琴中的代码

回答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 ageis 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
}());
  1. Creating an IIFEwhich acts as a scope container for the inner code
  2. Declaring a function called MyCircleusing 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 radiusinstance property on the invoked object
  3. Attempting to access a radiusproperty on MyCirclefunction's prototypewhich doesn't exist so evaluates to undefined
  4. Creating an areainstance property on the global window object and assigning it a function expression
  5. Creating a MyCircleinstance property on a windowobject and assigning to it the MyCirclefunction
  1. 创建一个IIFE充当内部代码的作用域容器
  2. 声明一个MyCircle使用构造函数模式调用的函数(但请注意它永远不会被“构造”,所以应该去掉大写字母,因为它具有误导性)
    • 当被调用时radius在被调用的对象上创建一个实例属性
  3. 尝试访问不存在的函数的radius属性,因此评估为MyCircleprototypeundefined
  4. area在全局窗口对象上创建实例属性并为其分配函数表达式
  5. MyCirclewindow对象上创建实例属性并为其分配MyCircle函数

Summary:It seems like it's creating an areaand MyCircleproperties on the global windowobject, and when MyCircleis invoked it creates an additional radiusproperty.

总结:它似乎是在全局对象上创建一个areaandMyCircle属性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