128

以前,当我需要存储许多相关变量时,我会创建一个类。

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

但我想知道这是否是一个好习惯。还有其他更好的方法来模拟 JavaScript 中的结构吗?

4

9 回答 9

197

对象字面量和构造对象之间的唯一区别是从原型继承的属性。

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
于 2009-02-02T06:41:56.040 回答
35

我总是使用对象字面量

{id: 1, speaker:"john", country: "au"}
于 2009-02-02T06:28:43.057 回答
23

真正的问题是语言中的结构应该是值类型而不是引用类型。建议的答案建议使用对象(引用类型)代替结构。虽然这可以达到其目的,但它回避了程序员实际上想要使用值类型(如原语)代替引用类型的好处。一方面,值类型不应导致内存泄漏。

编辑:有一项提案正在制定中以涵盖此目的。

//today
var obj = {fname: "Kris", lname: "Kringle"}; //vanilla object
var gifts = ["truck", "doll", "slime"]; //vanilla array

//records and tuples - not possible today
var obj = #{fname: "Buddy", lname: "Hobbs"};
var skills = #["phone calls", "basketball", "gum recycling"];

于 2012-11-07T01:37:21.720 回答
9

我认为创建一个类来模拟类似 C 的结构,就像你一直在做的那样,是最好的方法。

这是对相关数据进行分组并简化将参数传递给函数的好方法。考虑到模拟真正的面向对象功能所需 的额外工作,我还认为 JavaScript 类更像是 C++ 结构而不是 C++ 类。

我发现试图让 JavaScript 更像另一种语言会很快变得复杂,但我完全支持将 JavaScript 类用作无功能的结构。

于 2011-08-13T22:56:52.907 回答
8

按照 Markus 的回答,在较新版本的 JS(我认为是 ES6)中,您可以更简单地使用箭头函数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 的 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
于 2017-10-14T05:48:30.207 回答
3

我将对象 JSON 样式用于哑结构(无成员函数)。

于 2009-02-02T06:29:00.263 回答
2

设置工作量更大,但如果可维护性胜过一次性工作,那么这可能就是您的情况。

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

好处:

  • 不受参数顺序的约束
  • 易于扩展
  • 类型脚本支持:

在此处输入图像描述

于 2020-05-02T01:05:50.580 回答
1

如果您使用 ES6 兼容性,我创建了一个小型库来定义 struct。

它是一个 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 
于 2018-02-13T17:15:27.230 回答
0

这是一个老问题,似乎还没有解决。对于它的价值,我使用不变性来获得类似的行为。使用打字稿:

export class Point {
   public readonly X: number;
   public readonly Y: number;

   constructor(x: number, y: number)
   {
       this.X = x;
       this.Y = y;
   }

   public static SetX(value: number) : Point {
       return new Point(value, this.Y);
   }

   public static SetY(value: number) : Point {
       return new Point(this.X, value);
   }
}

这为您带来了复杂值类型的主要好处,即您不会通过对它的引用意外地修改对象。

当然,缺点是如果您确实想要修改成员,则必须创建一个新实例,因此需要静态SetXSetY函数。

这是很多语法糖,但我认为对于特殊情况是值得的,例如Point,如果值被意外更改,可能会被大量使用并导致大量错误。

于 2021-06-27T13:13:35.257 回答