Padrão OLOO de Kyle Simpson vs. Padrão de Design de Protótipo

109

O "Padrão OLOO (Objetos Vinculados a Outros Objetos)" de Kyle Simpson difere de alguma forma do padrão de projeto Prototype? Além de cunhá-lo por algo que indica especificamente "vinculação" (o comportamento dos protótipos) e esclarecendo que não há "cópia" acontecendo aqui (um comportamento das classes), o que exatamente seu padrão apresenta?

Aqui está um exemplo do padrão de Kyle em seu livro, "You Don't Know JS: this & Object Prototypes":

var Foo = {
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."
shmuli
fonte
2
Você pode pelo menos criar um link para uma descrição do padrão sobre o qual está perguntando. Melhor ainda seria mostrar um exemplo de código em sua pergunta.
jfriend00
4
Getify está no Stackoverflow às vezes. Eu enviei esta pergunta para ele :)
Pontudo,

Respostas:

155

o que exatamente seu padrão apresenta?

O OLOO abraça a cadeia de protótipo como ela é, sem a necessidade de sobrepor outras semânticas (confusas de IMO) para obter a ligação.

Portanto, esses dois trechos têm o mesmo resultado EXATA, mas chegam lá de forma diferente.

Forma do construtor:

function Foo() {}
Foo.prototype.y = 11;

function Bar() {}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.z = 31;

var x = new Bar();
x.y + x.z;  // 42

Formulário OLOO:

var FooObj = { y: 11 };

var BarObj = Object.create(FooObj);
BarObj.z = 31;

var x = Object.create(BarObj);
x.y + x.z;  // 42

Em ambos os trechos, um xobjeto é [[Prototype]]vinculado a um objeto ( Bar.prototypeou BarObj), que por sua vez está vinculado a um terceiro objeto ( Foo.prototypeou FooObj).

Os relacionamentos e delegação são idênticos entre os snippets. O uso de memória é idêntico entre os snippets. A capacidade de criar muitos "filhos" (também conhecido como muitos objetos como x1through x1000, etc) é idêntica entre os snippets. O desempenho da delegação ( x.ye x.z) é idêntico entre os snippets. O desempenho de criação de objeto é mais lento com OLOO, mas a verificação de integridade que revela que o desempenho mais lento não é realmente um problema.

O que eu argumento que o OLOO oferece é que é muito mais simples apenas expressar os objetos e vinculá-los diretamente, do que vinculá-los indiretamente por meio do construtor / newmecanismos. O último finge ser sobre classes, mas na verdade é apenas uma sintaxe terrível para expressar delegação ( nota lateral: aclass sintaxe ES6 também !).

OLOO está apenas eliminando o intermediário.

Aqui está outra comparação de classvs OLOO.

Kyle Simpson
fonte
2
Achei muito interessante sua resposta e a ideia de OLOO descrita em seus livros, gostaria de ter seu feedback sobre esta questão: stackoverflow.com/questions/40395762/… Especialmente se você achou esta implementação correta e como resolver o problema relacionado ao acesso membro privado. Obrigado pelo seu tempo e parabéns pelo seu último livro.
GibboK
Mas Object.create(...)é muitas vezes mais lento do que new. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…
Píer
3
@Pier o desempenho não é realmente um grande problema. consertou o link da postagem do blog quebrado sobre a verificação de sanidade do desempenho da criação de objetos, o que explica como pensar sobre isso de maneira adequada.
Kyle Simpson de
2
E o jQuery é mais lento do que a API DOM, certo? Mas, é o ano em curso, cara - prefiro escrever de forma elegante e simples do que me preocupar com a otimização. Se eu precisar microotimizar mais tarde, vou me preocupar com isso quando chegar a hora.
Eirik Birkeland,
6
Eu gostaria de acrescentar que agora, pouco mais de um ano depois, Object.create () é altamente otimizado em cromo, e que jsperf mostra isso - é uma das opções mais rápidas agora. Isso mostra exatamente por que você não deve se preocupar com essas micro-otimizações e, em vez disso, apenas escrever um código de som algoritmicamente.
Kyle Baker
25

Eu li o livro de Kyle e o achei muito informativo, especialmente os detalhes sobre como thisé encadernado.

Prós:

Para mim, existem alguns grandes prós do OLOO:

