โครงสร้างใน Javascript


112

ก่อนหน้านี้เมื่อฉันต้องการจัดเก็บตัวแปรที่เกี่ยวข้องจำนวนหนึ่งฉันจะสร้างคลาส

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

แต่ฉันสงสัยว่านี่เป็นแนวทางปฏิบัติที่ดี มีวิธีอื่นที่ดีกว่าในการจำลองโครงสร้างใน Javascript หรือไม่?

คำตอบ:


184

ความแตกต่างเพียงอย่างเดียวระหว่างตัวอักษรวัตถุและวัตถุที่สร้างขึ้นคือคุณสมบัติที่สืบทอดมาจากต้นแบบ

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

คุณสามารถสร้างโรงงานโครงสร้าง

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
... แล้วฉันก็เข้าใจฟังก์ชั่นของโรงงาน +1 สำหรับคำตอบที่ชัดเจนเข้าใจและกระชับพร้อมตัวอย่างโรงงาน
ยอห์น

ฉันชอบแนวทางนี้อย่างไรก็ตามโปรดระวังหากคุณใช้คอมไพเลอร์การปิด ทูเปิลสามารถเข้าถึงได้ในรูปแบบสตริงเท่านั้นในกรณีนี้เนื่องจากคุณสมบัติถูกเปลี่ยนชื่อ (อย่างน้อยในโหมดขั้นสูง)
kap

ฉันอยากรู้เกี่ยวกับประสิทธิภาพของวิธีนี้มากกว่าตัวอักษรของวัตถุ
c0degeas

อาจเป็นไปได้ที่จะใช้คลาส JS
SphynxTech

31

ฉันใช้ตัวอักษรวัตถุเสมอ

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

2
นั่นจะไม่ทำให้ยากต่อการดูแลรักษา (คุณควรจะเพิ่มช่องใหม่ในอนาคต) และโค้ดอื่น ๆ อีกมากมาย (พิมพ์ "id", "speaker", "country" ทุกครั้ง)
nickf

5
มันสามารถบำรุงรักษาได้เหมือนกับโซลูชันที่มีคลาสเนื่องจาก JavaScript ไม่สนใจเกี่ยวกับจำนวนอาร์กิวเมนต์ที่คุณเรียกใช้ฟังก์ชันด้วย การย้อนกลับไม่ใช่ปัญหาหากคุณใช้เครื่องมือที่เหมาะสมเช่น Emacs และคุณสามารถดูว่าอะไรเท่ากับสิ่งที่ทำผิดพลาดเช่นการแลกเปลี่ยนอาร์กิวเมนต์ล้าสมัย
vava

4
แต่โปรที่ใหญ่ที่สุดคือคุณจะเขียนโค้ดน้อยลงและมันจะสะอาดขึ้น :)
vava

