JavaScript mirası: Object.create ve yeni


123

JavaScript'te bu iki örnek arasındaki fark nedir:

Önkoşul:

function SomeBaseClass(){
}

SomeBaseClass.prototype = {
    doThis : function(){
    },

    doThat : function(){
    }
}

Object.create kullanarak kalıtım örneği A:

function MyClass(){
}

MyClass.prototype = Object.create(SomeBaseClass.prototype);

Yeni anahtar kelimeyi kullanan kalıtım örneği B

function MyClass(){
}

MyClass.prototype = new SomeBaseClass();

Her iki örnek de aynı şeyi yapıyor gibi görünüyor. Ne zaman birini diğerine tercih edersiniz?

Ek bir soru: Prototipte işlevin kendi kurucusuna bir referansın depolandığı aşağıdaki bağlantıdaki (satır 15) kodu düşünün. Bu neden yararlıdır?

https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

Alıntı (bağlantıyı açmak istemiyorsanız):

THREE.ImageLoader.prototype = {

    constructor: THREE.ImageLoader
}

23
Bu neden yinelenen olarak işaretlendi!?! Diğer soru ve cevaplar, bahsetme bile Object.create. Bu bir hatadır ve yeniden açılmalıdır.
Scott Rippey


1
Bu yoruma 13 oy verildi ve hala yeniden açılmadı ..?!
TJ

Yanıtlar:


111

Sorunuzda bundan bahsetmiştiniz Both examples seem to do the same thing, bu hiç doğru değil çünkü

İlk örneğiniz

function SomeBaseClass(){...}
SomeBaseClass.prototype = {
    doThis : function(){...},
    doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);

Bu örnekte, sadece devralan SomeBaseClass' prototypeEğer bir mülk varsa ama ne SomeBaseClassbeğendiniz

function SomeBaseClass(){ 
    this.publicProperty='SomeValue'; 
}

ve eğer onu beğenirsen

var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);​

objNesne olmayacak publicPropertygibi özellik bu örnekte .

İkinci örneğiniz

MyClass.prototype = new SomeBaseClass();

Yürütme oluyor constructorbir örneğini yaparak, işlevi SomeBaseClassve bütün miras SomeBaseClassnesne. Yani, kullanırsan

    var obj=new MyClass();
    console.log(obj.publicProperty); // SomeValue
    console.log(obj);​

Bu durumda publicPropertyözelliği, bu örnektekiobj gibi nesne için de mevcuttur .

Yana Object.createbazı eski tarayıcılarda kullanılamaz, bu durumda size kullanabilirsiniz

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

Yukarıdaki kod, Object.createmevcut değilse yalnızca işlevi ekler, böylece Object.createişlevi kullanabilirsiniz ve bence yukarıdaki kod, Object.creategerçekte ne yaptığını açıklar . Umarım bir şekilde yardımcı olur.


6
Merhaba Şeyh. Bu konudaki çabalarınız için teşekkürler. Evet, aradaki fark, kurucunun ikinci örnekte çalıştırılması, ancak birinci örnekte çalıştırılmamasıdır. (benim durumumda arzu edilen). Süper uygulamadan miras alınmayan tanımsız genel özellik ile ilgili olarak, alt yapıcının yapıcısında super çağırmanız yeterlidir: SomeBaseClass.call (this). Bu keman kontrol et: jsfiddle.net/NhQGB
ChrisRich

Herhangi bir kitaplık / çerçeve kullanmadan JS'de uygun miras almanın süper basit bir yolunu arıyordum. Bence bu örnek (yukarıdaki kemanımda) modern tarayıcılar için en iyi yaklaşımdır. Belki Object.Create polyfill eski tarayıcılar için destek ekleyebilir mi?
ChrisRich

Yani özetlemek gerekirse, eğer .prototype = new yaparsanız, o zaman buna atadığınız değerleri temel sınıfta miras alırsınız ve object.create yaptığınızda YALNIZCA temel sınıftaki prototipte olanı miras alırsınız, değil mi?
davidjnelson

Bu "MyClass.prototype = new SomeBaseClass ()", MyClass örneği henüz oluşturulmadığında yeni SomeBaseClass örneğinin oluşturulduğu anlamına mı geliyor?

Hayır, yalnızca ana nesneyi oluşturduğunuzda prototip buna ayarlanır SomeBaseClass.
The Alpha

39

Her iki örnek de aynı şeyi yapıyor gibi görünüyor.

Bu senin durumunda doğru.

Ne zaman birini diğerine tercih edersiniz?

Bir SomeBaseClassişlev gövdesine sahip olduğunda , bu newanahtar sözcükle çalıştırılır . Bu genellikle amaçlanmamıştır - yalnızca prototip zincirini kurmak istersiniz. Hatta bazı durumlarda , özel kapsamlı değişkenleri aynı ayrıcalıklı yöntemleri miras aldıkları için tüm örnekler tarafından paylaşılan bir nesneyi gerçekten başlattığınız için ciddi sorunlara neden olabilir MyClass. Diğer yan etkiler de düşünülebilir.

Yani genel olarak tercih etmelisiniz Object.create. Yine de bazı eski tarayıcılarda desteklenmemektedir; newçoğu zaman (bariz) bir zararı olmadığı için yaklaşımı çok sık görmenizin nedeni budur . Ayrıca bu cevaba bir göz atın .


Bu iyi açıklanmış en iyi cevap
spex

8

Amaçlandığı Object.create()gibi kullanırsanız fark belirgin hale gelir . Aslında, prototypekelimeyi kodunuzdan tamamen gizler , işi kaputun altında yapar. Kullanarak Object.create(), gibi gidebiliriz

var base =  {
    doThis : function(){
    },

    doThat : function(){
    }
};

Ve bundan sonra diğer nesneleri genişletebilir / miras alabiliriz

var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally

Yani bu başka bir kavram, daha "nesne yönelimli" bir engelleme yolu. Object.create()Örneğin , kutunun dışında bir "yapıcı işlevi" yoktur . Ancak elbette, bu nesneler içinde kendi kendini tanımlayan bir yapıcı işlevi oluşturabilir ve çağırabilirsiniz .

Kullanmak için bir argüman Object.create()daha görünebilir olmasıdır doğal etmek mix / * devralır * diğer nesnelerden, Javascriptleri kullanmaktan daha varsayılan yol .


7
Object.createnewbir yapıcı işlevi gerektiğinde klasik yaklaşımı gerçekten değiştiremez
Bergi

1
Kesinlikle @Bergi olabilir. Şu blog gönderisine bakın: davidwalsh.name/javascript-objects-deconstruction . Ayrıca bir başlatma nesnesini ikinci parametre olarak Object.create () öğesine iletebilirsiniz.
LocalPCGuy

@LocalPCGuy: Hayır olamaz, çünkü Object.createkapanışlar yaratmak için gerekli olacak bir işlevi çağırmaz. Tabii ki, birlikte Object.createsize bir koyabilirsiniz initolduğunu hemen nesneler ve çağrı yöntemi ve hatta belki de döner thisböylece kısa sözdizimi almak - ama bekleme, bir sonra yapıcı.
Bergi

1
Bir init işlevini çağırmak bir kurucuya benzer şekilde çalışır, ancak bir yapıcı değildir. Ve bu yöntem, klasik yaklaşımı tam olarak Object.create ile değiştirmenize izin veriyor. Ve nesne bağlantısının zihinsel modeli, "yeni" aracılığıyla oluşturulan modelden çok daha basittir.
LocalPCGuy

Benim zihinsel modelim olan new"nesne bağlantısı" kullanımı, dolayısıyla pek bir fark yok. Aslında sadece iki şey vardır: .constructorçağrılır .initve bu işlevin .prototypeprototip nesnenize geri işaret eden bir özelliği yoktur. Gerisi sözdizimi - ve tercih new Xüzerinde Object.create(x).init().
Bergi

0

Java betiğinde uzman değilim ama burada "Object.create" ve "new" arasındaki farkı anlamak için basit bir örnek var ..

1. adım: bazı özellikler ve eylemlerle ana işlevi oluşturun ..

function Person() {

this.name = 'venkat';

this.address = 'dallas';

this.mobile='xxxxxxxxxx'

}

Person.prototype.func1 = function () {

    return this.name + this.address;
}

2. adım: New anahtar sözcüğünü kullanarak Kişi işlevinin üzerine çıkan bir çocuk işlevi (PersonSalary) oluşturun ..

function PersonSalary() {
    Person.call(this);
}
PersonSalary.prototype = new Person();

PersonSalary();

Adım 3: Object.create anahtar sözcüğünü kullanarak Person işlevinin üzerine uzanan ikinci çocuk işlevi (PersonLeaves) oluşturun .

function PersonLeaves() {
 Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

// Şimdi her iki alt işlev prototipini kontrol edin.

PersonSalary.prototype
PersonLeaves.prototype

bu çocuk işlevlerin her ikisi de Kişi (ana işlev) prototipine bağlanır ve yöntemlerine erişebilir, ancak yeniyi kullanarak çocuk işlev oluşturursanız, ihtiyacımız olmayan tüm üst özelliklere sahip yepyeni bir nesne döndürür ve ayrıca herhangi bir şey oluşturduğunuzda nesne veya işlev "Yeni" kullanılarak yürütülür ve bizim olmasını istemediğimiz üst işlev yürütülür.

İşte çıkarımlar

Üst işlevdeki bazı yöntemlere yetki vermek istiyorsanız ve yeni bir nesnenin oluşturulmasını istemiyorsanız, Object.create kullanmak en iyi yoldur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.