1. Simplicidade

O OLOO depende da Object.create()criação de um novo objeto que é [[prototype]]vinculado a outro objeto. Você não precisa entender que as funções têm uma prototypepropriedade ou se preocupar com qualquer uma das armadilhas potenciais relacionadas que vêm de sua modificação.

2. Sintaxe mais limpa

Isso é discutível, mas acho que a sintaxe OLOO é (em muitos casos) mais organizada e concisa do que a abordagem javascript 'padrão', especialmente quando se trata de polimorfismo ( superchamadas de estilo).

Contras:

Acho que há uma parte questionável do design (que realmente contribui para o ponto 2 acima), e isso tem a ver com sombreamento:

Na delegação de comportamento, evitamos, se possível, nomear as coisas iguais em diferentes níveis da [[Prototype]]cadeia.

A ideia por trás disso é que os objetos têm suas próprias funções mais específicas que, então, são delegadas internamente a funções mais abaixo na cadeia. Por exemplo, você pode ter um resourceobjeto com uma save()função que envia uma versão JSON do objeto para o servidor, mas também pode ter um clientResourceobjeto que tem uma stripAndSave()função, que primeiro remove propriedades que não deveriam ser enviadas ao servidor .

O problema potencial é: se alguém vier e decidir fazer um specialResourceobjeto, não totalmente ciente de toda a cadeia de protótipos, eles podem razoavelmente * decidir salvar um carimbo de data / hora para o último salvamento em uma propriedade chamada save, que obscurece a save()funcionalidade básica o resourceobjeto dois liga-se à cadeia de protótipo:

var resource = {
  save: function () { 
    console.log('Saving');
  }
};

var clientResource = Object.create(resource);

clientResource.stripAndSave = function () {
  // Do something else, then delegate
  console.log('Stripping unwanted properties');
  this.save();
};

var specialResource = Object.create( clientResource );

specialResource.timeStampedSave = function () {
  // Set the timestamp of the last save
  this.save = Date.now();
  this.stripAndSave();
};

a = Object.create(clientResource);
b = Object.create(specialResource);

a.stripAndSave();    // "Stripping unwanted properties" & "Saving".
b.timeStampedSave(); // Error!

Este é um exemplo particularmente artificial, mas a questão é que, especificamente, não sombrear outras propriedades pode levar a algumas situações embaraçosas e ao uso intenso de um dicionário de sinônimos!

Talvez uma ilustração melhor disso seja um initmétodo - particularmente comovente, já que o OOLO evita as funções do tipo construtor. Uma vez que cada objeto relacionado provavelmente precisará dessa função, pode ser um exercício tedioso nomeá-los de maneira apropriada, e a exclusividade pode dificultar a lembrança de qual usar.

* Na verdade, não é particularmente razoável ( lastSavedseria muito melhor, mas é apenas um exemplo).

Ed Hinchliffe
fonte
23
Eu concordo que o potencial para conflitos de nomes é uma desvantagem ... mas na verdade é uma desvantagem do [[Prototype]]próprio sistema, não especificamente do OLOO.
Kyle Simpson de
Talvez isso também devesse ter sido mencionado no livro?
aluga
Não tenho certeza se esta é realmente uma solução para o problema que @Ed Hinchliffe descreve, já que ele apenas move save () para seu próprio namespace, mas funciona codepen.io/tforward/pen/govEPr?editors=1010
Tristan Forward
Acho que @ ed-hinchliffe significava em b.timeStampedSave();vez de a.timeStampedSave();na última linha do trecho de código.
amangpt777
1
@tristan-forward, obrigado por trazer Rick e Morty para isso!
Eric Bishard
13

A discussão em "You Don't Know JS: this & Object Prototypes" e a apresentação do OLOO são instigantes e eu aprendi muito lendo o livro. Os méritos do padrão OLOO são bem descritos nas outras respostas; no entanto, tenho as seguintes queixas de animais de estimação com ele (ou estou faltando algo que me impede de aplicá-lo com eficácia):

1

Quando uma "classe" "herda" outra "classe" no padrão clássico, as duas funções podem ser declaradas sintaxe semelhante ( "declaração de função" ou "instrução de função" ):

function Point(x,y) {
    this.x = x;
    this.y = y;
};

