28

我正试图了解这种名为 JavaScript 的黑魔法——而且,我必须承认,我对此感到非常兴奋。我一直在看代码示例,主要来自“easeljs”,因为这是我主要使用的。而且我有点迷茫。。

prototype我(想我)理解使用作为变量的函数或属性class与使用“实例”变量之间的区别this.someProp(是的,我知道 JavaScript 中没有类。)

我看过的代码,正在用作我自己的代码、declare prototype变量的模板,然后用这个来引用它们,即

在构造函数中:

this.name = name;

然后声明:

Object.prototype.name;

然后,

this.name = "Freddy";

这是在用“new”调用的函数中,所以在这种情况下,据我所知,this指的是当前对象。令我困惑的是原型声明在做什么,为什么我们将它用于实例变量?


澄清:在下面的代码中,我看不到半径的原型声明正在实现什么:

(function(){
    // constructor
    function MyCircle(radius){
        this.radius = radius;
    }
    MyCircle.prototype.radius;
    this.area = function(){
        return 3.14*this.radius*this.radius;
    };
    window.MyCircle = MyCircle;
}());
4

4 回答 4

58

原型上的值具有与直接在实例上设置的属性不同的关键行为。尝试这个:

// 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

如果没有原型继承,这是不可能的。

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

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

实例可以覆盖该prototype值。

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

并返回prototype值。

delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George

这是原型继承的一个强大部分。

在另一种模式中:

function A() {
  this.name = "George";
}

this.name每个新实例都会再次声明该变量。

将方法作为在原型上声明的函数是有意义的。所有实例都可以共享一个函数,而不是在每个实例上重新声明函数定义。

在变量而不是函数方面,原型可以在实例没有设置自己的值的情况下用作默认值。

小提琴中的代码

于 2013-05-25T15:59:14.453 回答
11

存储在原型上的值提供了该属性的默认值。

如果您随后向该属性写入值,实例将获取该新值,隐藏原型上的值,该值将保持不变。

在您现在添加到问题中的代码的上下文中:

MyCircle.prototype.radius;

绝对什么都不做。这是一个无操作 - 它尝试读取该属性,然后丢弃结果。

于 2013-05-25T15:52:09.730 回答
0

其他答案已经解释了原型与实例属性之间的区别。

但只是为了增加答案,让我们分解您的代码片段:

(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. 创建一个IIFE充当内部代码的范围容器的
  2. 声明一个MyCircle使用构造函数模式调用的函数(但请注意它永远不会被“构造”,因此可能应该去掉大写字母,因为它具有误导性)
    • 调用时在被调用对象上创建radius实例属性
  3. 尝试访问不存在的函数上的radius属性,因此评估为MyCircleprototypeundefined
  4. 在全局窗口对象上创建area实例属性并为其分配函数表达式
  5. 在对象上创建MyCircle实例属性并将函数window分配给它MyCircle

摘要:它似乎是在全局对象上创建一个areaand属性,当被调用时它会创建一个附加属性。MyCirclewindowMyCircleradius

用法: MyCircle 应该在 area 之前调用,因为 area 依赖于 MyCircle 初始化半径:

window.MyCircle(10);
window.area(); // evaluates to 314
于 2017-12-18T22:37:21.400 回答
0

是的,我同意原型可用于属性(变量)的默认值。构造函数不需要声明属性;它可以有条件地完成。

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!

看看 Lucyage是如何有条件地声明和初始化的。

于 2017-04-26T08:25:50.817 回答