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で構造体をシミュレートする他のより良い方法はありますか?

回答:


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は、ファクトリーの例とともに、明確で理解しやすい簡潔な回答を示します。
John

私はこのアプローチが好きですが、クロージャーコンパイラーを使用する場合は注意してください。この場合、プロパティの名前が変更されるため、タプルには文字列としてのみアクセスできます。(アドバンストモードで少なくとも)
KAP

オブジェクトリテラルに対するこのメソッドの効率に興味がありました。
c0degeas

JSクラスを使用することも可能です。
SphynxTech

31

常にオブジェクトリテラルを使用します

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

2
それは維持するのをはるかに難しくしません(将来的に新しいフィールドを追加する必要があります)、さらにはるかに多くのコード(毎回「id」、「speaker」、「country」を再入力します)?
nickf 2009

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クラスを関数なしの構造体として使用することを完全にサポートしています。


構造体、タプルのようなもの-強く型付けされたデータのコレクションを可能にするもの
コンパイル

4

Markusの答えに従って、新しいバージョンのJS(ES6だと思います)では、次のようにArrow FunctionsRest Parameterを使用して、より単純に「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

あなたはそれを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 ++および他の言語の構造体のように見えますが、実際にはそうではありません-オブジェクトのプロパティは、次のように記述されて順序付けされることが保証されていません。オブジェクトはタイプObjectのメンバーです。これは、それぞれがプリミティブ値、オブジェクト、または関数を含む、順序付けされていないプロパティのコレクションです。オブジェクトのプロパティに格納されている関数はメソッドと呼ばれます
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

設定するのはもっと大変ですが、保守性が1回限りの努力に勝る場合、これはあなたのケースかもしれません。

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

利点:

  • 引数の順序にバインドされていません
  • 簡単に拡張可能
  • タイプスクリプトのサポート:

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.