property new mdn ejemplos create javascript prototype object-create

javascript - mdn - object.create vs new



Comprender la diferencia entre Object.create() y el nuevo SomeFunction() (10)

Recientemente me topé con el método Object.create() en JavaScript, y estoy tratando de deducir en qué se diferencia de crear una nueva instancia de un objeto con el new SomeFunction() , y cuándo querría usar uno sobre el otro.

Considere el siguiente ejemplo:

var test = { val: 1, func: function() { return this.val; } }; var testA = Object.create(test); testA.val = 2; console.log(test.func()); // 1 console.log(testA.func()); // 2 console.log(''other test''); var otherTest = function() { this.val = 1; this.func = function() { return this.val; }; }; var otherTestA = new otherTest(); var otherTestB = new otherTest(); otherTestB.val = 2; console.log(otherTestA.val); // 1 console.log(otherTestB.val); // 2 console.log(otherTestA.func()); // 1 console.log(otherTestB.func()); // 2

Observe que se observa el mismo comportamiento en ambos casos. Me parece que las principales diferencias entre estos dos escenarios son:

  • El objeto utilizado en Object.create() realidad forma el prototipo del nuevo objeto, mientras que en la new Function() de las propiedades / funciones declaradas no forma el prototipo.
  • No puede crear cierres con la sintaxis Object.create() como lo haría con la sintaxis funcional. Esto es lógico dado el alcance de tipo léxico (bloque vs) de JavaScript.

¿Son correctas las afirmaciones anteriores? ¿Y me estoy perdiendo algo? ¿Cuándo usarías uno sobre el otro?

EDITAR: enlace a la versión jsfiddle del ejemplo de código anterior: http://jsfiddle.net/rZfYL/


El objeto utilizado en Object.create en realidad forma el prototipo del nuevo objeto, donde, al igual que en la nueva Función (), las propiedades / funciones declaradas no forman el prototipo.

Sí, Object.create construye un objeto que hereda directamente del que pasó como primer argumento.

Con las funciones del constructor, el objeto recién creado se hereda del prototipo del constructor, por ejemplo:

var o = new SomeConstructor();

En el ejemplo anterior, o hereda directamente de SomeConstructor.prototype .

Hay una diferencia aquí, con Object.create puedes crear un objeto que no se hereda de nada, Object.create(null); , por otro lado, si establece SomeConstructor.prototype = null; el objeto recién creado heredará de Object.prototype .

No puede crear cierres con la sintaxis Object.create como lo haría con la sintaxis funcional. Esto es lógico dado el alcance de tipo léxico (bloque vs) de JavaScript.

Bueno, puede crear cierres, por ejemplo, usando el argumento de descriptores de propiedad:

var o = Object.create({inherited: 1}, { foo: { get: (function () { // a closure var closured = ''foo''; return function () { return closured+''bar''; }; })() } }); o.foo; // "foobar"

Tenga en cuenta que estoy hablando del método ECMAScript 5th Edition Object.create , no de la leyenda de Crockford.

El método está comenzando a implementarse de forma nativa en los últimos navegadores, verifique esta tabla de compatibilidad .


Déjame intentar explicar (más en el Blog ):

  1. Cuando escribes Car constructor var Car = function(){} , así es como son las cosas internamente: Tenemos un {prototype} enlace oculto a Function.prototype que no es accesible y un enlace prototype a Car.prototype que es accesible y tiene un constructor real de Car . Tanto Function.prototype como Car.prototype tienen enlaces ocultos a Object.prototype .
  2. Cuando queremos crear dos objetos equivalentes utilizando el new operador y el método de create , tenemos que hacerlo así: Honda = new Car(); y Maruti = Object.create(Car.prototype) . ¿Que esta pasando?

    Honda = new Car(); - Cuando creas un objeto como este, la propiedad oculta {prototype} apunta a Car.prototype . Así que aquí, el {prototype} del objeto Honda siempre será Car.prototype - no tenemos ninguna opción para cambiar la propiedad {prototype} del objeto. ¿Qué pasa si quiero cambiar el prototipo de nuestro objeto recién creado?
    Maruti = Object.create(Car.prototype) - Cuando crea un objeto como este, tiene una opción adicional para elegir la propiedad {prototype} su objeto. Si desea que Car.prototype sea el {prototype} , páselo como parámetro en la función. Si no desea ningún {prototype} para su objeto, puede pasar un null como este: Maruti = Object.create(null) .

Conclusión - Al usar el método Object.create , tiene la libertad de elegir su propiedad {prototype} objeto. En new Car(); , no tienes esa libertad.

Manera preferida en OO JavaScript:

Supongamos que tenemos dos objetos a y b .

var a = new Object(); var b = new Object();

Ahora, supongamos que a tiene algunos métodos a los que b también quiere acceder. Para eso, requerimos la herencia de objetos ( a debe ser el prototipo de b solo si queremos acceder a esos métodos). Si verificamos los prototipos de a y b , descubriremos que comparten el prototipo Object.prototype .

Object.prototype.isPrototypeOf(b); //true a.isPrototypeOf(b); //false (the problem comes into the picture here).

Problema: queremos que el objeto a sea ​​el prototipo de b , pero aquí creamos el objeto b con el prototipo Object.prototype . Solución: ECMAScript 5 introdujo Object.create() , para lograr tal herencia fácilmente. Si creamos el objeto b como este:

var b = Object.create(a);

entonces,

a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)

Por lo tanto, si está realizando scripts orientados a objetos, Object.create() es muy útil para la herencia.


De acuerdo con esta respuesta y este video, la new palabra clave hace lo siguiente:

  1. Crea nuevo objeto.

  2. Enlaza el nuevo objeto a la función constructora ( prototype ).

  3. Hace que this variable apunte al nuevo objeto.

  4. Ejecuta la función de constructor usando el nuevo objeto y la ejecución implícita return this ;

  5. Asigna el nombre de la función del constructor al nuevo constructor propiedades del objeto.

Object.create realiza solo los pasos 1st y 2nd !


En pocas palabras, la new X es Object.create(X.prototype) y además ejecuta la función constructor . (Y le da al constructor la oportunidad de return el objeto real que debería ser el resultado de la expresión en lugar de this ).

Eso es. :)

El resto de las respuestas son confusas, porque aparentemente nadie más lee la definición de new tampoco. ;)


Esta:

var foo = new Foo();

y

var foo = Object.create(Foo.prototype);

Son bastante similares. Una diferencia importante es que el new Foo realidad ejecuta el código del constructor, mientras que Object.create no ejecutará código como el

function Foo() { alert("This constructor does not run with Object.create"); }

Tenga en cuenta que si usa la versión de dos parámetros de Object.create() , puede hacer cosas mucho más poderosas.


Estos son los pasos que ocurren internamente para ambas llamadas:
(Pista: la única diferencia es en el paso 3)

new Test() :

  1. crear new Object() obj
  2. establecer obj.__proto__ a Test.prototype
  3. return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value

Object.create( Test.prototype )

  1. crear new Object() obj
  2. establecer obj.__proto__ a Test.prototype
  3. return obj;

Así que básicamente Object.create no ejecuta el constructor.


Internamente Object.create hace esto:

Object.create = function (o) { function F() {} F.prototype = o; return new F(); };

La sintaxis simplemente quita la ilusión de que JavaScript utiliza la herencia clásica.


La diferencia es la llamada "herencia pseudoclásica versus prototípica". La sugerencia es usar solo un tipo en su código, no mezclar los dos.

En la herencia pseudoclásica (con el operador "nuevo"), imagine que primero define una pseudo-clase y luego crea objetos de esa clase. Por ejemplo, defina una pseudo-clase "Persona", y luego cree "Alice" y "Bob" a partir de "Persona".

En la herencia prototípica (usando Object.create), crea directamente una persona específica "Alice", y luego crea otra persona "Bob" usando "Alice" como prototipo. No hay "clase" aquí; todos son objetos

Internamente, JavaScript usa la "herencia prototípica"; La forma "pseudoclásica" es solo un poco de azúcar.

Vea este enlace para una comparación de las dos maneras.


Variantes de creación de objetos.

Variante 1 : '' nuevo objeto () '' -> constructor de objetos sin argumentos.

var p1 = new Object(); // ''new Object()'' create and return empty object -> {} var p2 = new Object(); // ''new Object()'' create and return empty object -> {} console.log(p1); // empty object -> {} console.log(p2); // empty object -> {} // p1 and p2 are pointers to different objects console.log(p1 === p2); // false console.log(p1.prototype); // undefined // empty object which is in fact Object.prototype console.log(p1.__proto__); // {} // empty object to which p1.__proto__ points console.log(Object.prototype); // {} console.log(p1.__proto__ === Object.prototype); // true // null, which is in fact Object.prototype.__proto__ console.log(p1.__proto__.__proto__); // null console.log(Object.prototype.__proto__); // null

Variante 2 : '' Nuevo objeto (persona) '' -> Objeto constructor con argumento.

const person = { name: ''no name'', lastName: ''no lastName'', age: -1 } // ''new Object(person)'' return ''person'', which is pointer to the object -> // -> { name: ''no name'', lastName: ''no lastName'', age: -1 } var p1 = new Object(person); // ''new Object(person)'' return ''person'', which is pointer to the object -> // -> { name: ''no name'', lastName: ''no lastName'', age: -1 } var p2 = new Object(person); // person, p1 and p2 are pointers to the same object console.log(p1 === p2); // true console.log(p1 === person); // true console.log(p2 === person); // true p1.name = ''John''; // change ''name'' by ''p1'' p2.lastName = ''Doe''; // change ''lastName'' by ''p2'' person.age = 25; // change ''age'' by ''person'' // when print ''p1'', ''p2'' and ''person'', it''s the same result, // because the object they points is the same console.log(p1); // { name: ''John'', lastName: ''Doe'', age: 25 } console.log(p2); // { name: ''John'', lastName: ''Doe'', age: 25 } console.log(person); // { name: ''John'', lastName: ''Doe'', age: 25 }

Variante 3.1 : '' Object.create (person) ''. Utilice Object.create con el simple objeto ''person''. ''Object.create (person)'' creará (y devolverá) un nuevo objeto vacío y agregará la propiedad ''__proto__'' al mismo nuevo objeto vacío. Esta propiedad ''__proto__'' apuntará al objeto ''persona''.

const person = { name: ''no name'', lastName: ''no lastName'', age: -1, getInfo: function getName() { return `${this.name} ${this.lastName}, ${this.age}!`; } } var p1 = Object.create(person); var p2 = Object.create(person); // ''p1.__proto__'' and ''p2.__proto__'' points to // the same object -> ''person'' // { name: ''no name'', lastName: ''no lastName'', age: -1, getInfo: [Function: getName] } console.log(p1.__proto__); console.log(p2.__proto__); console.log(p1.__proto__ === p2.__proto__); // true console.log(person.__proto__); // {}(which is the Object.prototype) // ''person'', ''p1'' and ''p2'' are different console.log(p1 === person); // false console.log(p1 === p2); // false console.log(p2 === person); // false // { name: ''no name'', lastName: ''no lastName'', age: -1, getInfo: [Function: getName] } console.log(person); console.log(p1); // empty object - {} console.log(p2); // empty object - {} // add properties to object ''p1'' // (properties with the same names like in object ''person'') p1.name = ''John''; p1.lastName = ''Doe''; p1.age = 25; // add properties to object ''p2'' // (properties with the same names like in object ''person'') p2.name = ''Tom''; p2.lastName = ''Harrison''; p2.age = 38; // { name: ''no name'', lastName: ''no lastName'', age: -1, getInfo: [Function: getName] } console.log(person); // { name: ''John'', lastName: ''Doe'', age: 25 } console.log(p1); // { name: ''Tom'', lastName: ''Harrison'', age: 38 } console.log(p2); // use by ''__proto__''(link from ''p1'' to ''person''), // person''s function ''getInfo'' console.log(p1.getInfo()); // John Doe, 25! // use by ''__proto__''(link from ''p2'' to ''person''), // person''s function ''getInfo'' console.log(p2.getInfo()); // Tom Harrison, 38!

Variante 3.2 : '' Object.create (Object.prototype) ''. Utilice Object.create con objeto incorporado -> ''Object.prototype''. ''Object.create (Object.prototype)'' creará (y devolverá) un nuevo objeto vacío y agregará la propiedad ''__proto__'' al mismo nuevo objeto vacío. Esta propiedad ''__proto__'' apuntará al objeto ''Object.prototype''.

// ''Object.create(Object.prototype)'' : // 1. create and return empty object -> {}. // 2. add to ''p1'' property ''__proto__'', which is link to ''Object.prototype'' var p1 = Object.create(Object.prototype); // ''Object.create(Object.prototype)'' : // 1. create and return empty object -> {}. // 2. add to ''p2'' property ''__proto__'', which is link to ''Object.prototype'' var p2 = Object.create(Object.prototype); console.log(p1); // {} console.log(p2); // {} console.log(p1 === p2); // false console.log(p1.prototype); // undefined console.log(p2.prototype); // undefined console.log(p1.__proto__ === Object.prototype); // true console.log(p2.__proto__ === Object.prototype); // true

Variante 4 : '' nuevo SomeFunction () ''

// ''this'' in constructor-function ''Person'' // represents a new instace, // that will be created by ''new Person(...)'' // and returned implicitly function Person(name, lastName, age) { this.name = name; this.lastName = lastName; this.age = age; //----------------------------------------------------------------- // !--- only for demonstration --- // if add function ''getInfo'' into // constructor-function ''Person'', // then all instances will have a copy of the function ''getInfo''! // // this.getInfo: function getInfo() { // return this.name + " " + this.lastName + ", " + this.age + "!"; // } //----------------------------------------------------------------- } // ''Person.prototype'' is an empty object // (before add function ''getInfo'') console.log(Person.prototype); // Person {} // With ''getInfo'' added to ''Person.prototype'', // instances by their properties ''__proto__'', // will have access to the function ''getInfo''. // With this approach, instances not need // a copy of the function ''getInfo'' for every instance. Person.prototype.getInfo = function getInfo() { return this.name + " " + this.lastName + ", " + this.age + "!"; } // after function ''getInfo'' is added to ''Person.prototype'' console.log(Person.prototype); // Person { getInfo: [Function: getInfo] } // create instance ''p1'' var p1 = new Person(''John'', ''Doe'', 25); // create instance ''p2'' var p2 = new Person(''Tom'', ''Harrison'', 38); // Person { name: ''John'', lastName: ''Doe'', age: 25 } console.log(p1); // Person { name: ''Tom'', lastName: ''Harrison'', age: 38 } console.log(p2); // ''p1.__proto__'' points to ''Person.prototype'' console.log(p1.__proto__); // Person { getInfo: [Function: getInfo] } // ''p2.__proto__'' points to ''Person.prototype'' console.log(p2.__proto__); // Person { getInfo: [Function: getInfo] } console.log(p1.__proto__ === p2.__proto__); // true // ''p1'' and ''p2'' points to different objects(instaces of ''Person'') console.log(p1 === p2); // false // ''p1'' by its property ''__proto__'' reaches ''Person.prototype.getInfo'' // and use ''getInfo'' with ''p1''-instance''s data console.log(p1.getInfo()); // John Doe, 25! // ''p2'' by its property ''__proto__'' reaches ''Person.prototype.getInfo'' // and use ''getInfo'' with ''p2''-instance''s data console.log(p2.getInfo()); // Tom Harrison, 38!


function Test(){ this.prop1 = ''prop1''; this.prop2 = ''prop2''; this.func1 = function(){ return this.prop1 + this.prop2; } }; Test.prototype.protoProp1 = ''protoProp1''; Test.prototype.protoProp2 = ''protoProp2''; var newKeywordTest = new Test(); var objectCreateTest = Object.create(Test.prototype); /* Object.create */ console.log(objectCreateTest.prop1); // undefined console.log(objectCreateTest.protoProp1); // protoProp1 console.log(objectCreateTest.__proto__.protoProp1); // protoProp1 /* new */ console.log(newKeywordTest.prop1); // prop1 console.log(newKeywordTest.__proto__.protoProp1); // protoProp1

Resumen:

1) con la new palabra clave hay dos cosas a tener en cuenta;

a) la función se utiliza como un constructor

b) el objeto function.prototype se pasa a la propiedad __proto__ ... o donde __proto__ no se admite, es el segundo lugar donde el nuevo objeto busca propiedades.

2) con Object.create(obj.prototype) está construyendo un objeto ( obj.prototype ) y pasándolo al objeto deseado ... con la diferencia de que ahora el nuevo __proto__ del objeto también apunta a obj.prototype (por favor, ref. xj9 para eso)