Các cấu trúc trong Javascript


112

Trước đây, khi tôi cần lưu trữ một số biến có liên quan, tôi sẽ tạo một lớp.

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

Nhưng tôi đang tự hỏi liệu đây có phải là một thực hành tốt. Có cách nào khác tốt hơn để mô phỏng một cấu trúc trong Javascript không?

Câu trả lời:


184

Sự khác biệt duy nhất giữa các chữ đối tượng và các đối tượng được xây dựng là các thuộc tính được kế thừa từ nguyên mẫu.

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

Bạn có thể tạo ra một nhà máy cấu trúc.

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
... và sau đó tôi hiểu các chức năng của nhà máy. +1 để có câu trả lời rõ ràng, dễ hiểu và ngắn gọn, cùng với ví dụ về nhà máy.
John

Tôi thích cách tiếp cận này, tuy nhiên hãy cẩn thận nếu bạn sử dụng trình biên dịch bao đóng. Tuple chỉ có thể được truy cập dưới dạng chuỗi trong trường hợp này, vì các thuộc tính đã được đổi tên. (Ít nhất là trong chế độ nâng cao)
kap

Tôi tò mò về hiệu quả của phương pháp này đối với các nghĩa đen của đối tượng.
c0degeas

Cũng có thể sử dụng lớp JS.
SphynxTech

31

Tôi luôn sử dụng các ký tự đối tượng

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

2
Điều đó sẽ không làm cho việc duy trì khó hơn nhiều (nếu bạn muốn thêm một trường mới trong tương lai) và cũng có nhiều mã hơn (gõ lại "id", "speaker", "country" mỗi lần)?
nickf

5
Nó chính xác là có thể bảo trì được như giải pháp với các lớp vì JavaScript không quan tâm đến số lượng đối số mà bạn gọi hàm. Nhập lại không phải là một vấn đề nếu bạn sử dụng các công cụ phù hợp như Emacs. Và bạn có thể thấy những gì tương đương với những gì gây ra lỗi như hoán đổi đối số đã lỗi thời.
vava

4
Nhưng điểm chuyên nghiệp lớn nhất là bạn sẽ viết ít mã hơn và nó sẽ sạch hơn :)
vava 02/02

1
Nhập lại @vava vẫn là một vấn đề, vì có nhiều bước nhảy hơn là sao chép nguyên mẫu ___ (,,) mới. Ngoài ra, không có khả năng đọc. Một khi bạn đã quen với việc viết mã, bạn new READABLE_PART(ignore everything in here)sẽ trở nên rất dễ quét và tự ghi lại tài liệu, trái ngược với {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PARTtrong đầu bạn. Phiên bản đầu tiên có thể đọc được trong khi phân trang nhanh chóng. Thứ hai, bạn cấu trúc lại thành cấu trúc chỉ để hiểu.
Christopher

19

Vấn đề thực sự là các cấu trúc trong một ngôn ngữ được cho là kiểu giá trị chứ không phải kiểu tham chiếu. Các câu trả lời được đề xuất đề xuất sử dụng các đối tượng (là kiểu tham chiếu) thay cho cấu trúc. Mặc dù điều này có thể phục vụ mục đích của nó, nhưng nó tránh xa điểm mà một lập trình viên thực sự muốn có lợi ích của việc sử dụng các kiểu giá trị (như kiểu nguyên thủy) thay cho kiểu tham chiếu. Đối với một loại giá trị, không được gây rò rỉ bộ nhớ.


8

Tôi nghĩ rằng việc tạo một lớp để mô phỏng các cấu trúc giống C, giống như cách bạn đang làm, là cách tốt nhất .

Đó là một cách tuyệt vời để nhóm dữ liệu liên quan và đơn giản hóa việc chuyển các tham số cho các hàm. Tôi cũng tranh luận rằng một lớp JavaScript giống như một cấu trúc C ++ hơn là một lớp C ++, xem xét nỗ lực bổ sung cần thiết để mô phỏng các tính năng hướng đối tượng thực.

Tôi nhận thấy rằng việc cố gắng làm cho JavaScript giống một ngôn ngữ khác trở nên phức tạp nhanh chóng, nhưng tôi hoàn toàn ủng hộ việc sử dụng các lớp JavaScript dưới dạng cấu trúc vô chức năng.


Tôi rất muốn có một cái gì đó giống như cấu trúc, các bộ - một cái gì đó cho phép gõ mạnh bộ sưu tập dữ liệu - được xử lý tại compiletime và không có những phí của hashmaps như đối tượng
derekdreery

4

Theo câu trả lời của Markus , trong các phiên bản JS mới hơn (tôi nghĩ là ES6), bạn có thể tạo một nhà máy 'cấu trúc' đơn giản hơn bằng cách sử dụng Hàm mũi tênTham số phần còn lại như sau:

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

Kết quả của việc chạy này là:

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

Bạn có thể làm cho nó trông giống với tên của 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);

Và kết quả:

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

Có vẻ như cấu trúc trong C / C ++ và các ngôn ngữ khác, nhưng thực tế không phải vậy - các thuộc tính trong các đối tượng không được đảm bảo sắp xếp theo thứ tự được mô tả như sau: Định nghĩa đối tượng từ ECMAScript Phiên bản thứ ba (pdf): 4.3.3 Đối tượng Một đối tượng là một thành viên của kiểu Đối tượng. Nó là một tập hợp các thuộc tính không có thứ tự, mỗi thuộc tính chứa một giá trị, đối tượng hoặc hàm nguyên thủy. Một chức năng lưu trữ trong một tài sản của một đối tượng được gọi là phương pháp
tibetty

3

Tôi sử dụng kiểu JSON đối tượng cho các cấu trúc câm (không có hàm thành viên).


1

Tôi đã tạo một thư viện nhỏ để định nghĩa struct nếu bạn làm việc với khả năng tương thích với ES6.

Đó là trình phân tích cú pháp JKT, bạn có thể kiểm tra kho lưu trữ dự án tại đây Trình phân tích cú pháp JKT

Ví dụ, bạn có thể tạo cấu trúc của mình như thế này

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

Việc thiết lập sẽ tốn nhiều công sức hơn, nhưng nếu khả năng bảo trì đánh bại nỗ lực một lần thì đây có thể là trường hợp của bạn.

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

Ưu điểm:

  • không bị ràng buộc với thứ tự đối số
  • dễ dàng mở rộng
  • gõ hỗ trợ script:

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.