Javascript 中的结构

Structs in Javascript

提问人:nickf 提问时间:2/2/2009 最后编辑:Mario Petrovicnickf 更新时间:10/9/2022 访问量:276212

问:

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

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 中的结构?

javascript 结构

评论

7赞 Nathan B 12/28/2020
代码中有一个错别字 - “spkr”
1赞 Ciro Santilli OurBigBook.com 4/28/2022
你关心内存效率吗?还是只是打字检查?对于类型检查,打字稿绝对是当今的方式。为了内存效率,我还在寻找!stackoverflow.com/questions/1248302/......

答:

41赞 vava 2/2/2009 #1

我总是使用对象文字

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

评论

4赞 nickf 2/2/2009
这难道不会使维护变得更加困难(如果您将来想添加一个新字段),以及更多的代码(每次都重新输入“ID”、“Speaker”、“Country”)?
6赞 vava 2/2/2009
它与带有类的解决方案完全一样可维护,因为 JavaScript 不关心你调用函数的参数数量。如果你使用像 Emacs 这样的正确工具,重新输入不是问题。你可以看到什么等于什么,这使得交换参数等错误过时了。
5赞 vava 2/2/2009
但最大的优点是,你可以写更少的代码,而且会更干净:)
3赞 Chris 4/4/2018
@vava重新键入仍然是一个问题,因为跳转比复制新的 ___ ( , , , ) 原型要多。此外,没有可读性。一旦你习惯了编码,就会变得非常可扫描和自我记录,而不是在你的脑海中。第一个版本在快速分页时是可读的。第二,你重构结构只是为了理解。new READABLE_PART(ignore everything in here){read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PART
0赞 nickf 8/11/2023
谢谢你的关心,伙计!在过去的 14 年里,我一直做得很好,并且在软件工程领域拥有非常健康的职业生涯。
3赞 Robert Gould 2/2/2009 #2

我使用对象 JSON 样式作为哑结构(没有成员函数)。

评论

0赞 WestCoastProjects 1/29/2021
但是如何重用结构的结构/字段呢?我想多次创建相同结构的实例。
201赞 Markus Jarderot 2/2/2009 #3

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

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

评论

0赞 kap 3/24/2016
我喜欢这种方法,但是如果您使用闭包编译器,请小心。在这种情况下,元组只能作为字符串进行访问,因为属性已重命名。(至少在高级模式下)
3赞 c0degeas 7/5/2019
我很好奇这种方法对对象文字的效率。
0赞 SphynxTech 4/4/2020
也许也可以使用 JS 类。
9赞 peter 8/14/2011 #4

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

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

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

评论

2赞 derekdreery 3/23/2016
我希望有像结构、元组这样的东西——允许强类型数据集合的东西——在编译时处理,并且没有像对象这样的哈希映射的开销
1赞 EnderShadow8 5/9/2021
@derekdreery同意了。现在您可以使用位数组,但这非常麻烦,因此它仅用于性能优化。
27赞 Mario 11/7/2012 #5

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

编辑: 有一项提案正在酝酿中,以涵盖这一目的。

//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"];

8赞 typoerrpr 10/14/2017 #6

按照 Markus 的回答,在较新版本的 JS(我认为是 ES6)中,您可以更简单地使用 Arrow FunctionsRest 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

评论

1赞 tibetty 1/7/2019
它看起来像 C/C++ 和其他语言中的结构,但实际上不是 - 对象中的 属性不保证有序,描述如下: ECMAScript 第三版中对象的定义 (pdf): 4.3.3 对象 对象是 Object 类型的成员。它是属性的无序集合,每个属性都包含一个基元值、对象或函数。存储在对象属性中的函数称为方法
1赞 Aditya Kresna Permana 2/14/2018 #7

我做了一个小库来定义结构,如果你使用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 
3赞 Manuel 5/2/2020 #8

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

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

优势:

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

enter image description here

0赞 Emperor Eto 6/27/2021 #9

这是一个似乎尚未解决的老问题。就其价值而言,我使用不变性来获得类似的行为。使用 Typescript:

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

-1赞 Md. Ariful Islam 10/9/2022 #10

这个过程对我有用。将智能合约从 Hardhat Dev-env 部署到 Ganachi 区块链测试网。

文件:./scripts/deploy,.js

var structJS = { id: 55, title: "GP", iccid: "56", msisdn: "1712844177", imsi: "12345" };
const USIMContract = await ethers.getContractFactory("USIM");
const usimContract = await USIMContract.deploy(89, structJS);
console.log("USIM deployed to: ", usimContract.address);

Solidity 脚本:

struct SolStruct { uint id; string title; string iccid; string msisdn; string imsi; }
contract USIM { 
 uint private _iccid; 
 SolStruct private _communicationProfile; 
 constructor( uint iccid_, SolStruct memory communicationProfile_ ) 
 { 
   _iccid = iccid_; 
   _communicationProfile = communicationProfile_; 
 }
}