Estendendo um Objeto em Javascript

164

Atualmente, estou transformando de Java para Javascript, e é um pouco difícil para mim descobrir como estender os objetos da maneira que eu quero.

Eu já vi várias pessoas na internet usarem um método chamado estender no objeto. O código ficará assim:

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

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

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

Alguém sabe como fazer isso funcionar? Ouvi dizer que você precisa escrever

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

Mas não sei como fazer esse sistema funcionar. Se não for possível, mostre-me outra alternativa que estenda um objeto.

Wituz
fonte
return true; mas é por isso que eu estou pedindo :)
Wituz
2
eu sugeriria passar por este belo tutorial no MDN: - developer.mozilla.org/en/…
Pranav
Se depois de ler esses bons docs você ainda está curioso sobre uma extendfunção, eu configurar um exemplo aqui: jsfiddle.net/k9LRd
Codrin Eugeniu
2
Eu também sugerem não pensar nisso estritamente como 'transformando de Java para JavaScript' e mais como 'aprender uma nova língua, Javascript, que tem uma sintaxe semelhante ao Java'
Toni Leigh

Respostas:

195

Você deseja 'herdar' do objeto de protótipo da Pessoa:

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
fonte
4
Eu tenho uma pergunta: como o Person()construtor está sendo chamado quando você faz isso new Robot()? Parece-me que você deve chamar esse construtor da classe base em vez de fazer this.name = name;no Robot()construtor ...
Alexis Wilke
21
@AlexisWilke: Sim, você deve ligar Person.apply(this, arguments);. Também seria melhor usar em Robot.prototype = Object.create(Person.prototype);vez de new Person();.
Felix Kling
18
Conforme declarado por Felix, 'Robot.prototype = Person.prototype;' é uma má ideia se alguém desejar que o tipo 'Robot' tenha sua própria instância de protótipo. Adicionar novas funções específicas do robô também o adicionaria pessoalmente.
James Wilkins
20
Este exemplo está completamente errado. Ao fazer isso, você altera o protótipo de Pessoa. Isso não é herança e você corre o risco de colocar uma enorme bagunça na classe Person. Veja a resposta que recomenda o uso de Object.create (). Essa é a maneira correta de fazer as coisas.
nicolas-van
6
@osahyoun Esta resposta tem uma classificação alta na pesquisa do Google. Eu realmente sugiro que você corrija o código e corrija a cadeia de protótipos, conforme sugerido por outros comentários aqui.
Raphaëλ 22/01
102

Mundo sem a "nova" palavra-chave.

E mais simples sintaxe "tipo prosa" com Object.create ().

* Este exemplo é atualizado para as classes ES6.

Primeiro, lembre-se de que o Javascript é uma linguagem prototípica . Não é baseado em classe. Portanto, escrever em forma de protótipo expõe sua verdadeira natureza e pode ser muito simples, parecido com uma prosa e 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'

Não, você não precisa de construtores, nenhuma newinstanciação ( leia por que você não deve usarnew ), não super, nada engraçado __construct. Você simplesmente cria objetos e depois os estende ou transforma.

( Se você souber sobre getters e setters, consulte a seção "Leitura adicional" para ver como esse padrão oferece getters e setters gratuitos da maneira que o Javascript originalmente pretendia, e quão poderosos eles são .)

Sintaxe em forma de prosa: protótipo de 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!

À primeira vista, parece muito legível.

Extensão, criando um descendente de Person

* Os termos corretos são prototypese os deles descendants. Não há classese não há necessidade 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

Uma maneira de fornecer uma maneira "padrão" de criar a descendanté anexando um #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')

As maneiras abaixo têm menor legibilidade:

Compare com o equivalente "clássico":

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!

A legibilidade do código usando o estilo "clássico" não é tão boa.

Classes ES6

É certo que alguns desses problemas são erradicados pelas classes ES6, mas ainda assim:

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

Ramificação do protótipo de 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

Anexar métodos exclusivos 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

Verificando herança

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

Você já tem tudo o que precisa! Sem construtores, sem instanciação. Prosa limpa e clara.

