JavaScript'te nesne oluşturmak için en iyi yol hangisidir? Bir nesne özelliğinden önce “var` gerekli mi?


177

Şimdiye kadar JavaScript'te bir nesne oluşturmanın üç yolunu gördüm. Nesne oluşturmak için en iyi yol hangisidir ve neden?

Ayrıca tüm bu örneklerde anahtar kelimenin varbir özellikten önce kullanılmadığını gördüm - neden? varÖzelliklerin değişken olduğunu belirttiği gibi bir özellik adından önce bildirilmesi gerekli değil mi?

İkinci ve üçüncü şekilde, nesnenin adı büyük harf olurken, birinci şekilde nesnenin ismi küçük harftir. Bir nesne adı için hangi durumu kullanmalıyız?

İlk yol:

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

İkinci yol:

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

Robot.killAllHumans();

Üçüncü yol - dizi sözdizimini kullanan JavaScript nesneleri:

var NewObject = {};

NewObject['property1'] = value;
NewObject['property2'] = value;
NewObject['method'] = function(){ /* function code here */ }

2
"var" değişkenin kapsamına bağlı olarak kullanılır, global olanı tanımlar ya da tanımlamaz, arar ve farkı görürsünüz.
jackJoe

80
Eğer cinayet robotları var
yaratırsanız

9
"değişken değişkenin kapsamına bağlı olarak kullanılır" - bu KÖTÜ uygulama - hangi kapsamda olursanız olun kullanılmalıdır
treecoder

1
Yöntem ne olacak Object.create()?
Maksimum

“Özelliklerin değişken olduğu belirtildiği gibi” açıklığa kavuşturulması güzel olurdu . Kim o"? Nerede bahsediliyor? Belirli bir alıntı yapabilir misiniz?
user4642212

Yanıtlar:


181

En iyi yolu yoktur , kullanım durumunuza bağlıdır.

  • Birkaç benzer nesne oluşturmak istiyorsanız 1. yöntemi kullanın . Örneğinizde, Person(adı büyük harfle başlatmalısınız) yapıcı işlevi olarak adlandırılır . Bu, diğer OO dillerindeki sınıflara benzer .
  • Yalnızca bir tür nesneye (singleton gibi) ihtiyacınız varsa 2. yolu kullanın . Bu nesnenin başka bir nesneden miras almasını istiyorsanız, yine de bir yapıcı işlevi kullanmanız gerekir.
  • Nesnenin diğer özelliklerine bağlı olarak özelliklerini başlatmak istiyorsanız veya dinamik özellik adlarınız varsa, 3. yolu kullanın .

Güncelleme: Üçüncü yol için talep edilen örnekler.

Bağımlı özellikler:

Aşağıdaki gibi çalışmıyor thismu değil bakın book. Bir nesne değişmezindeki diğer özelliklerin değerlerine sahip bir özellik başlatmanın bir yolu yoktur:

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

bunun yerine şunları yapabilirsiniz:

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

Dinamik mülk adları:

Özellik adı bazı değişkenlerde depolanıyorsa veya bazı ifadelerle oluşturulmuşsa, parantez notasyonu kullanmanız gerekir:

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;

1
Cevabınız için teşekkürler ... şimdi böyle bir şey istiyorsak way1'i kullanabileceğimiz ilk noktanızı anladım myFather = new person ("John", "Doe", 50, "blue"); myMother = yeni kişi ("gazy", "Doe", 45, "kahverengi"); myBrother = yeni kişi ("anket", "Doe", 15, "mavi");
Jamna

Sanırım obj [name] = 42 demek istiyorsun, değil mi?
Keith Pinson

Seçenek 2 ve 3'ün neredeyse aynı olduğunu, yalnızca nesneyi yaptıktan sonra özellikleri atadığınızı belirtmek isterim. Değişmez gösterim olarak adlandırılan budur , çünkü nesnenizi oluşturmak için bir nesne değişmezi kullanırsınız. Kaputun altında, bu aslında "new Object ()" olarak adlandırılır. Bununla ilgili daha fazla bilgiyi buradan edinebilirsiniz: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…
dudewad

İkinci durumda, ...başka bir nesneden miras almak için forma operatörünü kullanmamız mantıklı olur mu?
paket çocuk

114

