2012-02-27 11 views
35

Estoy muy confundido acerca de cómo trabajan los constructores en Javascrpt; a pesar de usar el lenguaje por varios años (principalmente como si fuera una versión semi-imperativa de LISP) me gustaría saber más sobre cómo se supone que los objetos funcionan en él.¿Qué hace `new` en JavaScript, de todos modos?

Teniendo en cuenta este código:

function Foo(x) { 
    return { 
     bar: function() { return x; } 
    }; 
} 

¿Cuál es la diferencia entre llamar myFoo = Foo(5) y myFoo = new Foo(5)? O, en otras palabras, ¿qué hace exactamente un constructor en Javascript do?

+13

Y si no entendieron esos resultados de búsqueda de Google, y vinieron aquí esperando una mejor explicación, ¿de qué sirve su comentario sarcástico? –

+0

@ChrisSobolewski porque si no sabemos lo que el OP no entiende al respecto, ¿cómo podemos ayudarlo? ¿Cómo podemos aclarar las cosas si no sabemos lo que no está claro? – Jeff

+0

@ChrisSobolewski, algunas personas olvidan que el propósito de este sitio es aclarar las cosas que usted no comprende. Solo porque la información precisa está disponible y tú la entiendes. Este sitio funciona perfectamente para mí para aclarar las cosas. –

Respuesta

44

¿Cuál es la diferencia entre llamar myFoo = Foo(5) y myFoo = new Foo(5)?

No hay diferencia para ese código, ya que devuelve un objeto, y el spec dice:

  • Vamos resultado ser el resultado de llamar al [[Call]] interna propiedad de F, proporcionando obj como el valor this y proporcionando la lista de argumentos pasada a [[Constructo]] como argumentos.
  • Si Type(result) es Object, entonces devuelva resultado.

Desde que la función devuelve un resultado que es un objeto, se utiliza su resultado. Se daría cuenta de la diferencia si no devolver un objeto, o si se comprueba this, por ejemplo si se volvió a escribir como:

function Foo(x) { 
    if (!(this instanceof Foo)) { return new Foo(x); } 
    this.bar = function() { return x; }; 
} 
// Now instanceof works. 
alert((new Foo) instanceof Foo); 

Lo que hace new en JavaScript hacer, de todos modos?

new El operador hace que la función a ser llamada con this unido a un recién creado Object cuyo prototipo es la propiedad de esa función prototype.

Para las funciones definidas por el usuario,

new f(a, b, c) 

es equivalente a

// Create a new instance using f's prototype. 
var newInstance = Object.create(f.prototype), result; 

// Call the function 
result = f.call(newInstance, a, b, c), 

// If the result is a non-null object, use it, otherwise use the new instance. 
result && typeof result === 'object' ? result : newInstance 

Tenga en cuenta, que la especificación del lenguaje define en realidad funciones con dos operaciones, [[Call]] y [[Construct]], por lo que hay algunos casos de esquina donde new se comporta de manera extraña.

Por ejemplo, atados y con funciones integradas:

var g = f.call.bind(f); 

debe definir una función que cuando se le llama, sólo llama a f, por lo g debe ser el mismo que f en todos los aspectos, pero

new g() 

produce

TypeError: function call() { [native code] } is not a constructor 

porque el La función integrada Function.prototype.call admite [[Llamar]] pero no [[Construir]].

Function.prototype.bind también se comporta de manera diferente alrededor de new y llamadas regulares. El valor this siempre es el límite thisValue cuando se llama, pero es una instancia recién construida cuando usa new.

+1

Esto es informativo, pero no responde exactamente la pregunta. – benekastah

+3

@benekastah, hay dos preguntas. Uno en el título y otro en el texto. Respondí el título primero y ahora he editado para responder el que está en el texto. –

+1

Así lo hiciste. Retiro mi objeción :) – benekastah

12

En este ejemplo particular, no hay diferencia en el resultado final.

Esto se debe a que su función Foo devuelve una instancia de objeto .

new El operador devuelve un nuevo objeto creado que hereda de prototipo del constructor sólo cuando la función devuelve un valor simple (o no devuelve nada, lo cual es técnicamente el valor undefined).

Por ejemplo:

function Foo() { 
    return 5; // or "", or null, or no return statement at all (undefined) 
} 

var foo = new Foo(); 
typeof foo; // "object" 
foo instanceof Foo; // true 
Foo.prototype.isPrototypeOf(foo); // true 

Cuando regresa un objeto, el objeto recién creado que hereda de prototipo del constructor simplemente se descarta:

function Foo() { 
    return {}; 
} 

var foo = new Foo(); 
typeof foo; // "object" 
foo instanceof Foo; // false 
Foo.prototype.isPrototypeOf(foo); // false 

Ver también:

5

En este caso, no habrá ninguna diferencia cuando devuelva un objeto nuevo. Podría ser reescrita como:

function Foo(x){ 
    this._x = x; 
} 

Foo.prototype.bar = function() { 
    return this._x; 
} 

Con esta sintaxis cada vez que llame new Foo se creará un nuevo objeto con una propiedad de _x. El beneficio es que la función bar se almacenará una vez y se reutilizará para múltiples instancias de Foo. Con el código en la pregunta llamando al Foo() varias veces creará una función de barra para cada instancia. Por lo tanto, adjuntar funciones al prototipo en lugar de tenerlas directamente en el objeto será más ligero en la memoria.

Un desglose completo de cómo funciona el prototipo se puede encontrar en MDC.

Cuestiones relacionadas