Extender un objeto en Javascript

164

Actualmente me estoy transformando de Java a Javascript, y es un poco difícil para mí descubrir cómo extender los objetos de la manera que quiero.

He visto a varias personas en Internet usar un método llamado extender en objeto. El código se verá así:

var Person = {
   name : 'Blank',
   age  : 22
}

var Robot = Person.extend({
   name : 'Robo',
   age  : 4
)}

var robot = new Robot();
alert(robot.name); //Should return 'Robo'

¿Alguien sabe cómo hacer que esto funcione? He escuchado que necesitas escribir

Object.prototype.extend = function(...);

Pero no sé cómo hacer que este sistema funcione. Si no es posible, muéstrame otra alternativa que extienda un objeto.

Wituz
fuente
volver verdadero; pero es por eso que estoy preguntando :)
Wituz
2
Sugeriría pasar por este hermoso tutorial en MDN: - developer.mozilla.org/en/…
Pranav
Si después de leer esos buenos documentos todavía tiene curiosidad acerca de una extendfunción, he configurado un ejemplo aquí: jsfiddle.net/k9LRd
Codrin Eugeniu
2
También sugeriría que no piense en ello estrictamente como 'transformar de Java a JavaScript' y más como 'aprender un nuevo lenguaje, Javascript, que tiene una sintaxis similar a Java'
Toni Leigh

Respuestas:

195

Desea 'heredar' del objeto prototipo de la Persona:

var Person = function (name) {
    this.name = name;
    this.type = 'human';
};

Person.prototype.info = function () {
    console.log("Name:", this.name, "Type:", this.type);
};

var Robot = function (name) {
    Person.apply(this, arguments);
    this.type = 'robot';
};

Robot.prototype = Person.prototype;  // Set prototype to Person's
Robot.prototype.constructor = Robot; // Set constructor back to Robot

person = new Person("Bob");
robot = new Robot("Boutros");

person.info();
// Name: Bob Type: human

robot.info();
// Name: Boutros Type: robot
osahyoun
fuente
44
Tengo una pregunta: ¿cómo se Person()llama al constructor cuando lo haces new Robot()? Me parece que deberías llamar a ese constructor de clase base en lugar de hacerlo this.name = name;en el Robot()constructor ...
Alexis Wilke
21
@AlexisWilke: Sí, deberías llamar Person.apply(this, arguments);. También sería mejor usarlo en Robot.prototype = Object.create(Person.prototype);lugar de new Person();.
Felix Kling
18
Como dijo Felix, 'Robot.prototype = Person.prototype;' Es una mala idea si alguien desea que el tipo 'Robot' tenga su propia instancia de prototipo. Agregar nuevas funciones específicas de Robot también lo agregaría a persona.
James Wilkins
20
Este ejemplo es completamente incorrecto. Al hacerlo, altera el prototipo de Persona. Eso no es herencia y te arriesgas a poner un gran lío en la clase Persona. Vea la respuesta que recomienda usar Object.create (). Esa es la forma correcta de hacer las cosas.
nicolas-van
66
@osahyoun esta respuesta tiene un alto ranking en la búsqueda de google. Realmente te sugiero que arregles el código y corrijas la cadena del prototipo como lo sugieren otros comentarios aquí.
raphaëλ
103

Mundo sin la palabra clave "nueva".

Y una sintaxis más simple "en prosa" con Object.create ().

* Este ejemplo se actualiza para las clases de ES6.

En primer lugar, recuerde que Javascript es un lenguaje prototípico . No está basado en clases. Por lo tanto, escribir en forma prototípica expone su verdadera naturaleza y puede ser muy simple, similar a la prosa y poderoso.

TLDR;

const Person = { name: 'Anonymous' } // person has a name

const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'

No, no necesitas constructores, no hay newinstanciación ( lee por qué no deberías usarnew ), no super, no es gracioso __construct. Simplemente crea objetos y luego los extiende o transforma.

( Si conoce los captadores y establecedores, consulte la sección "Lecturas adicionales" para ver cómo este patrón le ofrece captadores y establecedores gratuitos de una manera que Javascript había pensado originalmente y cuán poderosos son ).

