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结构吗?

Answers:


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”)吗?
尼克

5
它与类的解决方案一样可维护,因为JavaScript不在乎调用函数的参数数量。如果使用诸如Emacs之类的正确工具,则重新键入不是问题。您会看到什么等于导致过错(例如交换参数)的错误。
vava

4
但是最大的
优点

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)中,您可以使用箭头函数Rest参数更简单地创建“结构”工厂,如下所示:

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的namedtuple:

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

它看起来像C / C ++和其他语言中的结构,但实际上不是-不能保证对象的属性按如下所述进行排序:ECMAScript第三版(pdf)中对象的定义:4.3.3对象对象是对象类型的成员。它是属性的无序集合,每个属性都包含原始值,对象或函数。存储在对象属性中的函数称为方法
tibetty


1

如果您使用ES6兼容性,我做了一个小库来定义结构。

这是一个JKT解析器可能在这里签项目库JKT分析器

例如,您可以这样创建结构

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

优点:

  • 不受参数顺序约束
  • 容易扩展
  • 键入脚本支持:

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.