1
การพิมพ์ใหม่ @vava ยังคงเป็นปัญหาเนื่องจากมีการกระโดดมากกว่าการคัดลอกแบบใหม่ ___ (,,,) นอกจากนี้ยังไม่มีความสามารถในการอ่าน เมื่อคุณคุ้นเคยกับการเขียนโค้ดแล้วคุณnew READABLE_PART(ignore everything in here)จะสามารถสแกนและจัดทำเอกสารด้วยตัวเองได้มากเมื่อเทียบกับ{read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTในหัวของคุณ เวอร์ชันแรกสามารถอ่านได้ในขณะที่เพจขึ้นอย่างรวดเร็ว ประการที่สองคุณปรับโครงสร้างเป็นโครงสร้างเพียงเพื่อทำความเข้าใจ
Christopher

19

ปัญหาที่แท้จริงคือโครงสร้างในภาษาควรเป็นชนิดค่าไม่ใช่ประเภทอ้างอิง คำตอบที่เสนอแนะนำให้ใช้วัตถุ (ซึ่งเป็นประเภทอ้างอิง) แทนโครงสร้าง แม้ว่าสิ่งนี้สามารถตอบสนองวัตถุประสงค์ของมันได้ แต่ก็หลีกเลี่ยงจุดที่โปรแกรมเมอร์ต้องการประโยชน์จากการใช้ประเภทค่า (เช่นแบบดั้งเดิม) แทนประเภทอ้างอิง ประเภทค่าหนึ่งไม่ควรทำให้หน่วยความจำรั่วไหล


8

ฉันคิดว่าการสร้างคลาสเพื่อจำลองโครงสร้างแบบ C เหมือนที่คุณเคยทำมาเป็นวิธีที่ ดีที่สุด

เป็นวิธีที่ยอดเยี่ยมในการจัดกลุ่มข้อมูลที่เกี่ยวข้องและลดความซับซ้อนในการส่งผ่านพารามิเตอร์ไปยังฟังก์ชัน ฉันยังยืนยันว่าคลาส JavaScript เป็นเหมือนโครงสร้าง C ++ มากกว่าคลาส C ++ โดยพิจารณาจากความพยายามเพิ่มเติมที่จำเป็นในการจำลองคุณสมบัติเชิงวัตถุจริง

ฉันพบว่าการพยายามทำให้ JavaScript เป็นเหมือนภาษาอื่นนั้นซับซ้อนขึ้นอย่างรวดเร็ว แต่ฉันสนับสนุนอย่างเต็มที่โดยใช้คลาส JavaScript เป็นโครงสร้างที่ไม่มีฟังก์ชัน


ฉันชอบที่จะมีบางอย่างเช่นโครงสร้างสิ่งทอ - สิ่งที่อนุญาตให้มีการรวบรวมข้อมูลที่พิมพ์อย่างรุนแรงซึ่งจัดการได้ในเวลาคอมไพล์และไม่มีค่าใช้จ่ายของแฮชแมปเช่นวัตถุ
derekdreery

4

ตามคำตอบของ Markus ใน JS เวอร์ชันใหม่กว่า (ฉันคิดว่า ES6) คุณสามารถสร้างโรงงาน 'struct' ได้ง่ายขึ้นโดยใช้Arrow FunctionsและRest Parameterดังนี้:

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

ผลลัพธ์ของการรันสิ่งนี้คือ:

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

คุณสามารถทำให้มันดูคล้ายกับชื่อของ Python ได้:

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

และผลลัพธ์:

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

ดูเหมือนว่า struct ใน C / C ++ และภาษาอื่น ๆ แต่จริงๆแล้วไม่ใช่ - คุณสมบัติในอ็อบเจ็กต์ไม่รับประกันว่าจะเรียงลำดับตามที่อธิบายไว้ดังต่อไปนี้: คำจำกัดความของอ็อบเจ็กต์จาก ECMAScript Third Edition (pdf): 4.3.3 Object วัตถุเป็นสมาชิกของประเภทวัตถุ เป็นชุดของคุณสมบัติที่ไม่เรียงลำดับซึ่งแต่ละรายการมีค่าดั้งเดิมวัตถุหรือฟังก์ชัน ฟังก์ชันที่เก็บไว้ในคุณสมบัติของวัตถุเรียกว่าเมธอด
ทิเบต


1

ฉันสร้างห้องสมุดขนาดเล็กเพื่อกำหนดโครงสร้างถ้าคุณทำงานกับความเข้ากันได้ของ ES6

เป็นตัวแยกวิเคราะห์ JKT คุณสามารถชำระเงินที่เก็บโครงการได้ที่นี่JKT Parser

ตัวอย่างเช่นคุณอาจสร้างโครงสร้างของคุณเช่นนี้

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

การตั้งค่าทำได้มากกว่า แต่ถ้าการบำรุงรักษาทำได้เพียงครั้งเดียวอาจเป็นกรณีของคุณ

/**
 * @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;
    }
}

ข้อดี:

  • ไม่ผูกพันกับคำสั่งโต้แย้ง
  • ขยายได้ง่าย
  • พิมพ์การสนับสนุนสคริปต์:

ใส่คำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.