Leitura adicional

Gravabilidade, configurabilidade e getters e setters gratuitos!

Para getters e setters gratuitos, ou configuração extra, você pode usar o segundo argumento de Object.create (), conhecido como propertiesObject. Também está disponível em # Object.defineProperty e # Object.defineProperties .

Para ilustrar o quão poderoso isso é, suponha que queremos que todos Robotsejam estritamente feitos de metal (via writable: false) e padronize powerConsumptionvalores (via getters e 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

E todos os protótipos de Robotnão podem ser madeOfoutra coisa porque writable: false.

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

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

Mixins (usando # Object.assign) - Anakin Skywalker

Você pode sentir para onde isso está indo ...?

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

Object.assign(darthVader, Robot)

Darth Vader obtém os métodos de Robot:

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

Juntamente com outras coisas estranhas:

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

Bem, se Darth Vader é homem ou máquina é realmente subjetivo:

"Ele é mais máquina agora do que homem, distorcido e mal." - Obi wan Kenobi

"Eu sei que há algo bom em você." - Luke Skywalker

Extra - sintaxe um pouco mais curta com # Object.assign

Com toda a probabilidade, esse padrão reduz sua sintaxe. Porém, o ES6 # Object.assign pode reduzir um pouco mais (para o polyfill usar em navegadores mais antigos, consulte MDN no 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
fonte
8
tenha um voto positivo por não usar uma função construtora.
Nsmarks
1
programadores com formação clássica, o que você quer dizer com isso?
Petra
1
Eu venho de uma mentalidade clássica de POO e essa resposta me ajudou muito. Duas perguntas sobre o código: 1) O ES2015 de hoje é Object.assign(Robot, {a:1}uma boa alternativa para o seu extend()método? 2) Como substituir o greet()método para que ele retorne o mesmo texto, mas com "uma substituição de saudação" anexada?
Barry Staes
2
1) #Object.assignparece uma boa alternativa. Mas o suporte ao navegador é menor. 2) Você usará a __proto__propriedade do objeto para acessar a função greet do seu protótipo. então você chama a função protótipo greet com o escopo do receptor transmitido. Nesse caso, a função era um log do console; portanto, não é possível "anexar". Mas com este exemplo, acho que você entendeu. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr #
1
Bem, essa é uma discussão que deve ser realizada com os mantenedores da Especificação de Linguagem ECMAScript. Eu geralmente concordo, mas tenho que trabalhar com o que tenho.
51

Se você ainda não descobriu uma maneira, use a propriedade associativa dos objetos JavaScript para adicionar uma função de extensão à, Object.prototypecomo mostrado abaixo.

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

Você pode usar esta função como mostrado abaixo.

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

o.extend(x);
amanhã
fonte
18
Lembre-se de que isso criará ponteiros para o objeto original na classe 'filho' ao usar objetos / matrizes na classe 'pai'. Para elaborar: Se você tiver um objeto ou matriz em sua classe pai, modificá-lo em uma classe filho que se estende nessa base, na verdade o modificará para todas as classes filho que se estendem nessa mesma classe base.
Harold
Harold, Obrigado por destacar esse fato. É importante para quem usa a função incorporar uma condição que verifique se há objetos / matrizes e faça cópias deles.
tomilay
30

Abordagem diferente: Object.create

Por resposta da @osahyoun, considero o seguinte como uma maneira melhor e eficiente de 'herdar' do objeto de protótipo de Person:

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;

Crie novas instâncias:

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

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

Agora, usando Object.create :

Person.prototype.constructor !== Robot

Verifique também a documentação do MDN .

