2010-01-21 13 views
7

o.prototype = {...} funciona solo si o es una función. Supongamos que tengo el siguiente código¿Prototipo JavaScript limitado a funciones?

conf = { 
    a: 2, 
    b: 4 
}; 
conf.prototype = { 
    d: 16 
} 

conf.a y conf.b es recuperado y valores adecuados. Pero conf.d no devuelve 16 sino que va indefinido. ¿Hay alguna solución de succión que la generalización basada en prototipos también se puede aplicar a este tipo de objetos?

Respuesta

21

Usted está confundiendo la propiedad prototype que se puede utilizar en Constructor Functions y lo interno[[Prototype]] propiedad .

Todos los objetos tienen esta propiedad interna [[Prototype]], y sólo se permite la new operador cuando se le llama con una función constructora para configurarlo (a través de la operación interna [[Construct]]).

Si usted quiere tener herencia de prototipos a instancias de objetos (sin necesidad de utilizar constructores), Object.create la técnica del Crockford es lo que quiere (ese método es ahora parte de la recientemente aprobada ECMAScript 5 ª Edición):

// Check if native implementation available 
if (typeof Object.create !== 'function') { 
    Object.create = function (o) { 
    function F() {} // empty constructor 
    F.prototype = o; // set base object as prototype 
    return new F(); // return empty object with right [[Prototype]] 
    }; 
} 

var confProto = { 
    d: 16 
}; 
var conf = Object.create(confProto); 
conf.a = 2; 
conf.b = 4; 

en el código anterior conf tendrá sus tres miembros, pero sólo a y b existe voluntad físicamente en él:

conf.hasOwnProperty('a'); // true 
conf.hasOwnProperty('b'); // true 
conf.hasOwnProperty('d'); // false 

Debido d existe en el conf [[Prototype]] (confProto).

El property accessors, . y [] son responsables de resolver las propiedades mirando hacia arriba si es necesario en la cadena de prototipo (a través del método interno [[Get]]).

+3

¿Podría el infractor por favor dejar un comentario? Siempre estoy buscando mejorar mis respuestas :) – CMS

6

En realidad, hay dos tipos diferentes de "prototipo" en JavaScript:

  1. Uno de ellos es el enlace "oculta" cada objeto tiene (vamos a utilizar para representar [[Prototype]] este enlace oculto). los literales de objetos de forma predeterminada tienen sus enlaces ocultos apuntando a Object.prototype, los objetos de función tienen su enlace oculto apuntando a Function.prototype, y los arreglos tienen el apuntando a Array.prototype. Estos prototipos de enlaces ocultos no están relacionados con las propiedades con el nombre "prototipo". No puede cambiar estos enlaces ocultos agregando o modificando o.prototype.
  2. Otra es que todos los objetos de función tienen automáticamente una propiedad especial llamada "prototype". Esto es principalmente para el uso del patrón de invocación del constructor.

[[Prototype]] se utiliza para buscar propiedades (como el padre en la jerarquía clásica), siempre que una propiedad no se puede encontrar en un objeto, su [[Prototype]] se busca su lugar.Un escenario de uso: supongamos que desea agregar una propiedad a todos los objetos, simplemente puede agregarlo a Object.prototype, que se aplicaría automáticamente a todos los objetos, ya que todos los objetos de alguna manera tienen Object.prototype como su raíz de cadena [[Prototype]].

Permite volver a la propiedad de objetos "prototype". Solo es útil cuando se usa con el operador new. Tomemos el siguiente fragmento de código como ejemplo:

function F() {} // function declaration 
// F now has a property named "prototype" 

var f = new F(); // use "new" operator to create a new function object based on F 

Lo new F() hace lo anterior es que crear primero un nuevo objeto función, ajuste el [[Prototype]] (enlace oculto) de este objeto función de nueva creación para ser F.prototype, y luego devolver el nuevo objeto de función. Esto es probablemente lo que ya entiende que funciona para objetos funcionales.

¿Recuerdas que dije que no podemos cambiar el [[Prototype]] de los objetos? Bueno, al menos no directamente. La función Object.create de Crockford hace precisamente eso, al utilizar el hecho de que el operador new podría ayudarnos a configurar [[Prototype]]. Entonces, al usar Object.create, debes indicar deliberadamente a dónde debe apuntar el enlace oculto de tu nuevo objeto. (De alguna manera, siento que quieres indicar quién es tu clase principal)

En tu ejemplo, conf es un objeto literal y conf.prototype no es realmente útil. Aquí hay otra versión que utiliza el estilo clásico:

function ConfBase() {} 
ConfBase.prototype.d = 16; 
var conf = new ConfBase(); 
conf.a = 2; 
conf.b = 4; 

document.writeln(conf.a); 
document.writeln(conf.b); 
document.writeln(conf.d); 

En comparación con la respuesta de @CMS, yo prefiero usar Object.create. Pero esencialmente los 2 estilos están usando el mismo mecanismo subyacente, solo que Object.create ayuda a ponerlo en orden.

Cuestiones relacionadas