Sintaxis tipo prosa: prototipo base

const Person = {

   //attributes
   firstName : 'Anonymous', 
   lastName: 'Anonymous',
   birthYear  : 0,
   type : 'human',

   //methods
   name() { return this.firstName + ' ' + this.lastName },
   greet() {
       console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' )
   },
   age() {
      // age is a function of birth time.
   }
}

const person = Object.create(Person). // that's it!

De un vistazo, se ve muy legible.

Extensión, creando un descendiente de Person

* Los términos correctos son prototypes, y sus descendants. No hay classesy no hay necesidad de hacerlo instances.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'

const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true

Una forma de proporcionar una forma "predeterminada" de crear un descendant, es adjuntando un #createmétodo:

Skywalker.create = function(firstName, gender, birthYear) {

    let skywalker = Object.create(Skywalker)

    Object.assign(skywalker, {
        firstName,
        birthYear,
        gender,
        lastName: 'Skywalker',
        type: 'human'
    })

    return skywalker
}

const anakin = Skywalker.create('Anakin', 'male', '442 BBY')

Las siguientes formas tienen menor legibilidad:

Compare con el equivalente "clásico":

function Person (firstName, lastName, birthYear, type) {
    this.firstName = firstName 
    this.lastName = lastName
    this.birthYear = birthYear
    this.type = type
}

// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }

function Skywalker(firstName, birthYear) {
    Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}

// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker

const anakin = new Skywalker('Anakin', '442 BBY')

Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns false!

La legibilidad del código usando el estilo "clásico" no es tan bueno.

Clases ES6

Es cierto que algunos de estos problemas son erradicados por las clases ES6, pero aún así:

class Person {
    constructor(firstName, lastName, birthYear, type) {
        this.firstName = firstName 
        this.lastName = lastName
        this.birthYear = birthYear
        this.type = type
    }
    name() { return this.firstName + ' ' + this.lastName }
    greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}

class Skywalker extends Person {
    constructor(firstName, birthYear) {
        super(firstName, 'Skywalker', birthYear, 'human')
    }
}

const anakin = new Skywalker('Anakin', '442 BBY')

// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true

Ramificación del prototipo base

// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'
Robot.variant = '' // add properties for Robot prototype

Adjunte métodos únicos para Robot

// Robots speak in binaries, so we need a different greet function:
Robot.machineGreet = function() { /*some function to convert strings to binary */ }

// morphing the `Robot` object doesn't affect `Person` prototypes
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'
anakin.machineGreet() // error

Comprobando herencia

Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false

¡Ya tienes todo lo que necesitas! Sin constructores, sin instanciación. Prosa limpia y clara.

Otras lecturas

¡Posibilidad de escritura, configurabilidad y getters y setters gratuitos!

Para getters y setters gratuitos, o configuración adicional, puede usar el segundo argumento de Object.create () aka propertiesObject. También está disponible en # Object.defineProperty y # Object.defineProperties .

Para ilustrar cuán poderoso es esto, supongamos que queremos que todos Robotestén hechos estrictamente de metal (a través de writable: false) y estandarizar los powerConsumptionvalores (a través de getters y setters).

const Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    // getters and setters, how javascript had (naturally) intended.
    powerConsumption: {
        get() { return this._powerConsumption },
        set(value) { 
            if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k') 
            this._powerConsumption = value
            throw new Error('Power consumption format not recognised.')
        }  
    }
})

const newRobot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

Y todos los prototipos de Robotno pueden ser madeOfotra cosa porque writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

console.log(polymerRobot.madeOf) // outputs 'metal'

