Czy powinienem używać literałów obiektów czy funkcji konstruktora?


94

Nie wiem, w jaki sposób powinienem tworzyć obiekt w javascript. Wygląda na to, że są co najmniej dwa sposoby. Jedną z nich jest użycie notacji dosłownej obiektu, podczas gdy druga wykorzystuje funkcje konstrukcyjne. Czy istnieje przewaga jednego nad drugim?


1
Najlepsza odpowiedź: stackoverflow.com/questions/4597926/ ... - Podsumowując, możesz skonfigurować funkcję do tworzenia instancji również w notacji literału. Robiąc to, każda instancja przenosi wszystkie metody, podczas gdy w przypadku konstruktora wszystkie instancje odnoszą się do metod prototypowych. To znaczy konstruktor ma lepszą wydajność pamięci.
Federico

Jeśli pamięć nie jest problemem, dostęp do właściwości literałów obiektowych jest o wiele wielkości szybszy - jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Odpowiedzi:


131

Jeśli nie masz zachowania związanego z obiektem (tj. Jeśli obiekt jest tylko kontenerem dla danych / stanu), użyłbym literału obiektu.

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

Zastosuj zasadę KISS . Jeśli nie potrzebujesz niczego poza prostym kontenerem danych, użyj prostego literału.

Jeśli chcesz dodać zachowanie do swojego obiektu, możesz skorzystać z konstruktora i dodać metody do obiektu podczas konstruowania lub dać swojej klasie prototyp.

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

Taka klasa działa również jak schemat obiektu danych: masz teraz pewien rodzaj kontraktu (za pośrednictwem konstruktora), jakie właściwości obiekt inicjuje / zawiera. Wolny literał to po prostu amorficzna plama danych.

Równie dobrze możesz mieć funkcję zewnętrzną, verifyktóra działa na zwykłym starym obiekcie danych:

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

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

Jednak nie jest to korzystne w odniesieniu do hermetyzacji: w idealnym przypadku wszystkie dane + zachowanie związane z jednostką powinny współistnieć.


12
Świetne wyjaśnienie, ale co z umieszczaniem funkcji w dosłownym znaczeniu obiektu? Widziałem to już wcześniej. Właściwie poniższy post zawiera tego przykład.
chobo

23
Jeśli dołączysz definicje funkcji jako część literału obiektu lub użyjesz this.fn = function ...podejścia w konstruktorze, każde z wystąpień obiektów będzie miało własne kopie funkcji. Korzystając z podejścia prototypowego, każdą funkcję dołączasz raz i tylko raz: zostaną one odziedziczone przez instancje poprzez dziedziczenie prototypowe.
Ates Goral

14
Myślę, że przegapiłeś ważną rzecz. tylko funkcja konstruktora może udostępniać członków prywatnych, a także członków publicznych (hermetyzacja). w dosłowności obiektu - wszystkie są publiczne.
Royi Namir

Jaki byłby lepszy sposób na zakup silnika gry? Użyłem metody konstruktora, ale moje prototypy nie mają dostępu do danych konstruktora.
zachdyer

90

Zasadniczo sprowadza się to do tego, czy potrzebujesz wielu wystąpień obiektu, czy nie; obiekt zdefiniowany za pomocą konstruktora umożliwia utworzenie wielu instancji tego obiektu. Literały obiektów są w zasadzie singletonami ze zmiennymi / metodami, które są wszystkie publiczne.

// 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
Jest to bardzo dobry punkt, o którym należy pamiętać przy podejmowaniu decyzji. Dzięki.
zkent

Z mojego doświadczenia wynika, że ​​właśnie to robi różnicę. Świetny jasny przykład.
Air

9

Innym sposobem tworzenia obiektów w jednolity sposób jest użycie funkcji zwracającej obiekt:

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!

Ponieważ funkcje w JavaScript są domknięciami, możemy używać prywatnych zmiennych i metod oraz unikać new.

Z http://javascript.crockford.com/private.html na temat zmiennych prywatnych w JavaScript.


7

Poniższy kod przedstawia trzy metody tworzenia obiektu, składnię literału obiektu, konstruktor funkcji i Object.create(). Składnia literału obiektu po prostu tworzy obiekt w locie i jako taki __prototype__jest Objectobiektem i będzie miał dostęp do wszystkich właściwości i metod programu Object. Ściśle z punktu widzenia wzorca projektowego do przechowywania pojedynczego wystąpienia danych należy użyć prostego literału Object.

Konstruktor funkcji ma specjalną właściwość o nazwie .prototype. Ta właściwość stanie się właściwością __prototype__wszystkich obiektów utworzonych przez konstruktor funkcji. Wszystkie właściwości i metody dodane do .prototypewłaściwości konstruktora funkcji będą dostępne dla wszystkich tworzonych przez niego obiektów. Należy użyć konstruktora, jeśli potrzebujesz wielu wystąpień danych lub wymagasz zachowania od obiektu. Zwróć uwagę, że konstruktor funkcji jest również najlepiej używany, gdy chcesz symulować wzorzec programowania prywatny / publiczny. Pamiętaj, aby umieścić wszystkie metody współdzielone na .prototypetak, aby nie były tworzone w każdej instancji obiektu.

Tworzenie obiektów za pomocą Object.create()wykorzystuje literał obiektu jako __prototype__obiekt utworzony za pomocą tej metody. Wszystkie właściwości i metody dodane do literału obiektu będą dostępne dla wszystkich utworzonych z niego obiektów poprzez prawdziwe dziedziczenie prototypowe. To moja preferowana metoda.

//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
Ponieważ zadeklarowałeś funkcję wewnątrz literału obiektu. Czy to oznacza, że ​​kiedy tworzysz obiekt za Object.createpomocą funkcji wewnątrz literału, będzie on niepowtarzalny dla każdej instancji?
JohnnyQ,

6

To zależy od tego, co chcesz robić. Jeśli chcesz używać (pół-) prywatnych zmiennych lub funkcji w swoim obiekcie, sposobem na to jest funkcja konstruktora. Jeśli twój obiekt zawiera tylko właściwości i metody, literał obiektu jest w porządku.

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

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

Teraz metoda multiply5w myObji SomeLiteralrobią dokładnie to samo. Jedyną różnicą jest to, że myObj używa zmiennej prywatnej. To ostatnie może być przydatne w niektórych przypadkach. W większości przypadków literał Object jest wystarczający i jest dobrym i czystym sposobem na utworzenie obiektu JS.


Jaka jest różnica między funkcją a metodą? Pochodzę z tła ac #, więc dla mnie funkcja jest samodzielna, a metoda jest po prostu funkcją, która jest częścią klasy.
chobo

1
Nie ma dużej różnicy, zobacz na przykład web-source.net/javascript_tutorial/… . Właściwie, w DOMscripting (js po stronie klienta w przeglądarce), wszystkie funkcje stają się metodami obiektu window (globalnej przestrzeni nazw) powiedziałbym (możesz odnieść się do wszystkich „samodzielnych” funkcji jako window. [Jakaś funkcja].
KooiInc

5

wprowadź opis obrazu tutaj

Czy chcesz mieć jedną instancję obiektu dla strony - Literal.

Czy chcesz po prostu przesłać dane, takie jak obiekty DTO, proste GET SET: - Literal

Czy chcesz tworzyć rzeczywiste obiekty z zachowaniami metod, wieloma instancjami - funkcja konstruktora, przestrzeganie zasad OOP, dziedziczenie: - funkcje konstruktora.

Poniżej znajduje się film z youtube, który szczegółowo wyjaśnia, co jest dosłowne, czym są funkcje konstruktora i czym się od siebie różnią.

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


1

Idź z dosłownością obiektu, jest bardziej zwięzła i lepiej się rozwija dzięki wprowadzeniu wartości początkowych.


Jak utworzyć zmienne prywatne w literale obiektu?
EhevuTov

Naprawdę nie możesz, nie ma to związku z pierwotnym pytaniem, więc podam ci link: javascript.crockford.com/private.html
Tom

1
Właściwie jest to istotne, ponieważ tam, gdzie jest różnica, istnieje powód, aby użyć jednej lub drugiej w zależności od pewnych sytuacji; w tym przypadku będzie to, czy chcesz mieć zmienne prywatne, czy nie. Możesz utworzyć zmienne prywatne w dosłownym, tworząc najpierw funkcję zamykającą w swoim dosłownym, ale moim zdaniem jest ona dużo brzydsza i trudniejsza do odczytania.
EhevuTov

Stoję poprawiony, moje pierwotne odczytanie pytania było takie, że chobo pytał o to, jak przekazać zmienne do konstruktora, jak w przypadku listy parametrów w porównaniu z parametrem dosłownym pojedynczego obiektu.
Tom



0

Właściwie wydaje mi się, że możemy mieć prywatne metody w literałach obiektów. Rozważ poniższy kod:

var myObject = {

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

}

Kwestia gustu, ale wolę używać literałów obiektów tam, gdzie jest to możliwe.


-1

// Literał obiektu i konstruktor obiektu

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
Gdzie w twoim przykładzie zadeklarowano literał Object?
JohnnyQ,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.