function Point3D(x,y,z) {
    Point.call(this, x,y);
    this.z = z;
};

Point3D.prototype = Object.create(Point.prototype);

Em contraste, no padrão OLOO, diferentes formas sintáticas usadas para definir a base e os objetos derivados:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = Object.create(Point);
Point3D.init = function(x,y,z) {
    Point.init.call(this, x, y);
    this.z = z;
};

Como você pode ver no exemplo acima, o objeto base pode ser definido usando a notação literal do objeto, enquanto a mesma notação não pode ser usada para o objeto derivado. Essa assimetria me incomoda.

2

No padrão OLOO, a criação de um objeto consiste em duas etapas:

  1. ligar Object.create
  2. chame algum método personalizado não padrão para inicializar o objeto (que você deve se lembrar, pois pode variar de um objeto para o outro):

     var p2a = Object.create(Point);
    
     p2a.init(1,1);

Em contraste, no padrão Prototype você usa o operador padrão new :

var p2a = new Point(1,1);

3

No padrão clássico, posso criar funções de utilidade "estáticas" que não se aplicam diretamente a um "instante" atribuindo-as diretamente à função de "classe" (em oposição à sua .prototype). Por exemplo, função semelhante squareno código abaixo:

Point.square = function(x) {return x*x;};

Point.prototype.length = function() {
    return Math.sqrt(Point.square(this.x)+Point.square(this.y));
};

Em contraste, no padrão OLOO, quaisquer funções "estáticas" estão disponíveis (por meio da cadeia [[protótipo]]) nas instâncias do objeto:

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    },
    square: function(x) {return x*x;},
    length: function() {return Math.sqrt(Point.square(this.x)+Point.square(this.y));}
};
Marcus Junius Brutus
fonte
2
Não há literais em seu primeiro exemplo de código. Você provavelmente está usando mal o termo "literal", dando-lhe outro significado. Apenas dizendo ...
Ivan Kleshnin
2
Com relação ao segundo ponto, o autor argumenta que é uma "melhor" separação de interesses ter criação e inicialização separadas e cita que pode haver algum caso de uso raro em que isso pode brilhar (por exemplo, um pool de objetos). Acho o argumento terrivelmente fraco.
aluga
2
Novamente com relação ao segundo ponto, com OLOO, você pode criar seus objetos de uma vez e esperar para inicializar, enquanto com o construtor, você tem que inicializar na criação, então Kyle considera isso um benefício.
taco
5

"Achei que fazer isso tornaria cada obj dependente um do outro"

Como Kyle explica quando dois objetos estão [[Prototype]]vinculados, eles não são realmente dependentes um do outro; em vez disso, são objetos individuais. Você está ligando um objeto a outro com uma [[Prototype]]ligação que pode ser alterada a qualquer momento que desejar. Se você considerar dois [[Prototype]]objetos vinculados criados por meio do estilo OLOO como sendo dependentes um do outro, também deverá pensar o mesmo sobre os criados por meio de constructorchamadas.

var foo= {},
    bar= Object.create(foo),
    baz= Object.create(bar);


console.log(Object.getPrototypeOf(foo)) //Object.prototype

console.log(Object.getPrototypeOf(bar)) //foo

console.log(Object.getPrototypeOf(baz)) //bar

Agora pense por um segundo que você pensa foo bare bazcomo sendo dependente um do outro?

Agora vamos fazer o mesmo com este constructorcódigo de estilo

function Foo() {}

function Bar() {}

function Baz() {}

Bar.prototype= Object.create(Foo);
Baz.prototype= Object.create(Bar);

var foo= new Foo(),
    bar= new Bar().
    baz= new Baz();

console.log(Object.getPrototypeOf(foo)) //Foo.prototype
console.log(Object.getPrototypeOf(Foo.prototype)) //Object.prototype

console.log(Object.getPrototypeOf(bar)) //Bar.prototype
console.log(Object.getPrototypeOf(Bar.prototype)) //Foo.prototype

console.log(Object.getPrototypeOf(baz)) //Baz.prototype
console.log(Object.getPrototypeOf(Baz.prototype)) //Bar.prototype