Bir işlevi tanımlamanın çeşitli yolları vardır. Tamamen sizin ihtiyacına dayalı. Aşağıda birkaç stil vardır: -

  1. Nesne Oluşturucu
  2. Değişmez kurucu
  3. Fonksiyon Tabanlı
  4. Protokol Tabanlı
  5. İşlev ve Prototip Temelli
  6. Singleton Bazlı

Örnekler:

  1. Nesne oluşturucu
var person = new Object();

person.name = "Anand",
person.getName = function(){
  return this.name ; 
};
  1. Değişmez kurucu
var person = { 
  name : "Anand",
  getName : function (){
   return this.name
  } 
} 
  1. işlev Yapıcı
function Person(name){
  this.name = name
  this.getName = function(){
    return this.name
  } 
} 
  1. Prototip
function Person(){};

Person.prototype.name = "Anand";
  1. İşlev / Prototip kombinasyonu
function Person(name){
  this.name = name;
} 
Person.prototype.getName = function(){
  return this.name
} 
  1. Singleton
var person = new function(){
  this.name = "Anand"
} 

Herhangi bir karışıklık varsa, konsolda deneyebilirsiniz.


HEy @Alex_Nabu - Gönderimdeki örnekleri zaten paylaştım. Hala herhangi bir sorunla karşılaşırsanız lütfen beni güncelleyin, size yardımcı olacağım
Anand Deep Singh

1
var personsonunda aynı örneği veren her örneği oluşturmak daha anlamlı olmaz mıydı ? örneğin basitçe ekleyebileceğiniz işlev yapıcısında var person = new Person("Anand"). ve görünüşte rastgele yarı kolon kullanımıyla ilgili ne var? : P
cregox

2
Her yönüyle artılarını ve eksilerini açıklayan değer katacaktır.
RayLoveless

10

Bir nesne oluşturmanın "en iyi yolu" yoktur. Kullanım şeklinize bağlı olarak her yolun faydaları vardır.

Yapıcı modeli ( newonu çağırmak için işleçle eşleştirilen bir işlev ) prototip palet mirasını kullanma imkanı sağlarken diğer yollar kullanmaz. Prototypal mirasını istiyorsanız, bir yapıcı işlevi gitmek için iyi bir yoldur.

Bununla birlikte, prototip palet mirasını kullanmak istiyorsanız Object.create, mirasınızı daha açık hale getiren de kullanabilirsiniz .

Bir nesne hazır bilgisi oluşturmak (ex:) var obj = {foo: "bar"};, oluşturma sırasında elinizde ayarlamak istediğiniz tüm özelliklere sahipseniz harika çalışır.

Daha sonra özellikleri ayarlamak için, söz NewObject.property1dizimi genellikle NewObject['property1']özellik adını biliyorsanız tercih edilir . Ancak, ikincisi, mülkün adının vaktinden önce olmadığında yararlıdır (örn:) NewObject[someStringVar].

Bu yardımcı olur umarım!


6

Sanırım ne istediğine bağlı. Basit nesneler için sanırım ikinci yöntemleri kullanabilirsiniz. Nesneleriniz büyüdükçe ve benzer nesneleri kullanmayı planladığınız zaman, sanırım ilk yöntem daha iyi olur. Bu şekilde prototipleri kullanarak da genişletebilirsiniz.

Misal:

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

Üçüncü yöntemin büyük bir hayranı değilim, ancak örneğin özellikleri dinamik olarak düzenlemek için gerçekten yararlı var foo='bar'; var bar = someObject[foo];.


3

Nesnelerinizi JavaScript'te oluşturmanın birçok yolu vardır. Bir nesne veya nesne değişmez notasyonu oluşturmak için yapıcı işlevinin kullanılması JavaScript'te çok şey kullanıyor. Ayrıca bir Object örneği oluşturma ve daha sonra buna özellikler ve yöntemler ekleme, JavaScript'te nesne oluşturmanın üç yaygın yolu vardır.

Yapıcı fonksiyonları

Tarih (), Number (), Boolean () vb.Gibi hepimizin kullanabileceği yerleşik yapıcı işlevleri vardır, tüm yapıcı işlevleri Büyük Harf ile başlar, bu arada JavaScript'te özel oluşturucu işlevi oluşturabiliriz bunun gibi:

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

yapıcı yeni bir örneği oluşturmak, aşağıdaki gibi bir şey oluşturmak ve dolgu parametreleri ile yapıcı işlevini çağırmak için new () kullanarak onu çağırabilirsiniz:

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

Nesne değişmez değerleri

Nesne değişmezlerini kullanmak, JavaScript'te nesne oluşturma durumunda çok kullanılır, bu basit bir nesne oluşturma örneği, tanımlandığı sürece nesne özelliklerinize her şeyi atayabilirsiniz:

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

Prototip

Bir Nesne oluşturduktan sonra, bunun için daha fazla üye prototipleyebilirsiniz, örneğin Kutumuza renk ekleyerek, bunu yapabiliriz:

Box.prototype.colour = 'red';

2

Buradaki birçok kişi nesne oluşturmak için en iyi yol olmadığını söylese de, 2019'dan itibaren JavaScript'te neden nesne oluşturmak için bu kadar çok yol olduğu konusunda bir mantık var ve bunun JavaScript'in farklı iterasyonlar üzerindeki ilerlemesi ile ilgisi var. 1997 yılına kadar uzanan EcmaScript sürümleri.

ECMAScript 5'ten önce, nesne oluşturmanın sadece iki yolu vardı: yapıcı işlevi veya değişmez gösterim (yeni Object () için daha iyi bir alternatif). Yapıcı işlev gösterimi ile, birden çok örneğe (yeni anahtar sözcükle) örneklenebilecek bir nesne oluştururken, değişmez gösterim bir singleton gibi tek bir nesne sunar.

// constructor function
function Person() {};

// literal notation
var Person = {};

Kullandığınız yönteme bakılmaksızın, JavaScript nesneleri yalnızca anahtar / değer çiftlerinin özellikleridir:

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

JavaScript'in ilk sürümlerinde, sınıf tabanlı kalıtmayı taklit etmenin tek gerçek yolu yapıcı işlevlerini kullanmaktı. yapıcı işlevi, 'yeni' anahtar kelimeyle çağrılan özel bir işlevdir. Kural olarak, fonksiyon tanımlayıcısı büyük harfle yazılır, ancak zorunlu değildir. Yapıcı içinde, yapıcı işlevinin dolaylı olarak oluşturduğu nesneye özellikler eklemek için 'this' anahtar sözcüğüne başvururuz. Yapıcı işlevi, açıkça döndürülen anahtar sözcüğü ve başka bir şey döndürmediğiniz sürece, doldurulmuş özelliklere sahip yeni nesneyi dolaylı olarak arama işlevine dolaylı olarak döndürür.

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

SayName yöntemiyle ilgili bir sorun var. Genellikle, Nesneye Dayalı Sınıf tabanlı programlama dillerinde, nesneleri nesne oluşturmak için fabrika olarak kullanırsınız. Her nesnenin kendi örnek değişkenleri olacaktır, ancak sınıf planında tanımlanan yöntemlere bir işaretçi olacaktır. Ne yazık ki, JavaScript'in yapıcı işlevini kullanırken, her çağrıldığında, yeni oluşturulan nesne üzerinde yeni bir sayName özelliği tanımlayacaktır. Böylece her nesnenin kendine özgü sayName özelliği olacaktır. Bu, daha fazla bellek kaynağı tüketecektir.

Artırılmış bellek kaynaklarına ek olarak, yapıcı işlevinin içindeki yöntemleri tanımlamak, kalıtım olasılığını ortadan kaldırır. Yine, yöntem yeni oluşturulan nesnede bir özellik olarak tanımlanacak ve başka bir nesne olmayacak, bu nedenle miras böyle çalışamaz. Dolayısıyla JavaScript, prototip zincirini kalıtım biçimi olarak sunarak JavaScript'i prototip bir dil haline getirir.

Bir ebeveyniniz varsa ve bir ebeveyniniz bir çocuğun birçok özelliğini paylaşıyorsa, çocuk bu özellikleri miras almalıdır. ES5'ten önce şu şekilde gerçekleştirildi:

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

Yukarıdaki prototip zincirini kullanma şeklimizin bir tuhaflığı var. Prototip canlı bir bağlantı olduğundan, prototip zincirindeki bir nesnenin özelliğini değiştirerek, başka bir nesnenin aynı özelliğini de değiştirmiş olursunuz. Açıkçası, bir çocuğun kalıtsal yöntemini değiştirmek ebeveynin yöntemini değiştirmemelidir. Object.create, bu sorunu bir çoklu dolgu kullanarak çözdü. Böylece, Object.create ile, bir çocuğun prototip zincirindeki özelliğini, ebeveynin prototip zincirindeki aynı özelliğini etkilemeden güvenle değiştirebilirsiniz.

ECMAScript 5, nesne oluşturma için yapıcı işlevinde yukarıda belirtilen hatayı çözmek için Object.create öğesini tanıttı. Object.create () yöntemi, varolan bir nesneyi yeni oluşturulan nesnenin prototipi olarak kullanarak yeni bir nesne OLUŞTURUR. Yeni bir nesne oluşturulduğundan, artık prototip zincirindeki child özelliğinin değiştirilmesinin, üst öğenin zincirdeki o özelliğe başvurusunu değiştirmesi sorununuz yoktur.

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.

ES6'dan önce, işlev yapıcılarını ve Object.create'i kullanmak için yaygın bir yaratıcı model vardı:

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

Şimdi yapıcı işlevleriyle birleştirilmiş Object.create, JavaScript'te nesne oluşturma ve kalıtım için yaygın olarak kullanılmaktadır. Bununla birlikte, ES6, JavaScript'in mevcut prototip tabanlı kalıtım üzerinde sözdizimsel şeker olan sınıflar kavramını tanıttı. Sınıf sözdizimi, JavaScript'e yeni bir nesne tabanlı miras modeli getirmez. Böylece, JavaScript prototip bir dil olarak kalır.

ES6 sınıfları kalıtımı çok daha kolay hale getirir. Artık üst sınıfın prototip işlevlerini el ile kopyalamamız ve alt sınıfın yapıcısını sıfırlamamız gerekmiyor.

// 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

Sonuçta, JavaScript'te bu 5 farklı Nesne Oluşturma stratejisi EcmaScript standardının evrimine denk geldi.


0

Elbette en iyi yol var.Javascript'teki nesneler numaralandırılabilir ve sayılamaz özelliklere sahiptir.

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

Yukarıdaki örnekte, boş bir nesnenin gerçekten özelliklere sahip olduğunu görebilirsiniz.

İlk önce hangisinin en iyi yol olduğunu görelim:

var new_object = Object.create(null)

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

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

Yukarıdaki örnekte günlük yanlış çıktı verecektir.

Şimdi diğer nesne oluşturma yollarının neden yanlış olduğunu görelim.

//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

Yukarıda da görebileceğiniz gibi, tüm örnekler true değerini for inverir. Bu, nesnenin bir özelliğe sahip olup olmadığını görmek için bir döngünüz olduğu anlamına gelirse , muhtemelen yanlış sonuçlara yol açacaktır.

En iyi yolun kolay olmadığını unutmayın. Nesnenin tüm özelliklerini satır satır tanımlamanız gerekir.Diğer yollar daha kolaydır ve bir nesne oluşturmak için daha az kod içerir, ancak bazı durumlarda farkında olmanız gerekir. Ben her zaman "diğer yolları" arada ve en iyi yolu kullanmıyorsanız yukarıdaki uyarı için bir çözüm kullanın:

 for (var property in new_object) {
  if (new_object.hasOwnProperty(property)) {
    // ... this is an own property
  }
 }

0

Çoğunlukla Nesneler oluşturmanın 3 yolu vardır.

En basit olanı nesne değişmez değerleri kullanmaktır .

const myObject = {}

Bu yöntem en basit olmasına rağmen bir dezavantaja sahip olsa da, yani nesneniz davranış (işlevler) varsa, gelecekte herhangi bir değişiklik yapmak istiyorsanız, tüm nesnelerde değiştirmeniz gerekir .

Bu durumda, Fabrika veya Yapıcı İşlevlerini kullanmak daha iyidir. (İstediğiniz herkes)

Fabrika İşlevleri , bir nesne döndüren işlevlerdir.

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

Yapıcı İşlevleri , "this" keyword.eg- kullanarak nesnelere özellik atayan işlevlerdir

function constructorFunc(exampleValue){
   this.exampleProperty= exampleValue;
}
const myObj= new constructorFunc(1);
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.