Nesne değişmezlerini veya yapıcı işlevlerini kullanmalı mıyım?


94

JavaScript'te hangi yolla nesne oluşturmam gerektiği konusunda kafam karışıyor. Görünüşe göre en az iki yol var. Birincisi, nesne değişmez gösterimini kullanırken, diğeri inşa işlevlerini kullanmaktır. Birinin diğerine göre avantajı var mı?


1
En iyi cevap: stackoverflow.com/questions/4597926/… - Özet olarak, birebir gösterimlerden örnekler oluşturmak için bir işlev de ayarlayabilirsiniz. Bunu yapmak, her örnek tüm yöntemleri taşır, ancak bir yapıcıyla tüm örnekler prototip yöntemlerini ifade eder. Yani yapıcı daha iyi bellek performansına sahiptir.
Federico

Bellek bir sorun değilse, nesne değişmezleri özellik erişimi çok daha hızlıdır - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Yanıtlar:


131

Bir nesneyle ilişkili davranışınız yoksa (yani, nesne yalnızca veri / durum için bir kapsa), bir nesne değişmezi kullanırdım.

var data = {
    foo: 42,
    bar: 43
};

KISS ilkesini uygulayın . Basit bir veri kabının ötesinde bir şeye ihtiyacınız yoksa, basit bir hazır bilgi kullanın.

Nesnenize davranış eklemek istiyorsanız, bir kurucu ile gidebilir ve oluşturma sırasında nesneye yöntemler ekleyebilir veya sınıfınıza bir prototip verebilirsiniz.

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

Bunun gibi bir sınıf, aynı zamanda veri nesneniz için bir şema görevi görür: Artık nesnenin hangi özellikleri başlattığı / içerdiği (yapıcı aracılığıyla) bir tür sözleşmeniz var. Özgür bir değişmez bilgi, yalnızca şekilsiz bir veri bloğudur.

verifyDüz bir eski veri nesnesine etki eden harici bir işleve de sahip olabilirsiniz :

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

Bununla birlikte, bu, kapsülleme açısından elverişli değildir: İdeal olarak, bir varlıkla ilişkili tüm veriler + davranış birlikte yaşamalıdır.


12
Harika bir açıklama, ama işlevleri değişmez bir nesneye koymaya ne dersiniz? Bunun daha önce yapıldığını görmüştüm. Aslında aşağıdaki gönderide bunun bir örneği var.
chobo

23
İşlev tanımlarını nesne değişmezinin bir parçası olarak eklerseniz veya this.fn = function ...yaklaşımı bir yapıcıda kullanırsanız, nesne örneklerinizin her birinin kendi işlev kopyaları olacaktır. Prototip yaklaşımını kullanarak, her işlevi bir kez ve yalnızca bir kez eklersiniz: bunlar, prototip kalıtım yoluyla örnekler tarafından miras alınır.
Ates Goral

14
Önemli bir şeyi kaçırdığına inanıyorum. yalnızca yapıcı işlevi hem özel üyeler hem de genel üyeler (kapsülleme) sağlayabilir. nesne değişmezinde - hepsi herkese açıktır.
Royi Namir

Bir oyun motoruna gitmenin daha iyi bir yolu ne olabilir? Yapıcı yöntemini kullandım ancak prototiplerimin yapıcı verilerine erişimi yok.
zachdyer

90

Nesnenizin birden çok örneğine ihtiyaç duyup duymadığınıza temelde kaynar; bir yapıcıyla tanımlanan nesne, o nesnenin birden çok örneğine sahip olmanızı sağlar. Nesne değişmezleri temelde tümü herkese açık olan değişkenlere / yöntemlere sahip tekildir.

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line

1
Bu, karar verirken akılda tutulması gereken çok iyi bir noktadır. Teşekkürler.
zkent

Tecrübelerime göre, farkı yaratan tam olarak budur. Harika açık bir örnek.
Hava

9

Tek tip bir şekilde nesne oluşturmanın başka bir yolu, bir nesneyi döndüren bir işlevi kullanmaktır:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

JavaScript'teki işlevler kapanışlar olduğundan, özel değişkenleri ve yöntemleri kullanabilir ve önleyebiliriz new.

Gönderen http://javascript.crockford.com/private.html JavaScript özel değişkenlere.


7

Aşağıdaki kod, bir nesne oluşturmanın üç yöntemini gösterir; Object Literal sözdizimi, bir Function Constructor ve Object.create(). Nesne değişmez sözdizimi basitçe anında oluşturur ve nesneler oluşturur ve bu __prototype__nedenle Objectnesnesi ve tüm özelliklerine ve yöntemlerine erişime sahip olacaktır Object. Kesin olarak bir tasarım deseni perspektifinden, tek bir veri örneğini depolamak için basit bir Nesne değişmezi kullanılmalıdır.

İşlev yapıcısının adlı özel bir özelliği vardır .prototype. Bu özellik __prototype__, işlev yapıcısı tarafından oluşturulan tüm nesnelerin özelliği olacaktır . .prototypeBir işlev yapıcısının özelliğine eklenen tüm özellikler ve yöntemler, oluşturduğu tüm nesnelerde kullanılabilir olacaktır. Verilerin birden çok örneğine ihtiyaç duyuyorsanız veya nesnenizden davranış istiyorsanız bir kurucu kullanılmalıdır. Bir özel / genel geliştirme modelini simüle etmek istediğinizde işlev yapıcısının da en iyi şekilde kullanıldığını unutmayın. .prototypeHer nesne örneğinde yaratılmayacakları için tüm paylaşılan yöntemleri koymayı unutmayın .

İle nesneler oluşturmak , bu yöntemle oluşturulan nesneler için Object.create()bir nesne değişmezi kullanır __prototype__. Nesne değişmezine eklenen tüm özellikler ve yöntemler, gerçek prototip mirası yoluyla ondan oluşturulan tüm nesneler için kullanılabilir olacaktır. Bu benim tercih ettiğim yöntemdir.

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);

1
Fonksiyonu bir nesne değişmezi içinde ilan ettiğinizden beri. Bu Object.create, değişmez değerin içindeki işlevi kullanarak bir nesne oluşturduğunuzda örnek başına benzersiz olacağı anlamına mı geliyor ?
JohnnyQ

6

Bu ne yapmak istediğinize bağlıdır. Nesnenizde (yarı) özel değişkenler veya işlevler kullanmak istiyorsanız, bunu yapmanın yolu bir yapıcı işlevdir. Nesneniz yalnızca özellikler ve yöntemler içeriyorsa, bir nesne değişmezi uygundur.

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

Şimdi yöntem multiply5içeri girin myObjve SomeLiteraltamamen aynı şeyi yapın. Tek fark, myObj'nin özel bir değişken kullanmasıdır. İkincisi, bazı durumlarda yararlı olabilir. Çoğu zaman bir Object değişmezi yeterlidir ve bir JS nesnesi oluşturmanın güzel ve temiz bir yoludur.


Bir işlev ve yöntem arasındaki fark nedir? Ben ac # arka planından geliyorum, bu yüzden bana göre bir işlev bağımsızdır ve bir yöntem yalnızca bir sınıfın parçası olan bir işlevdir.
chobo

1
O kadar çok fark yok, örneğin web-source.net/javascript_tutorial/… bakın . Aslında, DOMscripting'de (bir tarayıcıdaki istemci tarafı js), tüm işlevler pencere nesnesinin (küresel ad alanı) yöntemleri haline gelir (pencere olarak tüm 'bağımsız' işlevleri de adresleyebilirsiniz. [Bir işlev].
KooiInc

5

görüntü açıklamasını buraya girin

Sayfa için nesnenin tek bir örneğini istiyor musunuz - Değişmez.

Sadece DTO nesneleri gibi verileri aktarmak ister misiniz basit GET SET: - Değişmez

Yöntem davranışları, çoklu örneklerle gerçek nesneler oluşturmak istiyor musunuz - Yapıcı işlevi, OOP ilkelerini takip edin, kalıtım: - Yapıcı işlevleri.

Aşağıda neyin gerçek olduğunu, yapıcı işlevlerin neler olduğunu ve birbirlerinden nasıl farklı olduklarını ayrıntılı olarak açıklayan youtube videosu bulunmaktadır.

https://www.youtube.com/watch?v=dVoAq2D3n44


1

Nesne değişmezi ile devam edin, daha anlaşılır ve başlangıç ​​değerlerinin tanıtılmasıyla daha iyi genişler.


Bir nesne değişmezinde özel değişkenleri nasıl yaratırsınız?
EhevuTov

Gerçekten yapamazsınız, asıl soruyla alakalı değil, bu yüzden size bir bağlantı vereceğim: javascript.crockford.com/private.html
Tom

1
Aslında konuyla ilgilidir, çünkü bir fark olduğunda, belirli durumlara bağlı olarak birini veya diğerini kullanmanın bir nedeni vardır; bu durumda özel değişkenler isteyip istemediğiniz olabilir. Özel değişkenleri, ilk önce birebir kapama işlevi oluşturarak birebir yaratabilirsiniz, ancak bence çok daha çirkin ve okunması zor.
EhevuTov

Düzeltilmiş durumdayım, soruyu orijinal okumam, chobo'nun değişkenleri bir yapıcıya parametre listesinde olduğu gibi tek nesneli değişmez parametreye karşı nasıl aktaracağını sormasıydı.
Tom



0

Aslında, bana göre, nesne değişmezlerinde özel yöntemlere sahip olabiliriz. Aşağıdaki kodu düşünün:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

Zevk meselesi, ama mümkün olduğu yerde nesne değişmezlerini kullanmayı tercih ederim.


-1

// Object Literal ve Object yapıcısı

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 

1
Örneğinizde Object değişmezi nerede beyan edildi?
JohnnyQ
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.