A única diferença b / w o último e o primeiro código é que no caso deste último foo, bar, bazbbjects estão ligados a cada um-a outra através de objectos arbitrários da sua constructorfunção ( Foo.prototype, Bar.prototype, Baz.prototype) mas no ex um ( OLOOestilo) que estão ligadas directamente. Ambas as maneiras que você está apenas ligando foo, bar, bazuns com os outros, diretamente na antiga um e indiretamente no último. Mas, em ambos os casos, os objetos são independentes um do outro porque não é realmente como uma instância de qualquer classe que, uma vez instanciada, não pode ser herdada de alguma outra classe. Você sempre pode alterar qual objeto um objeto deve delegar também.

var anotherObj= {};
Object.setPrototypeOf(foo, anotherObj);

Portanto, são todos independentes uns dos outros.

"Eu esperava OLOOresolver o problema em que cada objeto não sabe nada sobre o outro."

Sim, isso é realmente possível-

Vamos usar Techcomo um objeto utilitário

 var Tech= {
     tag: "technology",
     setName= function(name) {
              this.name= name;
}
}

crie quantos objetos desejar vinculados Tech-

var html= Object.create(Tech),
     css= Object.create(Tech),
     js= Object.create(Tech);

Some checking (avoiding console.log)- 

    html.isPrototypeOf(css); //false
    html.isPrototypeOf(js); //false

    css.isPrototypeOf(html); //false
    css.isPrototypeOf(js); //false

    js.isPrototypeOf(html); //false
    js.isPrototypwOf(css); //false

    Tech.isPrototypeOf(html); //true
    Tech.isPrototypeOf(css); //true
    Tech.isPrototypeOf(js); //true

Você acha que html, css, jsobjetos estão conectados uns aos-outros? Não, eles não são. Agora vamos ver como poderíamos ter feito isso com a constructorfunção

function Tech() { }

Tech.prototype.tag= "technology";

Tech.prototype.setName=  function(name) {
              this.name= name;
}

crie quantos objetos desejar vinculados Tech.proptotype-

var html= new Tech(),
     css= new Tech(),
      js= new Tech();

Algumas verificações (evitando console.log) -

html.isPrototypeOf(css); //false
html.isPrototypeOf(js); //false

css.isPrototypeOf(html); //false
css.isPrototypeOf(js); //false

js.isPrototypeOf(html); //false
js.isPrototypeOf(css); //false

Tech.prototype.isPrototypeOf(html); //true
Tech.prototype.isPrototypeOf(css); //true
Tech.prototype.isPrototypeOf(js); //true

Como você acha que esses constructorobjetos -estilo ( html, css, js) Objetos diferente do OLOOcódigo de estilo? Na verdade, eles têm o mesmo propósito. No OLOOestilo, um objeto delega Tech(a delegação foi definida explicitamente), enquanto no constructorestilo um objeto é delegado Tech.prototype(a delegação foi definida implicitamente). No final das contas, você acaba ligando os três objetos, sem ligação entre si, a um objeto, usando diretamente OLOO-style, indiretamente usando constructor-style.

"Como está, ObjB deve ser criado a partir de ObjA .. Object.create (ObjB) etc"

Não, ObjBaqui não é como uma instância (em linguagens clássicas) de qualquer classe ObjA. Deve-se dizer que o objBobjeto é delegado ao ObjAobjeto no momento de sua criação " . Se você usasse o construtor, teria feito o mesmo 'acoplamento', embora indiretamente usando .prototypes.

Abhishek Sachan
fonte
3

@Marcus @bholben

Talvez possamos fazer algo assim.

    const Point = {

        statics(m) { if (this !== Point) { throw Error(m); }},

        create (x, y) {
            this.statics();
            var P = Object.create(Point);
            P.init(x, y);
            return P;
        },

        init(x=0, y=0) {
            this.x = x;
            this.y = y;
        }
    };


    const Point3D = {

        __proto__: Point,

        statics(m) { if (this !== Point3D) { throw Error(m); }},

        create (x, y, z) {
            this.statics();
            var P = Object.create(Point3D);
            P.init(x, y, z);
            return P;
        },

        init (x=0, y=0, z=0) {
            super.init(x, y);
            this.z = z;
        }
    }; 

