Структуры в 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?

nickf
источник

Ответы:

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 за четкий, понятный и лаконичный ответ вместе с заводским примером.
Джон
Мне нравится этот подход, однако будьте осторожны, если используете компилятор замыкания. В этом случае к кортежу можно получить доступ только как к строке, потому что свойства переименованы. (По крайней мере, в расширенном режиме)
кап
Мне было любопытно, насколько эффективен этот метод над литералами объекта.
c0degeas 05
Возможно, также можно использовать класс JS.
SphynxTech,
31

Я всегда использую объектные литералы

{id: 1, speaker:"john", country: "au"}
Вава
источник
2
Разве это не усложнит поддержку (если вы захотите добавить новое поле в будущем), а также гораздо больше кода (каждый раз вводя «id», «Speaker», «country»)?
nickf 02
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. Первая версия доступна для чтения при быстром листании. Во-вторых, вы реорганизуете структуры просто для понимания.
Кристофер
19

Настоящая проблема заключается в том, что структуры в языке должны быть типами значений, а не ссылочными типами. Предлагаемые ответы предполагают использование объектов (которые являются ссылочными типами) вместо структур. Хотя это может служить своей цели, оно позволяет избежать того факта, что программисту действительно нужны преимущества использования типов значений (например, примитивов) вместо ссылочного типа. Типы значений, например, не должны вызывать утечки памяти.

Марио
источник
8

Я думаю, что создание класса для имитации C-подобных структур, как вы это делали, - лучший способ.

Это отличный способ группировать связанные данные и упрощает передачу параметров функциям. Я также утверждаю, что класс JavaScript больше похож на структуру C ++, чем на класс C ++, учитывая дополнительные усилия, необходимые для моделирования реальных объектно-ориентированных функций.

Я обнаружил, что попытки сделать JavaScript более похожим на другой язык быстро усложняются, но я полностью поддерживаю использование классов JavaScript как структур без функций.

Питер
источник
Я бы хотел иметь что-то вроде структур, кортежей - что-то, что позволяет строго типизированные коллекции данных - это обрабатывается во время компиляции и не имеет накладных расходов на хэш-карты, такие как объекты,
derekdreery
4

Следуя ответу Маркуса , в более новых версиях JS (я думаю, ES6) вы можете создать фабрику struct проще, используя функции стрелок и параметр отдыха, например:

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

Вы можете сделать его похожим на namedtuple в 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
typoerrpr
источник
Похоже на структуру на C / C ++ и других языках, но на самом деле это не так - не гарантируется, что свойства объектов будут упорядочены, как описано ниже: Определение объекта из ECMAScript Third Edition (pdf): 4.3.3 Object Объект является членом типа Object. Это неупорядоченный набор свойств, каждое из которых содержит примитивное значение, объект или функцию. Функция, хранящаяся в свойстве объекта, называется методом
tibetty
3

Я использую объекты в стиле JSON для тупых структур (без функций-членов).

Роберт Гулд
источник
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;
    }
}

Преимущества:

  • не привязан к порядку аргументов
  • легко расширяемый
  • тип поддержки скрипта:

введите описание изображения здесь

Manuel
источник