significado - this javascript ejemplo




¿Cuál es la palabra clave 'nueva' en JavaScript? (10)

La new palabra clave en JavaScript puede ser bastante confusa cuando se la encuentra por primera vez, ya que las personas tienden 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?

así que probablemente no sea para crear instancias de objeto

Se utiliza exactamente para eso. Se define un constructor de funciones así:

function Person(name) {
    this.name = name;
}

var john = new Person('John');

Sin embargo, el beneficio adicional que tiene ECMAScript es que puede extenderse con la propiedad .prototype , por lo que podemos hacer algo como ...

Person.prototype.getName = function() { return this.name; }

Todos los objetos creados a partir de este constructor tendrán ahora un getName debido a la cadena de prototipo a la que tienen acceso.


Resumen:

La new palabra clave se usa en javascript para crear un objeto a partir de una función constructora. La new palabra clave debe colocarse antes de la llamada de la función del constructor y hará lo siguiente:

  1. Crea un nuevo objeto
  2. Establece el prototipo de este objeto en la propiedad prototipo de la función constructora.
  3. Enlaza la palabra clave this al objeto recién creado y ejecuta la función constructora
  4. Devuelve el objeto recién creado

Ejemplo:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true

Lo que sucede exactamente:

  1. const doggie dice: Necesitamos memoria para declarar una variable.
  2. El operador de asignación = dice: vamos a inicializar esta variable con la expresión después de =
  3. La expresión es new Dog(12) . El motor JS ve la nueva palabra clave, crea un nuevo objeto y establece el prototipo en Dog.prototype
  4. La función constructora se ejecuta con this valor establecido en el nuevo objeto. En este paso es donde se asigna la edad al nuevo objeto perrito creado.
  5. El objeto recién creado se devuelve y se asigna a la variable doggie.

A veces el código es más fácil que las palabras:

var func1 = function (x) { this.x = x; }                    // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; }   // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;

A1 = new func1(1);      // has A1.x  AND  A1.y
A2 =     func1(1);      // undefined ('this' refers to 'window')
B1 = new func2(2);      // has B1.x  ONLY
B2 =     func2(2);      // has B2.x  ONLY

para mí, siempre y cuando no prototipo, uso el estilo de func2 ya que me da un poco más de flexibilidad dentro y fuera de la función.


Además de la respuesta de Daniel Howard, esto es lo que hace new (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);

Hace 5 cosas:

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

Nota: la función constructora refiere la función después de la new palabra clave, como en

new ConstructorFunction(arg1, arg2)

Una vez hecho esto, si se solicita una propiedad no definida del nuevo objeto, la secuencia de comandos verificará el objeto [[prototype]] del objeto en su lugar. Así es como puede obtener algo similar a la herencia de clase 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 [[prototipo]] . Solo se puede establecer en el momento de la creación del objeto, ya sea con nuevo , con Object.create , o basado en el literal (funciones predeterminadas para Function.prototype, números para Number.prototype, etc.). Solo se puede leer con Object.getPrototypeOf (someObject) . No hay otra manera de establecer o leer este valor.

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

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 the same
// as {}. 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 una herencia de clase porque ahora, todos los objetos que realice utilizando el 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 encontrar finalmente esta página , donde esto se explica muy bien con diagramas bonitos.


JavaScript es un lenguaje de programación orientado a objetos y se usa exactamente para crear instancias. Se basa en prototipos, en lugar de en clases, pero eso no significa que no esté orientado a objetos.


La new palabra clave cambia el contexto en el que se ejecuta la función y devuelve un puntero a ese contexto.

Cuando no usa la new palabra clave, el contexto bajo el cual se ejecuta la función Vehicle() es el mismo contexto desde el que está llamando la función Vehicle . La palabra clave this se referirá al mismo contexto. Cuando utiliza un new Vehicle() , se crea un nuevo contexto, por lo que la palabra clave dentro de la función se refiere al nuevo contexto. Lo que obtienes a cambio es el contexto recién creado.


La new palabra clave crea instancias de objetos utilizando funciones como constructor. Por ejemplo:

var Foo = function() {};
Foo.prototype.bar = 'bar';

var foo = new Foo();
foo instanceof Foo; // true

Las instancias heredan del prototype de la función constructora. Así que dado el ejemplo anterior ...

foo.bar; // 'bar'

Supongamos que tiene esta función:

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

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

Foo();

La ejecución de esta función agregará dos propiedades al objeto de la window ( A y B ). Lo agrega a la window porque la window es el objeto que llamó a la función cuando la ejecutó de esa manera, y this en una función es el objeto que llamó a la función. En Javascript al menos.

Ahora, llámalo así con new :

var bar = new Foo();

Lo que sucede cuando agrega new a una llamada de función es que se crea un nuevo objeto (solo var bar = new Object() ) y que this dentro de la función apunta al nuevo Object que acaba de crear, en lugar de al objeto que llamó la función. Así que bar ahora es un objeto con las propiedades A y B Cualquier función puede ser un constructor, simplemente no siempre tiene sentido.


Ya hay algunas respuestas muy buenas, pero estoy publicando una nueva para enfatizar mi observación sobre el caso III a continuación sobre lo que sucede cuando tiene una declaración de devolución explícita en una función que está iniciando. Echa un vistazo a los siguientes casos:

Caso I :

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

Arriba hay un caso simple de llamar a la función anónima señalada por Foo . Cuando llamas a esta función devuelve undefined . Como no hay una declaración de devolución explícita, el intérprete de JavaScript inserta a la fuerza una return undefined; Declaración al final de la función. Aquí la ventana es el objeto de invocación (contextual this ) que obtiene nuevas propiedades A y B

Caso II :

var Foo = function(){
  this.A = 1;
  this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1

Aquí el intérprete de JavaScript al ver la new palabra clave crea un nuevo objeto que actúa como el objeto de invocación (contextualizado) de la función anónima señalada por Foo . En este caso, A y B convierten en propiedades en el objeto recién creado (en lugar de objeto de ventana). Como no tiene ninguna declaración de devolución explícita, el intérprete de JavaScript inserta a la fuerza una declaración de devolución para devolver el nuevo objeto creado debido al uso de una new palabra clave.

Caso III :

var Foo = function(){
  this.A = 1;
  this.B = 2;
  return {C:20,D:30}; 
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.

Aquí, nuevamente, el intérprete de JavaScript al ver la new palabra clave crea un nuevo objeto que actúa como el objeto de invocación (contextualizado) de la función anónima señalada por Foo . Nuevamente, A y B convierten en propiedades en el objeto recién creado. Pero esta vez tiene una declaración de devolución explícita, por lo que el intérprete de JavaScript no hará nada por sí mismo.

Lo que hay que tener en cuenta en el caso III es que el objeto que se está creando debido a una new palabra clave se perdió de su radar. bar realidad apunta a un objeto completamente diferente que no es el creado por el intérprete de JavaScript debido a una new palabra clave.





new-operator