2011-03-22 123 views
4

我嘗試提高我的JavaScript技能。 我不明白爲什麼(5)工作和(2)返回錯誤。不一樣嗎?2個JavaScript對象有什麼區別?

  1. B.fn()// OK
  2. B.fn2()//類型錯誤:對象#沒有方法 'fn2的'
  3. 變種一個新= A()
  4. a.fn ()// OK
  5. a.fn2()// OK

    var A = function() { 
        this.fn = function() { alert(3); } 
    } 
    A.prototype = { 
        fn2: function() { alert(4); } 
    }; 
    
    var B = 
        { 
         fn: function() { alert(1); } 
        } 
    B.prototype = { 
        fn2: function() { alert(2); } 
    }; 
    

回答

1

(容易解釋)使用function作爲構造(通過使用new操作)時 的prototype屬性僅適用。該function創建克隆的是prototype和函數內部的this關鍵字設置爲克隆。克隆上的屬性是直接引用/指向prototypes屬性的指針。

對象文字{}是替代new Object()的更強大的表達式,因此可以從Object.prototype「繼承」屬性。

所以:

function ClassLike() {} 
ClassLike.prototype = { 
    foo : "bar" 
} 

var instance = new ClassLike(); 
alert(instance.foo); // bar 

工作,因爲new操作者在運動中踢一些操作,以創建新的對象,而:

var instance = { 
    foo : "bar" 
} 
instance.prototype = { 
    baz : "foobar" 
} 

僅僅增加了一個屬性(原型)到已創建的對象,沒有任何過程實際上分配/更改對象原始原型。

現在Mozilla添加了一個非標準(IE不支持它)的方式來改變一個已經實例化的對象原型通過__proto__,並且有一些請願書將它添加到ES5(EcmaScript 5)中。我不會使用它atm。但它的工作原理是這樣的:

var instance = {}; 
var parent = { 
    foo : "bar" 
} 
instance.__proto__ = parent; 

alert(instance.foo); // bar 

另一種方式來改變已經實例化對象的原型是添加到Object構造函數的原型(這是不建議的原因有很多)。因此:

var instance = {}; // a more powerful alternative to `new Object()` 

Object.prototype.foo = "bar"; 

alert(instance.foo); // bar 

這都是可能的,儘管羯羊它是明智的,做到這一點...我說沒有,但衆說紛紜,我寧願避免的辯論;)

不管怎麼說,只記得prototype作品當你newfunction,否則它只是成爲一個實例的屬性。

+0

謝謝你的回答。我有相對的問題。我需要訪問私有成員的特權函數,對吧?如果是,那麼爲什麼當我調用「new C().fn()」,「this」沒有看到「m」成員「?var C = function(){var m; this.fn = function(){ return this.m;}} – theateist 2011-03-22 10:06:29

+0

'var m'創建一個局部變量,而不是一個屬性,'this.m'試圖引用一個公共屬性,'this'關鍵字和其他語言不一樣,它是隻是一個指向函數擁有對象的'注入'變量,這可以起作用:'var C = function(){var m = 1; this.fn = function(){return m;}}' – BGerrissen 2011-03-22 10:19:14

+0

'__proto__'不會被添加到ES5中:ES5已經是最後一個不變的標準了,但是'Object.getPrototypeOf(o)'給出了'o'的原型,同樣的,現在說「now Mozilla已添加「;它已經存在了很長一段時間,並且也存在於Carakan(Opera),JSC(Safari)和V8(Chrome)中。 – gsnedders 2011-03-22 20:40:24

7

a是的一個實例在A類,那裏的B是類本身。由於fn2沒有被定義爲靜態函數,它只會提供給B類的實例,而不是類B本身。

如果您想直接使用B,你可以使用:

new B().fn2()

如果你定義Bfunction()

或者,你可以定義fn2您已經定義fn

以同樣的方式
+2

其實'新B()FN2()'是行不通的,因爲沒有'B()'函數的任何位置定義。 – rsp 2011-03-22 08:43:16

+0

哦,你是對的,編輯。 – 2011-03-22 08:43:53

0

你已經證明了什麼是什麼,我會考慮的最大所致JavaScript中面向對象的問題:原型必須是構造函數的屬性,而不是對象本身。這意味着,如果你有一個可以很容易地定義爲對象字面一個對象,你還需要有一個無用的構造函數只是定義對象的原型。由Douglas Crockford的Prototypal Inheritance in JavaScript

閱讀這篇文章。這裏是相關的部分:

[...] JavaScript itself is conflicted about its prototypal nature. In a prototypal system, objects inherit from objects. JavaScript, however, lacks an operator that performs that operation. Instead it has a new operator, such that new f() produces a new object that inherits from f.prototype This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. JavaScript's constructor pattern did not appeal to the classical crowd. It also obscured JavaScript's true prototypal nature. As a result, there are very few programmers who know how to use the language effectively. Fortunately, it is easy to create an operator that implements true prototypal inheritance. It is a standard feature in my toolkit, and I highly recommend it for yours.

閱讀文章的一些想法沒有如何有效地解決你想要做的事情。

0

那麼,你的答案是非常簡單的。在JavaScript中,只有構造函數具有「原型」,即原型屬性。對象文字例如「{}」不。因此,您的號碼2行不通,除非你改變它,如下所示:

var B = function(){ // the B constructor 
      return this; 
     } 
B.prototype = { 
fn2: function(){ alert(2); } 
}