Pola OLOO Kyle Simpson vs Pola Desain Prototipe


109

Apakah Pola "OLOO (Objects Linking to Other Objects)" Kyle Simpson berbeda dengan pola desain Prototipe? Selain menciptakannya dengan sesuatu yang secara khusus menunjukkan "menghubungkan" (perilaku prototipe) dan menjelaskan bahwa tidak ada "penyalinan" yang terjadi di sini (perilaku kelas), apa sebenarnya yang diperkenalkan oleh polanya?

Berikut ini contoh pola Kyle dari bukunya, "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."

2
Dapatkah Anda setidaknya menautkan ke deskripsi pola yang Anda tanyakan. Bahkan lebih baik untuk menunjukkan contoh kode dalam pertanyaan Anda.
jfriend00

4
Getify terkadang ada di Stackoverflow. Saya telah men-tweet dia pertanyaan ini :)
Pointy

Jawaban:


155

apa sebenarnya yang diperkenalkan oleh polanya?

OLOO merangkul rantai prototipe apa adanya, tanpa perlu melapisi semantik lain (IMO membingungkan) untuk mendapatkan tautan.

Jadi, kedua cuplikan ini memiliki hasil yang SAMA PERSIS, tetapi sampai di sana secara berbeda.

Bentuk Pembuat:

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

Formulir OLOO:

var FooObj = { y: 11 };

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

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

Di kedua cuplikan, sebuah xobjek [[Prototype]]ditautkan ke objek ( Bar.prototypeatau BarObj), yang pada gilirannya ditautkan ke objek ketiga ( Foo.prototypeatau FooObj).

Hubungan dan delegasi identik di antara cuplikan. Penggunaan memori identik di antara cuplikan. Kemampuan untuk menciptakan banyak "anak" (alias, banyak benda seperti x1melalui x1000, dll) identik antara potongan. Kinerja delegasi ( x.ydan x.z) identik di antara cuplikan. Kinerja pembuatan obyek adalah lebih lambat dengan OLOO, tapi kewarasan memeriksa bahwa mengungkapkan bahwa kinerja lambat adalah benar-benar tidak masalah.

Menurut saya, yang ditawarkan OLOO adalah jauh lebih mudah untuk hanya mengekspresikan objek dan menghubungkannya secara langsung, daripada menghubungkannya secara tidak langsung melalui konstruktor / newmekanisme. Yang terakhir berpura-pura tentang kelas tetapi sebenarnya hanya sintaks yang buruk untuk mengekspresikan delegasi ( catatan samping: begitu juga classsintaks ES6 !).

OLOO baru saja menghentikan perantara.

Berikut perbandingan lain dari classvs OLOO.


2
Saya menemukan jawaban Anda sangat menarik dan ide OLOO dijelaskan dalam buku Anda, saya ingin mendapatkan umpan balik Anda untuk pertanyaan ini: stackoverflow.com/questions/40395762/… Khususnya jika Anda menemukan penerapan ini benar dan bagaimana menyelesaikan masalah terkait akses anggota pribadi. Terima kasih atas waktu Anda sebelumnya dan selamat untuk buku terbaru Anda.
GibboK

Tapi Object.create(...)berkali-kali lebih lambat dari new. jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/…
Dermaga

3
@Pier kinerja sebenarnya tidak terlalu menjadi masalah. memperbaiki tautan entri blog yang rusak tentang pemeriksaan kewarasan kinerja pembuatan objek, yang menjelaskan cara memikirkan hal ini dengan benar.
Kyle Simpson

2
Dan jQuery lebih lambat dari API DOM, bukan? Tapi, ini tahun sekarang, sobat - Saya lebih suka menulis dengan elegan dan hanya khawatir tentang pengoptimalan. Jika saya perlu melakukan pengoptimalan mikro nanti, saya akan mengkhawatirkannya ketika saatnya tiba.
Eirik Birkeland

6
Saya ingin menambahkannya sekarang, lebih dari setahun kemudian, Object.create () sangat dioptimalkan di chrome, dan jsperf menunjukkannya - ini adalah salah satu opsi tercepat sekarang. Ini menunjukkan dengan tepat mengapa Anda tidak harus menyibukkan diri dengan pengoptimalan mikro seperti itu, dan sebaliknya hanya menulis kode yang terdengar secara algoritmik.
Kyle Baker

25

Saya membaca buku Kyle, dan menurut saya itu sangat informatif, terutama detail tentang bagaimana thisterikat.

Kelebihan:

Bagi saya, ada beberapa kelebihan OLOO:

1. Kesederhanaan

OLOO mengandalkan Object.create()untuk membuat objek baru yang [[prototype]]-link ke objek lain. Anda tidak perlu memahami bahwa fungsi memiliki aprototype properti atau khawatir tentang potensi jebakan terkait yang berasal dari modifikasinya.

2. Sintaks yang lebih bersih

Ini bisa diperdebatkan, tetapi saya merasa sintaks OLOO (dalam banyak kasus) lebih rapi dan lebih ringkas daripada pendekatan javascript 'standar', terutama dalam hal polimorfisme ( superpanggilan -style).

Kekurangan:

Saya pikir ada satu desain yang dipertanyakan (yang sebenarnya berkontribusi pada poin 2 di atas), dan itu berkaitan dengan shadowing:

Dalam pendelegasian perilaku, kita menghindari jika memungkinkan penamaan hal-hal yang sama di berbagai tingkat [[Prototype]]rantai.

Ide di balik ini adalah bahwa objek memiliki fungsi yang lebih spesifik yang kemudian didelegasikan secara internal ke fungsi di bagian bawah rantai. Misalnya, Anda mungkin memiliki resourceobjek dengan save()fungsi di atasnya yang mengirimkan versi JSON dari objek ke server, tetapi Anda mungkin juga memiliki clientResourceobjek yang memilikistripAndSave() fungsi, yang terlebih dahulu menghapus properti yang tidak boleh dikirim ke server. .

Masalah potensial adalah: jika orang lain datang dan memutuskan untuk membuat specialResourceobjek, tidak sepenuhnya menyadari keseluruhan rantai prototipe, mereka mungkin secara wajar * memutuskan untuk menyimpan stempel waktu untuk penyimpanan terakhir di bawah properti bernama save, yang membayangi save()fungsionalitas dasar pada yang resourceobjek dua link ke bawah rantai prototipe:

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!

Ini adalah contoh yang dibuat-buat, tetapi intinya adalah tidak membayangi properti lain dapat menyebabkan beberapa situasi yang canggung dan penggunaan tesaurus yang berat!

Mungkin ilustrasi yang lebih baik dari ini adalah initmetode - terutama pedih karena OOLO menghindari fungsi jenis konstruktor. Karena setiap objek terkait kemungkinan besar membutuhkan fungsi seperti itu, mungkin latihan yang membosankan untuk menamainya dengan tepat, dan keunikan mungkin membuat sulit untuk mengingat mana yang akan digunakan.

* Sebenarnya itu tidak terlalu masuk akal ( lastSavedakan jauh lebih baik, tapi ini hanya sebuah contoh.)


23
Saya setuju bahwa potensi benturan nama adalah sebuah kelemahan ... tetapi sebenarnya ini adalah kelemahan dari [[Prototype]]sistem itu sendiri, bukan secara spesifik OLOO.
Kyle Simpson

Mungkinkah itu seharusnya disebutkan dalam buku juga?
Sewa

Saya tidak begitu yakin ini benar-benar solusi untuk masalah yang dijelaskan oleh @Ed Hinchliffe karena ini hanya memindahkan save () ke namespace itu sendiri tetapi itu berfungsi codepen.io/tforward/pen/govEPr?editors=1010
Tristan Forward

Saya pikir @ ed-hinchliffe dimaksudkan b.timeStampedSave();sebagai pengganti a.timeStampedSave();pada baris terakhir dari potongan kode.
amangpt777

1
@ tristan-forward terima kasih telah membawa Rick dan Morty ke dalam ini!
Eric Bishard

13

Diskusi dalam "You Don't Know JS: this & Object Prototypes" dan presentasi OLOO sangat menggugah pikiran dan saya telah belajar banyak melalui buku ini. Keunggulan pola OLOO dijelaskan dengan baik di jawaban lain; Namun, saya memiliki keluhan hewan peliharaan berikut dengannya (atau saya kehilangan sesuatu yang mencegah saya menerapkannya secara efektif):

1

Ketika "class" "mewarisi" class "lain" dalam pola klasik, kedua fungsi tersebut dapat dinyatakan dengan sintaks yang serupa ( "deklarasi fungsi" atau "pernyataan fungsi" ):

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

Sebaliknya, dalam pola OLOO, bentuk sintaksis yang berbeda digunakan untuk menentukan basis dan objek turunan:

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

Seperti yang Anda lihat pada contoh di atas, objek dasar dapat didefinisikan menggunakan notasi literal objek, sedangkan notasi yang sama tidak dapat digunakan untuk objek turunan. Asimetri ini mengganggu saya.

2

Dalam pola OLOO, membuat objek dalam dua langkah:

  1. panggilan Object.create
  2. panggil beberapa metode kustom, non standar untuk menginisialisasi objek (yang harus Anda ingat karena ini mungkin berbeda dari satu objek ke objek berikutnya):

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

Sebaliknya, dalam pola Prototipe Anda menggunakan operator standar new:

var p2a = new Point(1,1);

3

Dalam pola klasik, saya dapat membuat fungsi utilitas "statis" yang tidak berlaku langsung ke "instan" dengan menetapkannya langsung ke fungsi "kelas" (sebagai lawannya .prototype). Misal seperti fungsi squarepada kode di bawah ini:

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

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

Sebaliknya, dalam pola OLOO semua fungsi "statis" tersedia (melalui rantai [[prototipe]]) pada instance objek juga:

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

2
Tidak ada literal dalam contoh kode pertama Anda. Anda mungkin menyalahgunakan istilah "literal" untuk memberikan arti lain. Hanya mengatakan ...
Ivan Kleshnin

2
Mengenai poin ke-2, penulis berpendapat bahwa itu adalah pemisahan perhatian yang "lebih baik" untuk memisahkan pembuatan dan inisialisasi dan mengutip mungkin ada beberapa kasus penggunaan yang jarang terjadi di mana hal ini mungkin bersinar (misalnya kumpulan objek). Saya menemukan argumen itu sangat lemah.
Sewa

2
Sekali lagi mengenai poin ke-2, dengan OLOO, Anda dapat membuat objek sekaligus, dan menunggu untuk menginisialisasi, sedangkan dengan konstruktor, Anda harus menginisialisasi saat pembuatan, jadi Kyle menganggap ini sebagai keuntungan.
taco

5

"Saya pikir untuk melakukannya membuat setiap obyek bergantung pada yang lain"

Seperti yang dijelaskan Kyle saat dua objek [[Prototype]]dihubungkan, keduanya tidak benar-benar bergantung satu sama lain; sebaliknya mereka adalah objek individu. Anda menautkan satu objek ke objek lainnya dengan [[Prototype]]tautan yang dapat Anda ubah kapan saja Anda mau. Jika Anda menganggap dua [[Prototype]]objek tertaut yang dibuat melalui gaya OLOO saling bergantung, Anda juga harus berpikiran sama tentang objek yang dibuat melalui constructorpanggilan.

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

Sekarang pikirkan sejenak apakah Anda memikirkan foo bardanbaz bergantung satu sama lain?

Sekarang mari lakukan hal yang sama constructordengan kode gaya ini-

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

Satu-satunya perbedaan b / w yang terakhir dan mantan kode adalah bahwa dalam satu terakhir foo, bar, bazbbjects dihubungkan satu sama-lain melalui objek sewenang-wenang dari mereka constructorfungsi ( Foo.prototype, Bar.prototype, Baz.prototype) tapi di bekas satu ( OLOOgaya) mereka terkait langsung. Kedua cara Anda hanya menghubungkan foo, bar, bazsatu sama lain, langsung di bekas satu dan tidak langsung dalam satu terakhir. Namun, dalam kedua kasus, objek tidak bergantung satu sama lain karena tidak benar-benar seperti instance dari kelas mana pun yang pernah dibuat instance-nya, tidak dapat dibuat untuk mewarisi dari kelas lain. Anda selalu dapat mengubah objek mana yang harus didelegasikan oleh objek juga.

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

Jadi mereka semua tidak bergantung satu sama lain.

"Saya berharap OLOOakan menyelesaikan masalah di mana setiap objek tidak tahu apa-apa tentang yang lain."

Ya itu memang mungkin-

Mari kita gunakan Techsebagai objek utilitas-

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

buat objek sebanyak yang Anda ingin ditautkan 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

Apakah Anda berpikir html, css, jsobjek yang terhubung satu sama-lain? Tidak, mereka tidak. Sekarang mari kita lihat bagaimana kita bisa melakukannya dengan constructorfungsi-

function Tech() { }

Tech.prototype.tag= "technology";

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

buat objek sebanyak yang Anda ingin ditautkan Tech.proptotype-

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

Beberapa pemeriksaan (menghindari 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

Bagaimana Anda pikir ini constructorObjects -gaya ( html, css, js) Objek berbeda dari OLOOkode-gaya? Sebenarnya mereka melayani tujuan yang sama. Dalam- OLOOgaya satu objek didelegasikan ke Tech(delegasi ditetapkan secara eksplisit) sedangkan dalam constructorgaya satu objek didelegasikan ke Tech.prototype(delegasi ditetapkan secara implisit). Pada akhirnya Anda akan menghubungkan ketiga objek, yang tidak memiliki keterkaitan satu sama lain, ke satu objek, secara langsung menggunakan OLOO-style, secara tidak langsung menggunakan constructor-style.

"Sebagaimana adanya, ObjB harus dibuat dari ObjA .. Object.create (ObjB) dll"

Tidak, di ObjBsini tidak seperti instance (dalam bahasa berbasis klasik) dari kelas mana pun ObjA. Ini bisa dikatakan seperti objBobjek dibuat delegasi ke ObjAobjek pada waktu pembuatannya " . Jika Anda menggunakan konstruktor, Anda akan melakukan 'penggandengan' yang sama, meskipun secara tidak langsung dengan menggunakan .prototypes.


3

@Jamur_kejang

Mungkin kita bisa melakukan sesuatu seperti ini.

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

Tentu saja, membuat objek Point3D yang ditautkan ke prototipe objek Point2D agak konyol, tapi itu tidak penting (saya ingin konsisten dengan contoh Anda). Ngomong-ngomong, sejauh keluhannya:

  1. Asimetri dapat diperbaiki dengan ES6's Object.setPrototypeOf atau lebih disukai __proto__ = ...yang saya gunakan. Sekarang kita juga bisa menggunakan super pada objek biasa, seperti yang terlihat di Point3D.init(). Cara lain adalah melakukan sesuatu seperti

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

    meskipun saya tidak terlalu suka sintaksnya.


  1. Kami selalu dapat membungkus p = Object.create(Point)dan kemudian p.init()menjadi konstruktor. mis Point.create(x,y). Menggunakan kode di atas kita dapat membuat Point3D"instance" dengan cara berikut.

    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. Saya baru saja membuat peretasan ini untuk meniru metode statis di OLOO. Saya tidak yakin apakah saya suka atau tidak. Ini membutuhkan pemanggilan properti khusus di atas setiap metode "statis". Misalnya, saya telah membuat Point.create()metode menjadi statis.

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

Alternatifnya, dengan Simbol ES6 Anda dapat memperluas kelas dasar Javascript dengan aman. Jadi Anda bisa menyimpan sendiri beberapa kode dan mendefinisikan properti khusus di Object.prototype. Sebagai contoh,

    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);
            ...


2

@james emanon - Jadi, yang Anda maksud adalah warisan berganda (dibahas di halaman 75 dalam buku "You Don't Know JS: this & Object Prototypes"). Dan mekanisme itu bisa kita temukan di fungsi "perluasan" garis bawah misalnya. Nama objek yang Anda sebutkan dalam contoh Anda sedikit mencampurkan apel, jeruk, dan permen, tetapi saya mengerti maksudnya. Dari pengalaman saya, ini adalah versi 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

Ini adalah contoh sederhana tetapi poin yang ditunjukkan adalah bahwa kita hanya merangkai objek bersama dalam struktur / formasi yang agak datar dan masih memiliki kemungkinan untuk menggunakan metode dan properti dari beberapa objek. Kami mencapai hal yang sama seperti dengan pendekatan kelas / "menyalin properti". Disimpulkan oleh Kyle (halaman 114, "this & Object Prototypes"):

Dengan kata lain, mekanisme sebenarnya, inti dari apa yang penting bagi fungsionalitas yang dapat kita manfaatkan dalam JavaScript, adalah tentang objek yang ditautkan ke objek lain .

Saya memahami bahwa cara yang lebih alami bagi Anda adalah dengan menyatakan semua objek "induk" (hati-hati :)) di satu tempat / fungsi memanggil pemodelan keseluruhan rantai.

Yang dibutuhkan adalah pergeseran dalam pemikiran dan pemodelan masalah dalam aplikasi kita yang sesuai dengan itu. Saya juga mulai terbiasa. Semoga membantu dan keputusan akhir dari Kyle sendiri akan bagus. :)


Ya - terima kasih - tapi saya berharap untuk menjauh dari metodologi ini karena cara Anda memilikinya, dan cara saya melakukannya membuat setiap objek bergantung satu sama lain .. Saya berharap OLOO akan menyelesaikan masalah di mana setiap objek tidak tahu apa-apa tentang yang lain. Seperti, objB harus dibuat dari ObjA .. Object.create (ObjB) dll .. yang terlalu digabungkan. ada ide?
james emanon

-1

@Marcus, sama seperti Anda, saya tertarik dengan OLOO dan juga tidak menyukai asimetri seperti yang dijelaskan pada poin pertama Anda. Saya telah bermain dengan abstraksi untuk mengembalikan simetri. Anda bisa membuat link()fungsi yang digunakan sebagai pengganti Object.create(). Saat digunakan, kode Anda akan terlihat seperti ini ...

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

Ingatlah bahwa Object.create()memiliki parameter kedua yang dapat dilewatkan. Berikut adalah fungsi link yang memanfaatkan parameter kedua. Ini juga memungkinkan sedikit konfigurasi khusus ...

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

Tentu saja, saya pikir @Kaos tidak akan mendukung init()fungsi di objek Point3D. ;-)


Dalam melihat ke belakang melalui ini, saya sekarang memikirkannya dengan menggabungkan Object.assign()denganObject.create() , kita dapat sangat menyederhanakan link()fungsi di atas. Sebagai gantinya, kita bisa menggunakan ini: function create(delegate, props) { return Object.assign(Object.create(delegate), props); }. Atau lebih baik lagi, kita dapat menggunakan Menggarisbawahi atau Lodash untuk membuatnya benar-benar ringkas: _.create(delegate, props).
bholben

-1

Apakah ada cara untuk OLOO lebih dari "dua" objek .. semua contoh saya terdiri dari contoh berbasis (lihat contoh OP). Katakanlah kita memiliki objek berikut, bagaimana kita bisa membuat objek "keempat" yang memiliki atribut dari tiga 'lainnya'? ala ...

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

var Shoe = {
     speed: 100
}

var Bike = {
     range: '4 miles'
}

objek-objek ini sewenang-wenang, dan dapat mencakup semua jenis perilaku. Tetapi intinya adalah, kita memiliki sejumlah 'n' objek, dan objek baru kita membutuhkan sesuatu dari ketiganya.

Alih-alih contoh yang diberikan ala:

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

TAPI, newObject = (Button, Bike, Shoe) ......

Bagaimana pola untuk menjalankan ini di OLOO?


1
Ini terdengar seperti "lebih menyukai komposisi daripada warisan" - strategi yang bagus. Di ES6, Anda dapat menggunakan Object.assign()- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Jika menulis di ES5, Anda dapat menggunakan Underscore _.extend()atau Lodash _.assign(). Berikut video yang bagus untuk menjelaskan ... youtu.be/wfMtDGfHWpA . Jika Anda memiliki properti yang bertabrakan, yang terakhir menang - jadi keteraturan itu penting.
bholben
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.