2015-01-02 2 views
3

Я пытался использовать следующий код, чтобы добавить метод start к объекту:Почему объект инициализации JavaScript не содержит объект-прототип?

var Bounce = Bounce || { 
    Info : {}, 
    Game : {} 
}; 

Bounce.Game.prototype.start = function() { 
    Bounce.log("Starting " + new Bounce.Info()); 
} 

Но это приводит к следующей ошибке (на Bounce.Game.prototype.start линии):

Uncaught TypeError: Cannot set property 'start' of undefined

Глядя на объект в консоли Chrome я вижу, что он не содержит объект prototype (но имеет toString, valueOf и constructor и т. д.).

Это легко исправить, добавив следующую строку перед въездом прототипа:

Bounce.Game = function() {}; 

Я не знаю, почему это необходимо, когда объект уже инициализирована?

W3Schools говорит мне, что «у каждого объекта JavaScript есть прототип», но это, похоже, не так.

+0

«Прототип», который, как вы считали, вы обращаетесь, на самом деле '__proto__'. – Leo

+0

Это ваше намерение, что 'Bounce.Game' будет классом? Если это так, это должна быть функция, а не '{}'. Если нет, то я не уверен, что вы надеетесь выполнить, установив метод на своем прототипе, а не непосредственно на самом объекте. –

+1

Понятно, что все объекты имеют прототип, но только объекты-объекты имеют свойство 'prototype' ** **. Они не одинаковы. Если вы читаете спецификацию ECMAScript, прототип обычно представляется как ** [[Prototype]] **, который является детальностью реализации, находится в JS-движке, а не в языковой функции. Однако в некоторых движках ** [[Prototype]] ** можно получить доступ к свойству '__proto__'. – Leo

ответ

4

Концептуально, все объекты имеют прототип, но только функциональные объекты (в том числе конструкторы, как Object, Array, хотя они не производят функции) имеют свойство именем prototype. Они не одинаковы.

Если вы читаете спецификацию ECMAScript, прототип обычно представлен как [[Prototype]], который является деталью реализации, в JS-движке, а не в языковой функции. Тем не менее, в некоторых двигателях [[Prototype]] выставлен и доступен через __proto__ объект (нестандартный).


Кстати:

  1. Если вы хотите получить доступ к [[Prototype]], Object.getPrototypeOf() является вашим другом.

  2. При использовании a instanceof b, это на самом деле сравнение a 's [[Prototype]] цепь с b' s prototypeсвойство.

  3. И почему мы говорим, что null является прототипом всего? Это также не относится к prototype но [[Prototype]]:

    Object.getPrototypeOf(Object.getPrototypeOf({})) // null 
    Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([]))) // null 
    Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(new String("")))) // null 
    
    // or shorter like this 
    ({}).__proto__.__proto__ // null 
    ([]).__proto__.__proto__.__proto__ // null 
    ("").__proto__.__proto__.__proto__ // null 
    
+0

это заставляет меня задуматься об обходном пути ... Я напишу ответ – balanza

2

Так, вдохновленный @Leo комментариями, я думаю об этом решении, чтобы использовать простой {} объект с его прототипом.

У нас есть этот объект:

var Bounce = Bounce || { 
    Info : {}, 
    Game : {} 
}; 

Определим prototype свойства для данного объекта

Object.defineProperty(Bounce.Game, 'prototype', { 
    get: function() { 
     return Object.getPrototypeOf(Bounce.Game); 
    } 
}); 

Теперь мы можем использовать прототип как обычно:

Bounce.Game.prototype.start = function(){ 
    console.log('start'); 
}; 

Bounce.Game.start(); 

Проверить это : http://jsbin.com/bapuvo/3/edit

+0

подход. Но почему бы не просто «Bounce.Game.start = function ...»? – Leo

+0

Прототип предназначен для совместного использования в разных случаях, для наследования и сохранения памяти. Это решение для проблемы, как предложил @ Микавели, возможно, я никогда не буду использовать этот подход. Например, мы не знаем, где этот код используется и как: если он находится в полной среде, совместимой с CommonJS, я бы предпочел использовать правильное решение для проектирования модулей (подумайте об nodejs или титане). – balanza

+0

@ Leo, отвечая на ваш вопрос: да, это то же самое. Поскольку вы не собираетесь использовать «новый» оператор с простым объектом, использование прототипа стало бессмысленным. – balanza