¿Cuál es la palabra clave "nueva" en JavaScript?

Resuelto Alon Gubkin asked hace 14 años • 17 respuestas

La newpalabra clave en JavaScript puede resultar bastante confusa cuando se encuentra por primera vez, ya que la gente tiende a pensar que JavaScript no es un lenguaje de programación orientado a objetos.

  • ¿Qué es?
  • ¿Qué problemas resuelve?
  • ¿Cuándo es apropiado y cuándo no?
Alon Gubkin avatar Oct 30 '09 04:10 Alon Gubkin
Aceptado

Hace 5 cosas:

  1. Crea un nuevo objeto. El tipo de este objeto es simplemente objeto .
  2. Establece la propiedad interna, inaccesible [[prototype]](es decir __proto__) de este nuevo objeto para que sea el prototypeobjeto externo y accesible de la función constructora (cada objeto de función tiene automáticamente una prototypepropiedad).
  3. Hace que la thisvariable apunte al objeto recién creado.
  4. Ejecuta la función constructora, utilizando el objeto recién creado cada vez que thisse menciona.
  5. Devuelve el objeto recién creado, a menos que la función constructora devuelva una nullreferencia que no sea un objeto. En este caso, se devuelve esa referencia de objeto.

Nota: la función constructora se refiere a la función después de la newpalabra clave, como en

new ConstructorFunction(arg1, arg2)

Una vez hecho esto, si se solicita una propiedad indefinida del nuevo objeto, el script verificará la [[prototype]]propiedad en el objeto del objeto. Así es como puedes obtener algo similar a la herencia de clases tradicional en JavaScript.

La parte más difícil de esto es el punto número 2. Cada objeto (incluidas las funciones) tiene esta propiedad interna llamada [[prototype]]. Solo se puede configurar en el momento de la creación del objeto, ya sea con new, con Object.createo en función del literal (las funciones predeterminadas son Function.prototype, los números son Number.prototype, etc.). Sólo se puede leer con Object.getPrototypeOf(someObject). No hay otra forma de obtener o establecer este valor.

Las funciones, además de la [[prototype]]propiedad oculta, también tienen una propiedad llamada prototipo , y es a esta a la que puedes acceder y modificar para proporcionar propiedades y métodos heredados para los objetos que creas.


Aquí hay un ejemplo:

ObjMaker = function() { this.a = 'first'; };
// `ObjMaker` is just a function, there's nothing special about it
// that makes it a constructor.

ObjMaker.prototype.b = 'second';
// like all functions, ObjMaker has an accessible `prototype` property that 
// we can alter. I just added a property called 'b' to it. Like 
// all objects, ObjMaker also has an inaccessible `[[prototype]]` property
// that we can't do anything with

obj1 = new ObjMaker();
// 3 things just happened.
// A new, empty object was created called `obj1`.  At first `obj1` 
// was just `{}`. The `[[prototype]]` property of `obj1` was then set to the current
// object value of the `ObjMaker.prototype` (if `ObjMaker.prototype` is later
// assigned a new object value, `obj1`'s `[[prototype]]` will not change, but you
// can alter the properties of `ObjMaker.prototype` to add to both the
// `prototype` and `[[prototype]]`). The `ObjMaker` function was executed, with
// `obj1` in place of `this`... so `obj1.a` was set to 'first'.

obj1.a;
// returns 'first'
obj1.b;
// `obj1` doesn't have a property called 'b', so JavaScript checks 
// its `[[prototype]]`. Its `[[prototype]]` is the same as `ObjMaker.prototype`
// `ObjMaker.prototype` has a property called 'b' with value 'second'
// returns 'second'

Es como herencia de clases porque ahora, cualquier objeto que crees new ObjMaker()también parecerá haber heredado la propiedad 'b'.

Si quieres algo como una subclase, entonces haz esto:

SubObjMaker = function () {};
SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
// Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
// is now set to the object value of ObjMaker.prototype.
// The modern way to do this is with Object.create(), which was added in ECMAScript 5:
// SubObjMaker.prototype = Object.create(ObjMaker.prototype);

SubObjMaker.prototype.c = 'third';  
obj2 = new SubObjMaker();
// [[prototype]] property of obj2 is now set to SubObjMaker.prototype
// Remember that the [[prototype]] property of SubObjMaker.prototype
// is ObjMaker.prototype. So now obj2 has a prototype chain!
// obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype

obj2.c;
// returns 'third', from SubObjMaker.prototype

obj2.b;
// returns 'second', from ObjMaker.prototype

obj2.a;
// returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype 
// was created with the ObjMaker function, which assigned a for us

Leí un montón de basura sobre este tema antes de finalmente encontrar esta página , donde se explica muy bien con bonitos diagramas.

Daniel Howard avatar Sep 07 '2010 12:09 Daniel Howard

Supongamos que tiene esta función:

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

Si llama a esto como una función independiente así:

Foo();

La ejecución de esta función agregará dos propiedades al windowobjeto ( Ay B). Lo agrega al windowporque windowes el objeto que llamó a la función cuando la ejecutas así, y thisen una función está el objeto que llamó a la función. Al menos en JavaScript.

Ahora, llámalo así con new:

var bar = new Foo();

Cuando agrega newa una llamada de función, se crea un nuevo objeto (solo var bar = new Object()) y thisdentro de la función apunta al nuevo Objectque acaba de crear, en lugar del objeto que llamó a la función. Ahora lo bares un objeto con las propiedades Ay B. Cualquier función puede ser un constructor; simplemente no siempre tiene sentido.

JulianR avatar Oct 29 '2009 22:10 JulianR

Además de la respuesta de Daniel Howard , esto es lo que newhace (o al menos parece hacer):

function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
    return res;
}

Mientras

var obj = New(A, 1, 2);

es equivalente a

var obj = new A(1, 2);
basilikum avatar Jun 20 '2013 23:06 basilikum