Claro, criar um objeto Point3D que se vincula ao protótipo de um objeto Point2D é meio bobo, mas isso não vem ao caso (eu queria ser consistente com seu exemplo). De qualquer forma, no que diz respeito às reclamações:

  1. A assimetria pode ser corrigida com Object.setPrototypeOf do ES6 ou o mais desaprovado __proto__ = ...que eu usar. Também podemos usar super em objetos regulares agora, como visto em Point3D.init(). Outra maneira seria fazer algo como

    const Point3D = Object.assign(Object.create(Point), {  
        ...  
    }   

    embora eu particularmente não goste da sintaxe.


  1. Sempre podemos apenas agrupar p = Object.create(Point)e então p.init()em um construtor. por exemplo Point.create(x,y). Usando o código acima, podemos criar uma Point3D"instância" da seguinte maneira.

    var b = Point3D.create(1,2,3);
    console.log(b);                         // { x:1, y:2, z:3 }
    console.log(Point.isPrototypeOf(b));    // true
    console.log(Point3D.isPrototypeOf(b))   // true

  1. Acabei de criar este hack para emular métodos estáticos no OLOO. Não tenho certeza se gosto ou não. Requer a chamada de uma propriedade especial no topo de quaisquer métodos "estáticos". Por exemplo, tornei o Point.create()método estático.

        var p = Point.create(1,2);
        var q = p.create(4,1);          // Error!  

Alternativamente, com os Símbolos ES6, você pode estender as classes básicas de Javascript com segurança. Portanto, você pode economizar algum código e definir a propriedade especial em Object.prototype. Por exemplo,

    const extendedJS = {};  

    ( function(extension) {

        const statics = Symbol('static');

        Object.defineProperty(Object.prototype, statics, {
            writable: true,
            enumerable: false,
            configurable: true,
            value(obj, message) {
                if (this !== obj)
                    throw Error(message);
            }
        });

        Object.assign(extension, {statics});

    })(extendedJS);


    const Point = {
        create (x, y) {
            this[extendedJS.statics](Point);
            ...

Andrew Szymczak
fonte
2

@james emanon - Então, você está se referindo à herança múltipla (discutida na página 75 do livro "Você não conhece JS: este e protótipos de objeto"). E esse mecanismo podemos encontrar na função "estender" do sublinhado, por exemplo. Os nomes dos objetos que você indicou em seu exemplo são uma mistura de maçãs, laranjas e doces, mas eu entendo o que está por trás. Pela minha experiência, esta seria a versão OOLO:

var ObjA = {
  setA: function(a) {
    this.a = a;
  },
  outputA: function() {
    console.log("Invoking outputA - A: ", this.a);
  }
};

// 'ObjB' links/delegates to 'ObjA'
var ObjB = Object.create( ObjA );

ObjB.setB = function(b) {
   this.b = b;
}

ObjB.setA_B = function(a, b) {
    this.setA( a ); // This is obvious. 'setA' is not found in 'ObjB' so by prototype chain it's found in 'ObjA'
    this.setB( b );
    console.log("Invoking setA_B - A: ", this.a, " B: ", this.b);
};

// 'ObjC' links/delegates to 'ObjB'
var ObjC = Object.create( ObjB );

ObjC.setC = function(c) {
    this.c = c;  
};

ObjC.setA_C = function(a, c) {
    this.setA( a ); // Invoking 'setA' that is clearly not in ObjC shows that prototype chaining goes through ObjB all the way to the ObjA
    this.setC( c );
    console.log("Invoking setA_C - A: ", this.a, " C: ", this.c);
};

ObjC.setA_B_C = function(a, b, c){
    this.setA( a ); // Invoking 'setA' that is clearly not in ObjC nor ObjB shows that prototype chaining got all the way to the ObjA
    this.setB( b );
    this.setC( c );
    console.log("Invoking setA_B_C - A: ", this.a, " B: ", this.b, " C: ", this.c);
};

ObjA.setA("A1");
ObjA.outputA(); // Invoking outputA - A:  A1

ObjB.setA_B("A2", "B1"); // Invoking setA_B - A:  A2  B:  B1

ObjC.setA_C("A3", "C1"); // Invoking setA_C - A:  A3  C:  C1
ObjC.setA_B_C("A4", "B2", "C1"); // Invoking setA_B_C - A:  A4  B:  B2  C:  C1

É um exemplo simples, mas o ponto mostrado é que estamos apenas encadeando objetos em uma estrutura / formação bastante plana e ainda temos a possibilidade de usar métodos e propriedades de vários objetos. Alcançamos as mesmas coisas que com a abordagem de classe / "copiar as propriedades". Resumido por Kyle (página 114, "this & Object Prototypes"):

Em outras palavras, o mecanismo real, a essência do que é importante para a funcionalidade que podemos alavancar no JavaScript, tem tudo a ver com objetos sendo vinculados a outros objetos .

Eu entendo que a maneira mais natural para você seria declarar todos os objetos "pai" (cuidado :)) em um lugar / chamada de função, em vez de modelar a cadeia inteira.

O que é necessário é uma mudança no pensamento e na modelagem de problemas em nossas aplicações de acordo com isso. Eu também estou me acostumando. Espero que ajude e o veredicto final do próprio Kyle seria ótimo. :)

NenadPavlov
fonte
Sim - obrigado - mas eu esperava me afastar dessa metodologia porque a forma como você a tem, e a forma como imaginei fazer isso torna cada obj dependente um do outro. Eu esperava que OLOO resolvesse o problema no qual cada objeto não sabe nada sobre o outro. Como está, objB deve ser criado a partir de ObjA .. Object.create (ObjB) etc. que é muito acoplado. alguma ideia?
James emanon
-1

@Marcus, assim como você, gostei muito do OLOO e também não gosto da assimetria descrita em seu primeiro comentário. Tenho brincado com uma abstração para trazer de volta a simetria. Você pode criar uma link()função que é usada no lugar de Object.create(). Quando usado, seu código pode ter a seguinte aparência ...

var Point = {
    init  : function(x,y) {
        this.x = x;
        this.y = y;
    }
};


var Point3D = link(Point, {
    init: function(x,y,z) {
        Point.init.call(this, x, y);
        this.z = z;
    }
});

Lembre-se de que Object.create()tem um segundo parâmetro que pode ser passado. Aqui está a função de link que aproveita o segundo parâmetro. Também permite um pouco de configuração personalizada ...

function link(delegate, props, propsConfig) {
  props = props || {};
  propsConfig = propsConfig || {};

  var obj = {};
  Object.keys(props).forEach(function (key) {
    obj[key] = {
      value: props[key],
      enumerable: propsConfig.isEnumerable || true,
      writable: propsConfig.isWritable || true,
      configurable: propsConfig.isConfigurable || true
    };
  });

  return Object.create(delegate, obj);
}

Claro, acho que @Kyle não endossaria o sombreamento da init()função no objeto Point3D. ;-)

