2011-08-09 97 views

回答

16

你說得對,JavaScript沒有類(但是),但它確實有構造函數,定義了對象和構造函數之間關係的instanceof運算符,以及基於原型鏈的繼承形式。

obj instanceof ctorctor.prototypeobj的原型鏈上時爲true。

模下方的警告,你可以在5的EcmaScript實施instanceof從而

function isInstanceOf(obj, ctor) { 
    var proto = ctor.prototype; 
    if (typeof obj === "object" || typeof obj === "function") { 
    while (obj) { 
     if (obj === proto) { return true; } 
     obj = Object.getPrototypeOf(obj); 
    } 
    } 
    return false; 
} 

除非你去重新分配各地的原型(o = new MyConstructor(); MyConstructor.prototype = somethingElse)應該是這樣的情況new MyConstructor() instanceof MyConstructor

15.3.5.3部分對此進行了詳細解釋。

15.3.5.3 [[HasInstance]] (V)

假設F是一個功能對象。

當F的[[HasInstance]]內部方法被調用,值V,採取以下步驟:

  1. 如果V不是一個對象,返回false。
  2. 設O是調用屬性名稱爲「prototype」的F的[[Get]]內部方法的結果。
  3. 如果Type(O)不是Object,則拋出TypeError異常。
  4. 重複

    1. 令V的[[原型]]五
    2. 如果V是空的內部屬性,返回false值。
    3. 如果O和V引用同一個對象,則返回true。

因爲主機對象(如DOM節點)被允許執行[[HasInstance]]內部方法但他們喜歡,但大多數瀏覽器採用主機對象爲行爲密切本地對象這並不是故事的全部儘可能。

+0

不要說'(還)':(類仍然是strawman。如果我們很幸運,他們不會進入ES6! – Raynos

-2

Javascript是面向對象的,所以它確實有類。根本沒有明確的「class」指令,就像你在其他OOP語言中那樣。

+4

Javascript沒有類,它是ap基於輪轉的語言,這是一種實現面向對象的不同方式。差異可能很微妙,但它們很重要。 –

5

JavaScript並沒有類,但它確實有類型。您可以定義自己的類型和使用new關鍵字創建新實例:

function Foo(initialValue) { 
    this.value = initialValue || 0; 
} 
var foo = new Foo(17); 
var fooIsAFoo = foo instanceof Foo; // true! 
var fooIsAnObject = foo instanceof Object; // also true! We have inheritance here :) 
+0

你可以通過引用規範來支持'Types'的概念嗎?我有一種感覺,只有本地類型,'Foo'不是一種類型。 – Raynos

1

JavaScript不使用經典的繼承,它採用prototypal inheritance這裏的一切是一個「對象」,並繼承是通過克隆來完成,例如:

var myPrototype = function() { 
    var privateMember = "I am private"; 
    var publicMember = "I am public"; 
    var publicMethod = function() { 
     alert(privateMember); 
    } 
    return { 
     publicMember = publicMember, 
     publicMethod = publicMethod 
    } 
} 

var myInstace = new myPrototype(); 
myInstance.publicMethod(); 

這裏myInstance可以說是一個myPrototype「的情況下」,但在現實中所發生的事情是利用你克隆myPrototypenew關鍵字來創建myInstance

3

在JS中,函數是一個對象。這需要一段時間才能習慣,但這是事實。把這個放在一邊,你看別人使用的代碼會更有意義。如果你已經看到Javascript在人們將函數(){}作爲參數傳遞給另一個函數的情況,那就證明函數是第一類對象。 (你花了我一段時間),那麼你需要明白,如果你做了一個函數,你可以得到它的一個新實例。請參閱以下代碼:

function FooName(){ 
    var name; 
    this.setName = function(n){ 
     this.name = n; 
    } 
    this.getName = function(){ 
     return this.name; 
    } 
} 
var n1 = new FooName(); 
var n2 = new FooName(); 
n1.setName("FOO"); 
n2.setName("BAR"); 

此時,您有兩個FooName方法實例:n1和n2。在JS中用一個大寫的第一個字母來命名實例化函數是一種慣例,而不是客戶小寫的第一個字母。在這個例子中,我指出我的函數可以通過將它命名爲FooName而不是fooName來實例化。我希望這是有道理的。

在上面的例子中,n1有三個屬性。私有名稱屬性,公共setName屬性和公共getName屬性。每次我實例化一個新的FooName時,都會創建一個getName和setName的副本。這可能浪費內存空間。由於getName和setName不會改變,我不需要每個FooName實例的新副本。這是原型進來的地方。

你可以這樣說,然後getName和setName只會在內存中存在一次,從而釋放內存,這是一件好事。

FooName.prototype.setName = function(n){ 
    this.name = n; 
} 
FooName.prototype.getName = function(){ 
    return this.name; 
} 

如果從FooName功能刪除的getName和setName,那麼現在你將有一個FooName「類」有兩種方法,的getName和setName。

玩它。如果您有任何問題,請告訴我。

+0

不知道這是否回答@ loldrup的問題,但它確實給了我一些見解。謝謝+1 – brenjt

+0

True ... 我想我會說「instanceof」意味着你有一個函數,並且已經聲明瞭一個新的函數。關鍵詞「新」是什麼讓你的實例。例如,我的代碼如上,var n3 = FooName與var n3 = new FooName不一樣。離開新的區別非常顯着。如果你離開了「新」,那麼單詞「this」的所有用法都會指向窗口本身。 JS中的「this」是指它被調用的上下文。如果你在一個obj實例中調用它,它會引用obj。如果你在obj實例外面調用它,它是全局的。 – frosty

+1

「如果您從FooName函數中刪除getName和setName,那麼現在您將擁有一個FooName」class「,它具有兩個方法getName和setName。」 也就是說,(函數 - ) - 對象FooName的原型對象現在具有這些函數,並且由於能夠遵循原型鏈的名稱解析方法,FooName的所有實例都能夠找到這些方法。這是你的意思嗎? – loldrup