Javascript'teki yapılar


112

Önceden, bir dizi ilgili değişkeni saklamam gerektiğinde, bir sınıf oluşturuyordum.

function Item(id, speaker, country) {
    this.id = id;
    this.speaker = spkr;
    this.country = country;
}
var myItems = [
    new Item(1, 'john', 'au'),
    new Item(2, 'mary', 'us')
];

Ama bunun iyi bir uygulama olup olmadığını merak ediyorum. Javascript'te bir yapıyı simüle etmenin başka, daha iyi yolları var mı?

Yanıtlar:


184

Nesne değişmezleri ile oluşturulan nesneler arasındaki tek fark, prototipten miras alınan özelliklerdir.

var o = {
  'a': 3, 'b': 4,
  'doStuff': function() {
    alert(this.a + this.b);
  }
};
o.doStuff(); // displays: 7

Bir yapı fabrikası yapabilirsin.

function makeStruct(names) {
  var names = names.split(' ');
  var count = names.length;
  function constructor() {
    for (var i = 0; i < count; i++) {
      this[names[i]] = arguments[i];
    }
  }
  return constructor;
}

var Item = makeStruct("id speaker country");
var row = new Item(1, 'john', 'au');
alert(row.speaker); // displays: john

27
... ve sonra fabrika işlevlerini anladım. Fabrika örneğiyle birlikte açık, anlaşılır ve özlü bir cevap için +1.
John

Bu yaklaşımı seviyorum, ancak closure derleyicisini kullanıyorsanız dikkatli olun. Bu durumda tuple'a yalnızca dize olarak erişilebilir, çünkü özellikler yeniden adlandırılır. (En azından gelişmiş modda)
kap

Bu yöntemin nesne değişmezleri üzerindeki etkinliğini merak ediyordum.
c0degeas

JS sınıfını kullanmak da mümkündür.
SphynxTech

31

Ben her zaman nesne değişmezlerini kullanırım

{id: 1, speaker:"john", country: "au"}

2
bu, bakımı (gelecekte yeni bir alan eklemek istemeniz gerekir) ve ayrıca çok daha fazla kod (her seferinde "id", "hoparlör", "ülke" yazmak) yapmayı çok daha zorlaştırmaz mı?
nickf

5
Bu, sınıflarla ilgili çözüm kadar sürdürülebilirdir çünkü JavaScript, işlevi çağırdığınız argümanların sayısını umursamaz. Emacs gibi doğru araçları kullanıyorsanız, yeniden yazmak sorun olmaz. Ve argümanların değiş tokuşu gibi hataları geçersiz kılan neyin eşit olduğunu görebilirsiniz.
vava

4
Ancak en büyük profesyonel, daha az kod yazmanız ve daha temizlemeniz :)
vava

1
@vava yeniden yazmak, yeni ___ (,,,) arketipini kopyalamaktan daha fazla atlama olduğu için hala bir sorundur. Ayrıca okunabilirlik yok. Kodlamaya alıştığınızda, new READABLE_PART(ignore everything in here)kafanızdakinin aksine çok taranabilir ve kendi kendini belgeleyen hale gelir {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PART. İlk sürüm hızlı bir şekilde sayfalanırken okunabilir. İkincisi, yalnızca anlamak için yapılara yeniden düzenleme yaparsınız.
Christopher

19

Gerçek sorun, bir dildeki yapıların referans türleri değil değer türleri olmaları gerektiğidir. Önerilen yanıtlar, yapılar yerine nesnelerin (referans türleridir) kullanılmasını önermektedir. Bu amacına hizmet edebilirken, bir programcının referans türü yerine değer türlerini (ilkel gibi) kullanmanın faydalarını gerçekten isteyeceği noktasından kaçınıyor. Öncelikle değer türleri bellek sızıntılarına neden olmamalıdır.


8

Sanırım sizin yaptığınız gibi C benzeri yapıları simüle etmek için bir sınıf oluşturmak en iyi yoldur.

İlgili verileri gruplamanın harika bir yoludur ve parametrelerin işlevlere aktarılmasını kolaylaştırır. Ayrıca, gerçek nesne yönelimli özellikleri simüle etmek için gereken ek çabayı göz önünde bulundurarak, bir JavaScript sınıfının bir C ++ sınıfından çok bir C ++ yapısına benzediğini iddia ediyorum .

JavaScript'i başka bir dile daha çok benzetmeye çalışmanın hızla karmaşıklaştığını keşfettim, ancak JavaScript sınıflarını işlevsiz yapılar olarak kullanmayı tamamen destekliyorum.


Yapılar, demetler gibi
derekdreery

4

Markus'un cevabını takiben , JS'nin daha yeni sürümlerinde (ES6) daha basit bir şekilde Arrow Fonksiyonları ve Rest Parametresini kullanarak bir 'yapı' fabrikası oluşturabilirsiniz :

const Struct = (...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {}))
const Item = Struct('id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

Bunu çalıştırmanın sonucu:

[ { id: 1, speaker: 'john', country: 'au' },
  { id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

Python'un adlandırılmış çiftine benzer görünmesini sağlayabilirsiniz:

const NamedStruct = (name, ...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {_name: name}))
const Item = NamedStruct('Item', 'id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

Ve sonuçlar:

[ { _name: 'Item', id: 1, speaker: 'john', country: 'au' },
  { _name: 'Item', id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

C / C ++ ve diğer dillerdeki yapıya benziyor, ama aslında öyle değil - nesnelerdeki özelliklerin aşağıdaki şekilde açıklanması garanti edilmez: ECMAScript Üçüncü Baskıdan Bir Nesnenin Tanımı (pdf): 4.3.3 Nesne Bir nesne, Object türünün bir üyesidir. Her biri ilkel bir değer, nesne veya işlev içeren sırasız bir özellik koleksiyonudur. Bir nesnenin özelliğinde depolanan bir işleve yöntem denir
tibetty

3

Aptal yapılar için nesneler JSON stili kullanıyorum (üye işlevi yok).


1

ES6 uyumluluğuyla çalışıyorsanız yapıyı tanımlamak için küçük bir kitaplık yaptım.

Bu bir JKT ayrıştırıcısıdır, buradan proje havuzunu kontrol edebilirsiniz JKT Parser

Bir örnek için yapınızı böyle oluşturabilirsiniz

const Person = jkt`
    name: String
    age: Number
`

const someVar = Person({ name: "Aditya", age: "26" })

someVar.name // print "Aditya"
someVar.age // print 26 (integer)

someVar.toJSON() // produce json object with defined schema 

0

Kurulum için daha fazla iş var, ancak sürdürülebilirlik bir defalık çabayı yeniyorsa, o zaman bu sizin durumunuz olabilir.

/**
 * @class
 */
class Reference {

    /**
     * @constructs Reference
     * @param {Object} p The properties.
     * @param {String} p.class The class name.
     * @param {String} p.field The field name.
     */
    constructor(p={}) {
        this.class = p.class;
        this.field = p.field;
    }
}

Avantajları:

  • argüman sırasına bağlı değil
  • kolayca uzatılabilir
  • komut dosyası desteği yazın:

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

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.