Lior Elrom
fonte
2
Só quero dizer @GaretClaborn ele funciona corretamente, mas você não está passando o nameparâmetro para o construtor pai, como este: jsfiddle.net/3brm0a7a/3 (diferença está na linha # 8)
xPheRe
1
@xPheRe Ah eu vejo, obrigado. Eu editei a resposta para refletir essa mudança
Garet Claborn
1
@ xPheRe, acho que estava mais focado em provar um ponto quando adicionei esta solução. Obrigado.
Lior Elrom 24/03
1
Agradável resposta +1, você pode dar uma olhada para ECMAScript 6. Palavras-chave classe e se estende está disponível: developer.mozilla.org/en-US/docs/Web/JavaScript/...
Benjamin Poignant
26

No ES6 , você pode usar o operador spread como

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

Observe que Object.assign () aciona setters, enquanto a sintaxe de propagação não.

Para obter mais informações, consulte o link MDN -Spread Syntax


Resposta antiga:

No ES6 , existe Object.assignpara copiar valores de propriedades. Use {}como primeiro parâmetro se não desejar modificar o objeto de destino (o primeiro parâmetro passou).

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

Para mais detalhes, consulte o link MDN - Object.assign ()

Caso você precise de um Polyfill para ES5 , o link também o oferece. :)

KrIsHnA
fonte
18

E outro ano depois, posso dizer que há outra resposta legal.

Se você não gosta da maneira como a prototipagem funciona para se estender a objetos / classes, veja o seguinte: https://github.com/haroldiedema/joii

Exemplo rápido de código de possibilidades (e muito mais):

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
fonte
Bem, eu ainda tenho 2 meses até que os 2 anos estão acima: P De qualquer maneira, JOII 3.0 está prestes a liberação :)
Harold
1
Faça isso 3 anos depois.
Conceito interessante, mas a sintaxe parece muito feia. Você seria melhor fora esperando para classes ES6 para tornar-se estável
sleepycal
Concordo plenamente @sleepycal. Infelizmente, levará pelo menos mais cinco anos para que todos os navegadores principais / comuns implementem isso. Então, até esse momento, este terá que fazer ...
Harold
12

Pessoas que ainda lutam pela abordagem simples e melhor, você pode usar Spread Syntaxpara estender o objeto.

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: Lembre - se de que a propriedade que estiver mais à direita terá prioridade. Neste exemplo, person2está do lado direito, então newObjterá o nome Robo .

Ali Shahbaz
fonte
6

O Mozilla 'anuncia' o objeto que se estende do ECMAScript 6.0:

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

NOTA: Essa é uma tecnologia experimental, parte da proposta do ECMAScript 6 (Harmony).

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 tecnologia está disponível no Gecko (Google Chrome / Firefox) - compilações noturnas de 03/2015.

Niek Vandael
fonte
4

Na maioria dos projetos, há alguma implementação de extensão de objeto: sublinhado, jquery, lodash: extensão .

Também existe uma implementação javascript pura, que faz parte do ECMAscript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Cezary Daniel Nowak
fonte
“Implementação pura de javascript” não se refere a algo implementado apenas com JavaScript, e não a uma função fornecida pelo ambiente que pode ser implementada nativamente?
binki
1
@binki, eu quis dizer implementação javascript nativa - parte do ECMAScript 2015 (ES6) padrão
Cezary Daniel Nowak
2
Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

Então:

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

Atualização 01/2017:

Ignore minha resposta de 2015, já que o Javascript agora suporta extendspalavras-chave 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
fonte
1
Ao chamar new ParentClass()antes de substituir o construtor, você já executou o construtor pai. Eu não acho que isso é o comportamento correto se você me perguntar ...
Harold
1

Resumo:

Javascript usa um mecanismo que é chamado de herança prototípica . A herança prototípica é usada ao procurar uma propriedade em um objeto. Quando estamos estendendo propriedades em javascript, estamos herdando essas propriedades de um objeto real. Funciona da seguinte maneira:

  1. Quando uma propriedade de objeto é solicitada, (por exemplo, myObj.fooou myObj['foo']), o mecanismo JS primeiro procurará essa propriedade no próprio objeto
  2. Quando essa propriedade não for encontrada no próprio objeto, ela escalará a cadeia de protótipos para o objeto de protótipo. Se essa propriedade também não for encontrada aqui, ela continuará subindo a cadeia de protótipos até que a propriedade seja encontrada. Se a propriedade não for encontrada, lançará um erro de referência.