Mixins (usando # Object.assign) - Anakin Skywalker

¿Puedes sentir a dónde va esto ...?

const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.

Object.assign(darthVader, Robot)

Darth Vader obtiene los métodos de Robot:

darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...

Junto con otras cosas extrañas:

console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.

Bueno, si Darth Vader es hombre o máquina es realmente subjetivo:

"Ahora es más máquina que hombre, retorcido y malvado". - Obi-Wan Kenobi

"Sé que hay algo bueno en ti". - Luke Skywalker

Extra: sintaxis ligeramente más corta con # Object.assign

Con toda probabilidad, este patrón acorta su sintaxis. Pero ES6 # Object.assign puede acortar un poco más (para usar Polyfill en navegadores antiguos, consulte MDN en ES6 ).

//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal"
    // for brevity, you can imagine a long list will save more code.
})
Calvintwr
fuente
8
tener un voto positivo por no usar una función constructora.
nsmarks
1
programadores "con formación clásica", ¿qué quieres decir con eso?
Petra
1
Vengo de una mentalidad clásica de OOP y esta respuesta me ayudó mucho. Dos preguntas sobre el código: 1) ¿Es el ES2015 de hoy Object.assign(Robot, {a:1}una buena alternativa para su extend()método? 2) ¿Cómo anular el greet()método para que devuelva el mismo texto, pero con "una anulación de saludo" añadida?
Barry Staes
2
1) #Object.assignLooke como una buena alternativa. Pero el soporte del navegador es un cajero automático más bajo. 2) Utilizará la __proto__propiedad del objeto para acceder a la función de saludo de su prototipo. luego llama a la función de saludo prototipo con el alcance del destinatario pasado. en este caso, la función era un registro de consola, por lo que no es posible "agregar". Pero con este ejemplo, creo que entiendes la deriva. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr
1
Bueno, esa es una discusión que se debe tener con los mantenedores de la especificación del lenguaje ECMAScript. Generalmente estoy de acuerdo, pero tengo que trabajar con lo que tengo.
51

Si aún no ha descubierto una forma, use la propiedad asociativa de los objetos JavaScript para agregar una función de extensión a la Object.prototypeque se muestra a continuación.

Object.prototype.extend = function(obj) {
   for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
         this[i] = obj[i];
      }
   }
};

Luego puede usar esta función como se muestra a continuación.

var o = { member: "some member" };
var x = { extension: "some extension" };

o.extend(x);
tomilay
fuente
18
Tenga en cuenta que esto creará punteros al objeto original en la clase 'secundaria' cuando utilice objetos / matrices en la clase 'primaria'. Para elaborar: si tiene un objeto o una matriz en su clase principal, al modificarlo en una clase secundaria que se extiende sobre esa base, en realidad lo modificará para todas las clases secundarias que se extiendan sobre esta misma clase base.
Harold
Harold, gracias por resaltar ese hecho. Es importante que quien utilice la función incorpore una condición que verifique los objetos / matrices y haga copias de ellos.
tomilay
30

Enfoque diferente: Object.create

Según la respuesta de @osahyoun, encuentro lo siguiente como una forma mejor y eficiente de 'heredar' del objeto prototipo de la Persona:

function Person(name){
    this.name = name;
    this.type = 'human';
}

Person.prototype.info = function(){
    console.log("Name:", this.name, "Type:", this.type);
}

function Robot(name){
    Person.call(this, name)
    this.type = 'robot';
}

// Set Robot's prototype to Person's prototype by
// creating a new object that inherits from Person.prototype,
// and assigning it to Robot.prototype
Robot.prototype = Object.create(Person.prototype);

// Set constructor back to Robot
Robot.prototype.constructor = Robot;

Crear nuevas instancias:

var person = new Person("Bob");
var robot = new Robot("Boutros");

person.info(); // Name: Bob Type: human
robot.info();  // Name: Boutros Type: robot

Ahora, usando Object.create :

Person.prototype.constructor !== Robot

Consulte también la documentación de MDN .

Lior Elrom
fuente
2
Solo quiero decir @GaretClaborn que funciona correctamente, pero no está pasando el nameparámetro al constructor principal, como este: jsfiddle.net/3brm0a7a/3 (la diferencia está en la línea # 8)
xPheRe
1
@xPheRe Ah, ya veo, gracias. Edité la respuesta para reflejar ese cambio
Garet Claborn el
1
@xPheRe, creo que estaba más enfocado en probar un punto cuando agregué esta solución. Gracias.
Lior Elrom
1
Buena respuesta +1, puedes echar un vistazo a ECMAScript 6. La clase de palabras clave y las extensiones están disponibles: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Benjamin Poignant
26

En ES6 , puede usar el operador de propagación como

var mergedObj = { ...Obj1, ...Obj2 };

Tenga en cuenta que Object.assign () activa los establecedores, mientras que la sintaxis extendida no.

Para obtener más información, consulte el enlace, Sintaxis extendida de MDN


Vieja respuesta:

En ES6 , existe Object.assignpara copiar valores de propiedad. Úselo {}como primer parámetro si no desea modificar el objeto de destino (se aprobó el primer parámetro).

var mergedObj = Object.assign({}, Obj1, Obj2);

Para más detalles ver enlace, MDN - Object.assign ()

En caso de que necesite un Polyfill para ES5 , el enlace también lo ofrece. :)

KrIsHnA
fuente
18

Y otro año después, puedo decirte que hay otra buena respuesta.

Si no le gusta la forma en que funciona la creación de prototipos para extenderse en objetos / clases, observe esto: https://github.com/haroldiedema/joii

Código de ejemplo rápido de posibilidades (y muchos más):

var Person = Class({

    username: 'John',
    role: 'Employee',

    __construct: function(name, role) {
        this.username = name;
        this.role = role;
    },

    getNameAndRole: function() {
        return this.username + ' - ' + this.role;
    }

});

var Manager = Class({ extends: Person }, {

  __construct: function(name)
  {
      this.super('__construct', name, 'Manager');
  }

});

var m = new Manager('John');
console.log(m.getNameAndRole()); // Prints: "John - Manager"
Harold
fuente
Bueno, todavía tengo 2 meses hasta que pasen los 2 años: P De cualquier manera, JOII 3.0 está a punto de lanzarse :)
Harold
1
Haz eso 3 años después.
Concepto interesante, pero la sintaxis se ve muy fea. Sería mejor esperar a que las clases de ES6 se estabilicen
sleepycal
Estoy completamente de acuerdo @sleepycal. Pero desafortunadamente, pasarán al menos 5 años más antes de que todos los navegadores principales / comunes hayan implementado esto. Así que hasta ese momento, esto tendrá que hacer ...
Harold
12

Las personas que todavía están luchando por el enfoque simple y mejor, puede usar Spread Syntaxpara extender objetos.

var person1 = {
      name: "Blank",
      age: 22
    };

var person2 = {
      name: "Robo",
      age: 4,
      height: '6 feet'
    };
// spread syntax
let newObj = { ...person1, ...person2 };
console.log(newObj.height);

Nota: Recuerde que la propiedad más alejada a la derecha tendrá prioridad. En este ejemplo, person2está en el lado derecho, por newObjlo que tendrá el nombre Robo .

Ali Shahbaz
fuente
6

Mozilla 'anuncia' el objeto que se extiende desde ECMAScript 6.0:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends

NOTA: Esta es una tecnología experimental, parte de la propuesta ECMAScript 6 (Armonía).

class Square extends Polygon {
  constructor(length) {
    // Here, it calls the parent class' constructor with lengths
    // provided for the Polygon's width and height
    super(length, length);
    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.area = value;     } 
}

Esta tecnología está disponible en Gecko (Google Chrome / Firefox) - 03/2015 versiones nocturnas.

Niek Vandael
fuente
4

En la mayoría de los proyectos hay algunas implementaciones de extensión de objetos: subrayado, jquery, lodash: extender .

También existe una implementación de JavaScript puro, que forma parte de ECMAscript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Cezary Daniel Nowak
fuente
¿La "implementación de javascript puro" no se refiere a algo que se implementa solo con JavaScript, no a una función proporcionada por el entorno que podría implementarse de forma nativa?
binki
1
@binki, me refería a la implementación nativa de JavaScript - parte del estándar ECMAScript 2015 (ES6)
Cezary Daniel Nowak
2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Luego:

function Person() {
    this.name = "anonym"
    this.skills = ["abc"];
}
Person.prototype.profile = function() {
    return this.skills.length // 1
};

function Student() {} //well extends fom Person Class
Student.extends(Person)

var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

Actualización 01/2017:

Por favor, ignore mi respuesta de 2015 ya que Javascript ahora es compatible con extendspalabras clave desde ES6 (Ecmasctipt6)

- ES6:

class Person {
   constructor() {
     this.name = "anonym"
     this.skills = ["abc"];
   }

   profile() {
    return this.skills.length // 1
   }

}

Person.MAX_SKILLS = 10;
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

- ES7:

class Person {
    static MAX_SKILLS = 10;
    name = "anonym"
    skills = ["abc"];

    profile() {
      return this.skills.length // 1
    }

}
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2
Abdennour TOUMI
fuente
1
Al llamar new ParentClass()antes de sobrescribir el constructor, ya ha ejecutado el constructor principal. No creo que sea un comportamiento correcto si me preguntas ...
Harold
1

Resumen:

Javascript usa un mecanismo que se llama herencia prototípica . La herencia de prototipos se usa cuando se busca una propiedad en un objeto. Cuando estamos extendiendo propiedades en JavaScript, heredamos estas propiedades de un objeto real. Funciona de la siguiente manera:

  1. Cuando se solicita una propiedad de objeto (p. Ej. myObj.fooOmyObj['foo'] ) el motor JS primero buscará esa propiedad en el objeto mismo
  2. Cuando esta propiedad no se encuentra en el objeto en sí, subirá la mirada de la cadena prototipo al objeto prototipo. Si esta propiedad tampoco se encuentra aquí, seguirá escalando la cadena del prototipo hasta que se encuentre la propiedad. Si no se encuentra la propiedad, arrojará un error de referencia.

Cuando queremos extender desde un objeto en javascript, simplemente podemos vincular este objeto en la cadena del prototipo. Hay numerosas formas de lograr esto, describiré 2 métodos de uso común.

Ejemplos:

1) Object.create()

Object.create()es una función que toma un objeto como argumento y crea un nuevo objeto. El objeto que se pasó como argumento será el prototipo del objeto recién creado. Por ejemplo:

// prototype of the dog
const dogPrototype = {
  woof: function () { console.log('woof'); }
}

// create 2 dog objects, pass prototype as an argument
const fluffy = Object.create(dogPrototype);
const notFluffy = Object.create(dogPrototype);

// both newly created object inherit the woof 
// function from the dogPrototype
fluffy.woof();
notFluffy.woof();

2. Establecer explícitamente la propiedad del prototipo

Al crear objetos utilizando funciones de constructor, podemos establecer propiedades de agregar a su propiedad de objeto prototipo. Los objetos que se crean forman una función constructora cuando se usa la newpalabra clave, tienen su prototipo establecido en el prototipo de la función constructora. Por ejemplo:

// Constructor function object
function Dog (name) {
   name = this.name;
}

// Functions are just objects
// All functions have a prototype property
// When a function is used as a constructor (with the new keyword)
// The newly created object will have the consturctor function's
// prototype as its prototype property
Dog.prototype.woof = function () {
  console.log('woof');
}

// create a new dog instance
const fluffy = new Dog('fluffyGoodBoyyyyy');
// fluffy inherits the woof method
fluffy.woof();

// can check the prototype in the following manner
console.log(Object.getPrototypeOf(fluffy));

Willem van der Veen
fuente
0

Simplemente puede hacerlo usando:

Object.prototype.extend = function(object) {
  // loop through object 
  for (var i in object) {
    // check if the extended object has that property
    if (object.hasOwnProperty(i)) {
      // mow check if the child is also and object so we go through it recursively
      if (typeof this[i] == "object" && this.hasOwnProperty(i) && this[i] != null) {
        this[i].extend(object[i]);
      } else {
        this[i] = object[i];
      }
    }
  }
  return this;
};

actualización: lo comprobé this[i] != nullya que nulles un objeto

Luego úsalo como:

var options = {
      foo: 'bar',
      baz: 'dar'
    }

    var defaults = {
      foo: false,
      baz: 'car',
      nat: 0
    }

defaults.extend(options);

Esto da como resultado:

// defaults will now be
{
  foo: 'bar',
  baz: 'dar',
  nat: 0
}
Mustafa Dwekat
fuente
0

POR FAVOR AGREGUE LA RAZÓN PARA VOTAR

  • No es necesario utilizar ninguna biblioteca externa para ampliar

  • En JavaScript, todo es un objeto (excepto los tres tipos de datos primitivos, e incluso se envuelven automáticamente con objetos cuando es necesario). Además, todos los objetos son mutables.

Persona de clase en JavaScript

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    getName: function() {
        return this.name;
    },
    getAge: function() {
        return this.age;
    }
}

/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);

Modificar una instancia / objeto específico .

alice.displayGreeting = function() 
{
    alert(this.getGreeting());
}

Modificar la clase

Person.prototype.getGreeting = function() 
{
    return 'Hi ' + this.getName() + '!';
};

O simplemente diga: extender JSON y OBJECT son los mismos

var k = {
    name : 'jack',
    age : 30
}

k.gender = 'male'; /*object or json k got extended with new property gender*/

gracias a ross harmes, dustin diaz

vijay
fuente
-1

Esto hará que extender sus propiedades cree un nuevo Objeto con los prototipos de parámetros del objeto sin alterar el objeto pasado.

function extend(object) {
    if (object === null)
        throw TypeError;
    if (typeof object !== "object" && typeof object !== "function")
        throw TypeError;
    if (Object.create)
        return Object.create(object);
    function f() {}
    ;
    f.prototype = p;
    return new f();
}

Pero si desea extender su Objeto sin modificar sus parámetros, puede agregar extendProperty a su objeto.

var Person{
//some code
extend: extendProperty
}

//Enforce type checking an Error report as you wish
    function extendProperty(object) {
        if ((object !== null && (typeof object === "object" || typeof object === "function"))){
            for (var prop in object) {
                if (object.hasOwnProperty(prop))
                    this[prop] = object[prop];
            }
        }else{
            throw TypeError; //Not an object
        }
    }
Ndifreke
fuente
-2

La creación de prototipos es una buena manera, pero el prototipo es bastante peligroso a veces y puede provocar errores. Prefiero encapsular esto en un objeto base, como lo hace Ember.js con Ember.Object.extend y Ember.Object.reopen. Eso es mucho más seguro de usar.

Creé una idea general de cómo configurarías algo similarCreé una idea general de a lo que usa Ember.Object.

Aquí está el enlace: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

Vinicius Dallacqua
fuente
9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.¿Qué quieres decir con eso? ¿Usar la cadena de prototipos en JavaScript puede generar errores? Es como decir que usar clases en Java puede generar errores y no tiene ningún sentido.
HMR
@HMR dice que extender los prototipos de objetos proporcionados por el entorno da como resultado un código frágil que podría entrar en conflicto con una función futura del lenguaje JavaScript central. Si agrega una función de utilidad útil a todo al extender Objectel prototipo, su función podría tener el mismo nombre que una futura función de JavaScript y hacer que su código explote cuando se ejecute en el futuro. Por ejemplo, supongamos que agregó una repeat()función Objecty la llamó en Stringinstancias y luego su tiempo de ejecución de JavaScript se actualizó a ES6.
binki
@binki Gracias por tu aporte. Estás hablando de cambiar el prototipo de clases que no "posees" y, por lo tanto, romper la referencia de encapsulación: developer.mozilla.org/en/docs/Web/JavaScript/… JS no tiene variables privadas, por lo que tu API expone miembros de implementación , que generalmente se resuelve por convención (iniciar el nombre del miembro con guión bajo). No estoy seguro de si ese es el principal problema que tiene el operador o si la sintaxis es confusa y mucha gente no lo entiende.
HMR
@HMR, puedo estar equivocado, pero creo que "pero el prototipo es bastante peligroso" se refiere al infame marco de prototipos que podría abusar de la prototypefunción del lenguaje .
binki
La creación de prototipos es peligrosa porque si usa objetos que no creó, no siempre sabe cuáles serán los efectos secundarios de usarlos como prototipos. Mira este violín, por ejemplo: jsfiddle.net/fo6r20rg
Arkain