簡體   English   中英

為什么在JavaScript中為實例變量聲明屬性

[英]Why declare properties on the prototype for instance variables in JavaScript

我試圖了解這種名為JavaScript的黑色藝術 - 而且,我必須承認,對此非常興奮。 我一直在尋找代碼示例,主要來自“easeljs”,因為這是我將主要使用的。 我有點困惑..

我(我想)理解使用prototype作為class變量的函數或屬性與使用this.someProp作為'實例'變量之間的區別(是的,我知道JavaScript中沒有類。)

我看過的代碼,我用作自己代碼的模板, declare prototype變量,然后用它來引用它們

在構造函數中:

this.name = name;

然后聲明:

Object.prototype.name;

然后,

this.name = "Freddy";

這是在用'new'調用的函數中,所以在這種情況下,據我所知, this是指當前對象。 令我困惑的是原型聲明正在做什么以及為什么我們將它用於實例變量?


澄清 :在下面的代碼中,我沒有看到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;
}());

原型上的值具有與直接在實例上設置的屬性不同的鍵行為。 試試這個:

// 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方法測試屬性是實例屬性還是prototype屬性。

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變量。

將方法作為在原型上聲明的函數是有道理的。 所有實例都可以共享一個函數,而不是在每個實例上重新聲明函數定義。

就變量而不是函數而言,在實例未設置其自己的值的情況下,原型可以用於默認值。

小提琴中的代碼

存儲在原型上的值為該屬性提供默認值。

如果您隨后將值寫入該屬性,則實例將獲取該新值,隱藏原型上的值,該值將保持不變。

在代碼的上下文中,您現在已添加到問題中:

MyCircle.prototype.radius;

什么都不做。 這是一個無操作 - 它試圖讀取該屬性然后丟棄結果。

是的,我同意原型可以用於屬性(變量)的默認值。 構造函數不需要聲明屬性; 它可以有條件地完成。

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!

了解露西的age是如何有條件地宣布和初始化的。

其他答案已經解釋了原型與實例屬性之間的區別。

但只是為了添加答案,讓我們分解你的代碼片段:

(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. 試圖訪問MyCircle函數prototype中不存在的radius屬性,因此求值為undefined
  4. 在全局窗口對象上創建area實例屬性並為其指定函數表達式
  5. window對象上創建MyCircle實例屬性並MyCircle分配MyCircle函數

簡介:看起來它正在全局window對象上創建一個areaMyCircle屬性,並且當調用MyCircle時,它會創建一個額外的radius屬性。

用法:應該在區域之前調用MyCircle,因為區域依賴於MyCircle初始化半徑:

window.MyCircle(10);
window.area(); // evaluates to 314

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM