Który sposób jest najlepszy do tworzenia obiektu w JavaScript? Czy argument „var” jest konieczny przed właściwością obiektu?

177

Do tej pory widziałem trzy sposoby tworzenia obiektu w JavaScript. Który sposób jest najlepszy do tworzenia obiektu i dlaczego?

Widziałem również, że we wszystkich tych przykładach słowo kluczowe varnie jest używane przed właściwością - dlaczego? Czy nie jest konieczne zadeklarowanie varprzed nazwą właściwości, ponieważ wspomniano, że właściwości są zmiennymi?

W drugim i trzecim przypadku nazwa obiektu jest zapisana wielkimi literami, w pierwszym przypadku nazwa obiektu jest pisana małymi literami. Jakiego przypadku powinniśmy użyć dla nazwy obiektu?

Pierwszy sposób:

function person(fname, lname, age, eyecolor){
  this.firstname = fname;
  this.lastname = lname;
  this.age = age;
  this.eyecolor = eyecolor;
}

myFather = new person("John", "Doe", 50, "blue");
document.write(myFather.firstname + " is " + myFather.age + " years old.");

Drugi sposób:

var Robot = {
  metal: "Titanium",
  killAllHumans: function(){
    alert("Exterminate!");
  }
};

Robot.killAllHumans();

Trzeci sposób - obiekty JavaScript wykorzystujące składnię tablicową:

var NewObject = {};

NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }
Jamna
źródło
2
"var" jest używany w zależności od zakresu zmiennej, definiuje globalny lub nie, przeszukaj go, a zobaczysz różnicę.
jackJoe
80
jeśli tworzysz zabójcze roboty, zawsze używaj var, proszę ... pomijanie tego sprawia, że ​​stają się one globalne
mykhal
9
„var jest używany w zależności od zakresu zmiennej” - to ZŁA praktyka - powinno się jej używać bez względu na to, w jakim zakresie się znajdujesz
treecoder
1
A co z metodą Object.create():?
Max
Byłoby miło, gdyby wyjaśniono, „jak wspomniano, że właściwości są zmiennymi” . Kto to jest"? Gdzie to jest wspomniane? Czy możesz podać konkretny cytat?
user4642212

Odpowiedzi:

181

Nie ma najlepszego sposobu, zależy to od twojego przypadku użycia.

  • Skorzystaj ze sposobu 1, jeśli chcesz utworzyć kilka podobnych obiektów. W Personnaszym przykładzie (nazwę należy rozpocząć od dużej litery) nazywamy funkcją konstruktora . Jest to podobne do zajęć w innych językach obiektowych.
  • Użyj sposobu 2, jeśli potrzebujesz tylko jednego rodzaju obiektu (np. Singletona). Jeśli chcesz, aby ten obiekt dziedziczył po innym, musisz jednak użyć funkcji konstruktora.
  • Użyj sposobu 3, jeśli chcesz zainicjować właściwości obiektu w zależności od innych jego właściwości lub jeśli masz dynamiczne nazwy właściwości.

Aktualizacja: zgodnie z żądanymi przykładami dla trzeciego sposobu.

Zależne właściwości:

Poniższa nie działa jak thisma nie dotyczą book. Nie ma możliwości zainicjowania właściwości wartościami innych właściwości w literale obiektu:

var book = {
    price: somePrice * discount,
    pages: 500,
    pricePerPage: this.price / this.pages
};

zamiast tego możesz zrobić:

var book = {
    price: somePrice * discount,
    pages: 500
};
book.pricePerPage = book.price / book.pages;
// or book['pricePerPage'] = book.price / book.pages;

Dynamiczne nazwy właściwości:

Jeśli nazwa właściwości jest przechowywana w jakiejś zmiennej lub utworzona za pomocą jakiegoś wyrażenia, musisz użyć notacji nawiasowej:

var name = 'propertyName';

// the property will be `name`, not `propertyName`
var obj = {
    name: 42
}; 

// same here
obj.name = 42;

// this works, it will set `propertyName`
obj[name] = 42;
Felix Kling
źródło
1
dzięki za odpowiedź ... teraz zrozumiałem twoją pierwszą kwestię, możemy użyć way1, jeśli chcemy czegoś takiego, jak ten mójFather = nowa osoba („John”, „Doe”, 50, „blue”); mojaMatka = nowa osoba ("gazy", "Łania", 45, "brązowy"); myBrother = nowa osoba ("ankieta", "Doe", 15, "niebieski");
Jamna
Myślę, że masz na myśli obj [imię] = 42. Zgadza się?
Keith Pinson
Chciałbym zaznaczyć, że opcje 2 i 3 są praktycznie identyczne, tylko że przypisujesz właściwości po utworzeniu obiektu. Nazywa się to notacją dosłowną , ponieważ do tworzenia obiektu używasz literału obiektu. W gruncie rzeczy to faktycznie wywołuje „nowy obiekt ()”. Możesz przeczytać więcej na ten temat tutaj: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/ ...
dudewad
W drugim przypadku, czy miałoby to sens, gdybyśmy użyli operatora spreadu ...do dziedziczenia z innego obiektu?
6
114

Istnieje wiele sposobów definiowania funkcji. Jest całkowicie oparty na twoich wymaganiach. Poniżej znajduje się kilka stylów: -

  1. Konstruktor obiektów
  2. Konstruktor dosłowny
  3. Oparte na funkcjach
  4. Na bazie Protoype
  5. Oparte na funkcjach i prototypach
  6. Oparty na singletonie

Przykłady:

  1. Konstruktor obiektów
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. Konstruktor dosłowny
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. function Constructor
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. Prototyp
function Person(){};

Person.prototype.name = "Anand";
  1. Połączenie funkcji / prototypu
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. Singel
var person = new function(){
  this.name = "Anand"
} 

Możesz to wypróbować na konsoli, jeśli masz jakieś zamieszanie.

Anand Deep Singh
źródło
HEy @Alex_Nabu - już podzieliłem się przykładami w moim poście. Jeśli nadal napotkasz jakieś wyzwania, poinformuj mnie o tym, pomogę ci.
Anand Deep Singh
1
Czy nie byłoby sensowniej budować każdy przykład, który ostatecznie daje dokładnie tę samą var personinstancję? na przykład w konstruktorze funkcji możesz po prostu dodać var person = new Person("Anand"). i o co chodzi z pozornie przypadkowym użyciem średnika? : P
cregox
2
Dodałoby to wartości wyjaśniającej zalety i wady każdego sposobu.
RayLoveless
10

Nie ma „najlepszego sposobu” tworzenia obiektu. Każdy sposób ma zalety w zależności od przypadku użycia.

Wzorzec konstruktora (funkcja sparowana z newoperatorem w celu jej wywołania) zapewnia możliwość korzystania z dziedziczenia prototypowego, podczas gdy inne sposoby nie. Jeśli więc chcesz dziedziczenia prototypowego, dobrym rozwiązaniem będzie funkcja konstruktora.

Jeśli jednak chcesz dziedziczenia prototypowego, równie dobrze możesz użyć Object.create, co sprawia, że ​​dziedziczenie jest bardziej oczywiste.

Tworzenie literału obiektu (np:) var obj = {foo: "bar"};działa świetnie, jeśli masz wszystkie właściwości, które chcesz ustawić w czasie tworzenia.

W przypadku późniejszego ustawiania właściwości NewObject.property1składnia jest ogólnie lepsza niż w NewObject['property1']przypadku znajomości nazwy właściwości. Ale to drugie jest przydatne, gdy w rzeczywistości nie znasz nazwy właściwości z wyprzedzeniem (np .:) NewObject[someStringVar].

Mam nadzieję że to pomoże!

jimbo
źródło
6

Myślę, że to zależy od tego, czego chcesz. W przypadku prostych obiektów myślę, że można by użyć drugiej metody. Kiedy twoje obiekty rosną i planujesz użyć podobnych obiektów, myślę, że pierwsza metoda byłaby lepsza. W ten sposób możesz go również rozszerzyć za pomocą prototypów.

Przykład:

function Circle(radius) {
    this.radius = radius;
}
Circle.prototype.getCircumference = function() {
    return Math.PI * 2 * this.radius;
};
Circle.prototype.getArea = function() {
    return Math.PI * this.radius * this.radius;
}

Nie jestem wielkim fanem trzeciej metody, ale jest ona bardzo przydatna na przykład do dynamicznej edycji właściwości var foo='bar'; var bar = someObject[foo];.

Daan Wilmer
źródło
3

Istnieje wiele sposobów tworzenia obiektów w JavaScript. Używanie funkcji konstruktora do tworzenia obiektu lub notacji literału obiektowego jest dużo używane w JavaScript. Tworząc instancję Object, a następnie dodając do niej właściwości i metody, istnieją trzy typowe sposoby tworzenia obiektów w JavaScript.

Funkcje konstruktora

Istnieją wbudowane funkcje konstruktora, z których wszyscy możemy korzystać od czasu do czasu, takie jak Date (), Number (), Boolean () itp., Wszystkie funkcje konstruktora zaczynają się od wielkiej litery, w międzyczasie możemy stworzyć niestandardową funkcję konstruktora w JavaScript lubię to:

function Box (Width, Height, fill) {  
  this.width = Width;  // The width of the box 
  this.height = Height;  // The height of the box 
  this.fill = true;  // Is it filled or not?
}  

i możesz go wywołać, po prostu używając new (), aby utworzyć nową instancję konstruktora, stworzyć coś takiego jak poniżej i wywołać funkcję konstruktora z wypełnionymi parametrami:

var newBox = new Box(8, 12, true);  

Literały obiektów

Używanie literałów obiektowych jest bardzo używanym przypadkiem tworzenia obiektu w JavaScript, to przykład tworzenia prostego obiektu, możesz przypisać wszystko do swoich właściwości obiektu, o ile są zdefiniowane:

var person = { 
    name: "Alireza",
    surname: "Dezfoolian"
    nose: 1,  
    feet: 2,  
    hands: 2,
    cash: null
};  

Prototypowanie

Po utworzeniu obiektu możesz prototypować więcej członków, na przykład dodając kolor do naszego Boxa, możemy zrobić to:

Box.prototype.colour = 'red';
Alireza
źródło
2

Chociaż wiele osób twierdzi, że nie ma najlepszego sposobu tworzenia obiektów, istnieje uzasadnienie, dlaczego istnieje tak wiele sposobów tworzenia obiektów w JavaScript od 2019 r., A ma to związek z postępem JavaScript w różnych iteracjach wydań EcmaScript z 1997 roku.

Przed ECMAScript 5 istniały tylko dwa sposoby tworzenia obiektów: funkcja konstruktora lub notacja dosłowna (lepsza alternatywa dla new Object ()). Za pomocą notacji funkcji konstruktora tworzysz obiekt, którego instancję można utworzyć w wielu instancjach (za pomocą słowa kluczowego new), podczas gdy notacja literału dostarcza pojedynczy obiekt, taki jak singleton.

// constructor function
function Person() {};

// literal notation
var Person = {};

Niezależnie od zastosowanej metody obiekty JavaScript są po prostu właściwościami par klucz-wartość:

// Method 1: dot notation
obj.firstName = 'Bob';

// Method 2: bracket notation. With bracket notation, you can use invalid characters for a javascript identifier.
obj['lastName'] = 'Smith';

// Method 3: Object.defineProperty
Object.defineProperty(obj, 'firstName', {
    value: 'Bob',
    writable: true,
    configurable: true,
    enumerable: false
})

// Method 4: Object.defineProperties
Object.defineProperties(obj, {
  firstName: {
    value: 'Bob',
    writable: true
  },
  lastName: {
    value: 'Smith',
    writable: false
  }
});

We wczesnych wersjach JavaScript jedynym prawdziwym sposobem naśladowania dziedziczenia opartego na klasach było użycie funkcji konstruktora. funkcja konstruktora jest specjalną funkcją wywoływaną za pomocą słowa kluczowego „new”. Zgodnie z konwencją identyfikator funkcji jest pisany wielkimi literami, ale nie jest to wymagane. Wewnątrz konstruktora odwołujemy się do słowa kluczowego „this”, aby dodać właściwości do obiektu, który funkcja konstruktora niejawnie tworzy. Funkcja konstruktora niejawnie zwraca nowy obiekt z wypełnionymi właściwościami z powrotem do funkcji wywołującej niejawnie, chyba że jawnie użyjesz słowa kluczowego return i zwrócisz coś innego.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.sayName = function(){
        return "My name is " + this.firstName + " " + this.lastName;
    }
} 

var bob = new Person("Bob", "Smith");
bob instanceOf Person // true

Wystąpił problem z metodą sayName. Zazwyczaj w językach programowania opartych na klasach zorientowanych obiektowo używa się klas jako fabryk do tworzenia obiektów. Każdy obiekt będzie miał własne zmienne instancji, ale będzie miał wskaźnik do metod zdefiniowanych w schemacie klasy. Niestety, podczas korzystania z funkcji konstruktora JavaScript, za każdym razem, gdy jest ona wywoływana, definiuje nową właściwość sayName w nowo utworzonym obiekcie. Zatem każdy obiekt będzie miał swoją własną unikalną właściwość sayName. Spowoduje to zużycie większej ilości zasobów pamięci.

Oprócz zwiększonych zasobów pamięci, zdefiniowanie metod wewnątrz funkcji konstruktora eliminuje możliwość dziedziczenia. Ponownie, metoda zostanie zdefiniowana jako właściwość nowo utworzonego obiektu i żadnego innego obiektu, więc dziedziczenie nie może działać tak, jak. W związku z tym JavaScript zapewnia łańcuch prototypów jako formę dziedziczenia, czyniąc JavaScript językiem prototypowym.

Jeśli masz rodzica, a rodzic ma wiele wspólnych cech dziecka, to dziecko powinno odziedziczyć te właściwości. Przed ES5 było to realizowane w następujący sposób:

function Parent(eyeColor, hairColor) {
    this.eyeColor = eyeColor;
    this.hairColor = hairColor;
}

Parent.prototype.getEyeColor = function() {
  console.log('has ' + this.eyeColor);
}

Parent.prototype.getHairColor = function() {
  console.log('has ' + this.hairColor);
}

function Child(firstName, lastName) {
  Parent.call(this, arguments[2], arguments[3]);
  this.firstName = firstName;
  this.lastName = lastName;
}

Child.prototype = Parent.prototype;

var child = new Child('Bob', 'Smith', 'blue', 'blonde');
child.getEyeColor(); // has blue eyes
child.getHairColor(); // has blonde hair

Sposób, w jaki wykorzystaliśmy powyższy łańcuch prototypów, jest dziwny. Ponieważ prototyp jest aktywnym łączem, zmieniając właściwość jednego obiektu w łańcuchu prototypów, zmieniasz również tę samą właściwość innego obiektu. Oczywiście zmiana odziedziczonej metody dziecka nie powinna zmienić metody rodzica. Object.create rozwiązało ten problem przy użyciu polyfill. Tak więc za pomocą Object.create można bezpiecznie modyfikować właściwość dziecka w łańcuchu prototypów bez wpływu na tę samą właściwość rodzica w łańcuchu prototypów.

ECMAScript 5 wprowadził Object.create, aby rozwiązać wyżej wymieniony błąd w funkcji konstruktora do tworzenia obiektów. Metoda Object.create () TWORZY nowy obiekt, używając istniejącego obiektu jako prototypu nowo utworzonego obiektu. Ponieważ tworzony jest nowy obiekt, nie występuje już problem polegający na tym, że modyfikacja właściwości potomnej w łańcuchu prototypów zmodyfikuje odniesienie rodzica do tej właściwości w łańcuchu.

var bobSmith = {
    firstName: "Bob",
    lastName: "Smith",
    sayName: function(){
      return "My name is " + this.firstName + " " + this.lastName;
    }
}

var janeSmith = Object.create(bobSmith, {
    firstName : {  value: "Jane" }
})

console.log(bobSmith.sayName()); // My name is Bob Smith
console.log(janeSmith.sayName()); // My name is Jane Smith
janeSmith.__proto__ == bobSmith; // true
janeSmith instanceof bobSmith; // Uncaught TypeError: Right-hand side of 'instanceof' is not callable. Error occurs because bobSmith is not a constructor function.

Przed ES6 istniał wspólny wzorzec tworzenia wykorzystujący konstruktory funkcji i Object.create:

const View = function(element){
  this.element = element;
}

View.prototype = {
  getElement: function(){
    this.element
  }
}

const SubView = function(element){
  View.call(this, element);
}

SubView.prototype = Object.create(View.prototype);

Obecnie Object.create w połączeniu z funkcjami konstruktora jest szeroko stosowany do tworzenia i dziedziczenia obiektów w JavaScript. Jednak ES6 wprowadził koncepcję klas, które są przede wszystkim cukrem syntaktycznym w stosunku do istniejącego dziedziczenia opartego na prototypach JavaScript. Składnia klas nie wprowadza do JavaScript nowego modelu dziedziczenia zorientowanego obiektowo. Zatem JavaScript pozostaje językiem prototypowym.

Klasy ES6 znacznie ułatwiają dziedziczenie. Nie musimy już ręcznie kopiować funkcji prototypowych klasy nadrzędnej i resetować konstruktora klasy potomnej.

// create parent class
class Person {
  constructor (name) {
    this.name = name;
  }
}

// create child class and extend our parent class
class Boy extends Person {
  constructor (name, color) {
    // invoke our parent constructor function passing in any required parameters
    super(name);

    this.favoriteColor = color;
  }
}

const boy = new Boy('bob', 'blue')
boy.favoriteColor; // blue

Podsumowując, te 5 różnych strategii tworzenia obiektów w JavaScript zbiegło się z ewolucją standardu EcmaScript.

Donato
źródło
0

Oczywiście jest najlepszy sposób: obiekty w javascript mają wyliczalne i niepoliczalne właściwości.

var empty = {};
console.log(empty.toString);
// . function toString(){...}
console.log(empty.toString());
// . [object Object]

W powyższym przykładzie widać, że pusty obiekt w rzeczywistości ma właściwości.

Ok, najpierw zobaczmy, który sposób jest najlepszy:

var new_object = Object.create(null)

new_object.name = 'Roland'
new_object.last_name = 'Doda'
//etc

console.log("toString" in new_object) //=> false

W powyższym przykładzie dziennik zwróci wartość false.

Zobaczmy teraz, dlaczego inne sposoby tworzenia obiektów są nieprawidłowe.

//Object constructor
var object = new Object();

console.log("toString" in object); //=> true

//Literal constructor
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 

console.log("toString" in person); //=> true

//function Constructor
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
}

var person = new Person ('landi')

console.log("toString" in person); //=> true

//Prototype
function Person(){};

Person.prototype.name = "Anand";

console.log("toString" in person); //=> true

//Function/Prototype combination
function Person2(name){
  this.name = name;
} 

Person2.prototype.getName = function(){
  return this.name
}

var person2 = new Person2('Roland')

console.log("toString" in person2) //=> true

Jak widać powyżej, wszystkie przykłady są rejestrowane jako prawda, co oznacza, że ​​jeśli masz przypadek, że masz for inpętlę sprawdzającą, czy obiekt ma właściwość, prawdopodobnie doprowadzi Cię do błędnych wyników.

Zauważ, że najlepszy sposób nie jest łatwy - musisz zdefiniować wszystkie właściwości obiektu wiersz po wierszu, inne sposoby są prostsze i będą wymagały mniej kodu do stworzenia obiektu, ale w niektórych przypadkach musisz być tego świadomy. Przy okazji zawsze używam „innych sposobów”, a jednym z rozwiązań powyższego ostrzeżenia, jeśli nie używasz najlepszego sposobu, jest:

 for (var property in new_object) {
  if (new_object.hasOwnProperty(property)) {
    // ... this is an own property
  }
 }
roli roli
źródło
0

Przede wszystkim istnieją 3 sposoby tworzenia obiektów -

Najprostszym jest użycie literałów obiektowych .

const myObject = {}

Chociaż ta metoda jest najprostsza, ale ma wadę, tj. Jeśli twój obiekt ma zachowanie (funkcje w nim), to w przyszłości, jeśli chcesz wprowadzić do niego jakiekolwiek zmiany, będziesz musiał to zmienić we wszystkich obiektach .

W takim przypadku lepiej jest użyć funkcji Factory lub Constructor. (Każdy, kogo lubisz)

Funkcje fabryki to te funkcje, które zwracają obiekt. Np.

function factoryFunc(exampleValue){
   return{
      exampleProperty: exampleValue 
   }
}

Funkcje konstruktora to te funkcje, które przypisują właściwości do obiektów za pomocą słowa kluczowego „this”.

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
shivam bansal
źródło