Bholben
fonte
Olhando para trás, agora acho que, combinando Object.assign()com Object.create(), podemos simplificar muito a link()função acima. Em seu lugar, poderíamos usar isso: function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. Ou melhor ainda, podemos usar Sublinhado ou Lodash para torná-lo realmente concisa: _.create(delegate, props).
bholben
-1

Existe uma maneira de OLOO mais do que "dois" objetos .. todos os exemplos consistem no exemplo baseado (veja o exemplo do OP). Digamos que temos os seguintes objetos, como podemos criar um "quarto" objeto que possui os atributos dos "outros" três? ala ...

var Button = {
     init: function(name, cost) {
       this.buttonName = name;
       this.buttonCost = cost;
     }
}

var Shoe = {
     speed: 100
}

var Bike = {
     range: '4 miles'
}

esses objetos são arbitrários e podem abranger todos os tipos de comportamentos. Mas a essência é que temos 'n' número de objetos, e nosso novo objeto precisa de algo de todos os três.

em vez dos exemplos fornecidos ala:

var newObj = Object.create(oneSingularObject);
    newObj.whatever..

MAS, nosso novoObjeto = (botão, bicicleta, sapato) ......

Qual é o padrão para fazer isso acontecer no OLOO?

James Emanon
fonte
1
Isso soa como "prefira a composição à herança" - uma ótima estratégia. No ES6, você pode usar Object.assign()- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Se estiver escrevendo em ES5, você pode usar Underscore's _.extend()ou Lodash's _.assign(). Aqui está um excelente vídeo para explicar ... youtu.be/wfMtDGfHWpA . Se você tiver qualquer propriedade colidindo, a última vence - então a ordem é importante.
bholben