Quando queremos estender a partir de um objeto em javascript, podemos simplesmente vincular esse objeto na cadeia de protótipos. Existem várias maneiras de conseguir isso, descreverei 2 métodos comumente usados.

Exemplos:

1 Object.create()

Object.create()é uma função que aceita um objeto como argumento e cria um novo objeto. O objeto que foi passado como argumento será o protótipo do objeto recém-criado. Por exemplo:

// 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. Definindo explicitamente a propriedade prototype

Ao criar objetos usando funções de construtor, podemos definir propriedades de adição à sua propriedade de objeto de protótipo. Os objetos criados formam uma função construtora ao usar a newpalavra - chave, com seu protótipo definido para o protótipo da função construtora. Por exemplo:

// 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
fonte
0

Você pode simplesmente fazer isso 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;
};

update: eu verifiquei this[i] != nullpois nullé um objeto

Em seguida, use-o como:

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

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

defaults.extend(options);

Isso também resulta em:

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

POR FAVOR, ADICIONE RAZÃO PARA DOWNVOTE

  • Não há necessidade de usar nenhuma biblioteca externa para estender

  • No JavaScript, tudo é um objeto (exceto os três tipos de dados primitivos, e mesmo eles são agrupados automaticamente com os objetos quando necessário). Além disso, todos os objetos são mutáveis.

Pessoa da classe em 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);

Modifique uma instância / objeto específico .

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

Modifique a classe

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

Ou simplesmente diga: estender JSON e OBJECT ambos são iguais

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

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

graças a ross harmes, dustin diaz

vijay
fonte
-1

Isso fará com que estender suas propriedades crie um novo objeto com os protótipos de parâmetro de objeto sem alterar o objeto passado.

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();
}

Mas se você deseja estender seu Objeto sem modificá-lo, pode adicionar extendProperty ao seu 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
fonte
-2

A criação de protótipos é uma maneira agradável, mas o protótipo às vezes é bastante perigoso e pode levar a erros. Eu prefiro encapsular isso em um objeto base, como o Ember.js faz com o Ember.Object.extend e o Ember.Object.reopen. Isso é muito mais seguro de usar.

Eu criei uma essência com como você configuraria algo semelhante ao que o Ember.Object usa.

Aqui está o link: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd

Vinicius Dallacqua
fonte
9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.O que você quer dizer com isso? Usar a cadeia de protótipos em JavaScript pode levar a erros? É como dizer que o uso de classes em Java pode levar a erros e não faz absolutamente nenhum sentido.
HMR 31/07
@HMR ele está dizendo que estender protótipos de objetos fornecidos pelo ambiente resulta em código frágil que pode entrar em conflito com um recurso futuro da linguagem JavaScript principal. Se você adicionar uma função útil de utilidade a tudo estendendo Objecto protótipo, sua função poderá ter o mesmo nome que uma futura função JavaScript e fazer com que seu código exploda quando executado no futuro. Por exemplo, digamos que você adicionou uma repeat()função Objecte a chamou em Stringinstâncias e, em seguida, seu tempo de execução JavaScript foi atualizado para o ES6?
binki
@binki Obrigado pela sua contribuição. Você está falando sobre alterar o protótipo de classes que você "não possui" e, assim, quebrar a referência de encapsulamento: developer.mozilla.org/en/docs/Web/JavaScript/… JS não possui variáveis ​​privadas, portanto sua API expõe membros de implementação , isso geralmente é resolvido por convenção (inicie o nome do membro com sublinhado). Não tenho certeza se esse é o principal problema da operação ou se a sintaxe é confusa e muitas pessoas não a entendem.
HMR
@HMR, posso estar errado, mas acho que “mas protótipo é bastante perigoso” refere-se à infame estrutura de protótipo que pode abusar do prototyperecurso de linguagem .
binki
A prototipagem é perigosa porque se você estiver usando objetos que não criou, nem sempre sabe quais serão os efeitos colaterais de usá-los como protótipos. Veja este violino, por exemplo: jsfiddle.net/fo6r20rg
Arkain 13/11/2015