853

次のようなものをJavaScriptで動作させる方法はありますか?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

this現在の形式では、を参照していないため、このコードは明らかに参照エラーをスローしますfoo。しかし、オブジェクトリテラルのプロパティの値を以前に宣言された他のプロパティに依存させる方法はありますか?

4

27 に答える 27

923

さて、私があなたに話すことができる唯一のことはゲッターです:

var foo = {
  a: 5,
  b: 6,
  get c() {
    return this.a + this.b;
  }
}

console.log(foo.c) // 11

これは、ECMAScript 5th Edition仕様によって導入された構文拡張であり、構文はほとんどの最新のブラウザー(IE9を含む)でサポートされています。

于 2011-01-06T14:58:54.997 に答える
338

あなたは次のようなことをすることができます:

var foo = {
   a: 5,
   b: 6,
   init: function() {
       this.c = this.a + this.b;
       return this;
   }
}.init();

これは、オブジェクトのある種の1回限りの初期化になります。

init()実際にはの戻り値をに割り当てていることに注意してください。fooしたがって、を割り当てる必要がありますreturn this

于 2011-01-06T14:59:53.403 に答える
210

明白で単純な答えが欠落しているので、完全を期すために:

しかし、オブジェクトリテラルのプロパティの値を以前に宣言された他のプロパティに依存させる方法はありますか?

いいえ。ここでのすべてのソリューションは、オブジェクトが(さまざまな方法で)作成されるまで延期し、3番目のプロパティを割り当てます。最も簡単な方法は、これを行うことです。

var foo = {
    a: 5,
    b: 6
};
foo.c = foo.a + foo.b;

他のすべては、同じことを行うためのより間接的な方法です。(Felixは特に賢いですが、一時的な関数を作成して破棄する必要があり、複雑さが増します。オブジェクトに余分なプロパティを残すか、[deleteそのプロパティの場合]そのオブジェクトへの後続のプロパティアクセスのパフォーマンスに影響を与えます。)

すべてを1つの式の中に含める必要がある場合は、一時プロパティなしでそれを行うことができます。

var foo = function(o) {
    o.c = o.a + o.b;
    return o;
}({a: 5, b: 6});

またはもちろん、これを複数回行う必要がある場合:

function buildFoo(a, b) {
    var o = {a: a, b: b};
    o.c = o.a + o.b;
    return o;
}

次に、それを使用する必要がある場所:

var foo = buildFoo(5, 6);
于 2012-05-26T12:11:31.890 に答える
66

匿名関数をインスタンス化するだけです。

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};
于 2013-04-11T22:32:13.257 に答える
32

ES6では、遅延キャッシュプロパティを作成できるようになりました。最初に使用すると、プロパティは1回評価され、通常の静的プロパティになります。結果:2回目は、数学関数のオーバーヘッドがスキップされます。

魔法はゲッターにあります。

const foo = {
    a: 5,
    b: 6,
    get c() {
        delete this.c;
        return this.c = this.a + this.b
    }
};

矢印でゲッターは周囲の字句スコープthisをピックアップします。

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
于 2016-11-08T23:43:06.887 に答える
24

いくつかの閉鎖はこれに対処する必要があります。

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

内で宣言されたすべての変数は、関数宣言で期待されるfooように、プライベートでfooあり、すべてスコープ内にあるため、関数で期待されるように、参照する必要なしにすべて相互にアクセスできthisます。違いは、この関数がプライベート変数を公開し、そのオブジェクトをに割り当てるオブジェクトを返すことfooです。return {}最後に、ステートメントを使用してオブジェクトとして公開するインターフェイスのみを返します。

次に、関数が最後に実行されます。()これにより、fooオブジェクト全体が評価され、インスタンス化されたすべての変数と、のプロパティとして追加されたreturnオブジェクトが生成されますfoo()

于 2013-07-02T09:04:12.550 に答える
16

あなたはこのようにそれを行うことができます

var a, b
var foo = {
    a: a = 5,
    b: b = 6,
    c: a + b
}

このメソッドは、関数が最初に宣言されたオブジェクトを参照する必要があるときに役立つことがわかりました。以下は、私がそれをどのように使用したかの最小限の例です。

function createMyObject() {
    var count = 0, self
    return {
        a: self = {
            log: function() {
                console.log(count++)
                return self
            }
        }
    }
}

印刷関数を含むオブジェクトとしてselfを定義することにより、関数がそのオブジェクトを参照できるようにします。これは、別の場所に渡す必要がある場合に、print関数をオブジェクトに「バインド」する必要がないことを意味します。

代わりに、this以下に示すように使用する場合

function createMyObject() {
    var count = 0
    return {
        a: {
            log: function() {
                console.log(count++)
                return this
            }
        }
    }
}

次に、次のコードは0、1、2をログに記録し、エラーを出します

var o = createMyObject()
var log = o.a.log
o.a.log().log() // this refers to the o.a object so the chaining works
log().log() // this refers to the window object so the chaining fails!

selfメソッドを使用することにより、関数が実行されているコンテキストに関係なく、printが常に同じオブジェクトを返すことを保証します。上記のコードは正常に実行され、の自己バージョンを使用すると0、1、2、および3をログに記録しますcreateMyObject()

于 2013-05-24T22:25:16.350 に答える
10

完了するために、ES6にはクラスがあります(これを書いている時点では最新のブラウザーでのみサポートされていますが、Babel、TypeScript、およびその他のトランスパイラーで利用できます)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();
于 2016-03-28T12:41:11.520 に答える
8

考えてみると、オブジェクトのプロパティをタイムラインの外に配置します。

var foo = {
    a: function(){return 5}(),
    b: function(){return 6}(),
    c: function(){return this.a + this.b}
}

console.log(foo.c())

上記にも良い答えがあります。これが、あなたが質問したサンプルコードを変更した方法です。

アップデート:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
于 2015-08-11T00:00:42.553 に答える
6

モジュールパターンを使用してそれを行うことができます。と同じように:

var foo = function() {
  var that = {};

  that.a = 7;
  that.b = 6;

  that.c = function() {
    return that.a + that.b;
  }

  return that;
};
var fooObject = foo();
fooObject.c(); //13

このパターンを使用すると、必要に応じていくつかのfooオブジェクトをインスタンス化できます。

http://jsfiddle.net/jPNxY/1/

于 2013-01-08T00:21:05.007 に答える
5

これを実現するにはいくつかの方法があります。これは私が使用するものです:

function Obj() {
 this.a = 5;
 this.b = this.a + 1;
 // return this; // commented out because this happens automatically
}

var o = new Obj();
o.b; // === 6
于 2011-01-06T18:55:45.493 に答える
4

オブジェクトリテラルで新しい関数を作成し、コンストラクターを呼び出すことは、元の問題からの根本的な逸脱のように思われ、それは不要です。

オブジェクトリテラルの初期化中に兄弟プロパティを参照することはできません。

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 

計算されたプロパティの最も簡単な解決策は次のとおりです(ヒープ、関数、コンストラクターなし)。

var x = { a: 1, b: 2 };

x.c = x.a + x.b; // apply computed property
于 2014-09-13T21:36:40.077 に答える
3

ここに投稿された他の回答の方が優れていますが、次のような選択肢があります。

  • 初期化時に値を設定します(ゲッターや派生などではありません)
  • init()オブジェクトリテラル以外のタイプやコードは必要ありません
  • オブジェクトリテラルであり、ファクトリ関数やその他のオブジェクト作成メカニズムではありません。
  • パフォーマンスに影響を与えるべきではありません(初期化時を除く)

自己実行型の無名関数とウィンドウストレージ

var foo = {
    bar:(function(){
        window.temp = "qwert";
        return window.temp;
    })(),
    baz: window.temp
};

注文は保証されています(barbaz)。

もちろんそれは汚染しますが、永続的windowである必要があるスクリプトを誰かが書いているとは想像できません。window.temp多分tempMyAppあなたがパラノイアなら。

それも醜いですが、時々便利です。例として、厳密な初期化条件でAPIを使用していて、リファクタリングしたくない場合は、スコープが正しくなります。

もちろん、それは乾燥しています。

于 2015-03-24T21:06:12.927 に答える
3

プロパティはgetうまく機能し、一度だけ実行する必要がある「高価な」関数にバインドされたクロージャを使用することもできます(これは、でのみ機能しvarconstまたはでは機能しませんlet

var info = {
  address: (function() {
    return databaseLookup(this.id)
  }).bind(info)(),

  get fullName() {
    console.log('computing fullName...')
    return `${this.first} ${this.last}`
  },

  id: '555-22-9999',
  first: 'First',
  last: 'Last',
}

function databaseLookup() {
  console.log('fetching address from remote server (runs once)...')
  return Promise.resolve(`22 Main St, City, Country`)
}

// test
(async () => {
  console.log(info.fullName)
  console.log(info.fullName)
  console.log(await info.address)
  console.log(await info.address)
  console.log(await info.address)
  console.log(await info.address)
})()

于 2020-11-01T03:25:13.077 に答える
2

これらすべての鍵はSCOPEです。

定義するプロパティの「親」(親オブジェクト)をそれ自体のインスタンス化されたオブジェクトとしてカプセル化する必要があります。その後、キーワードを使用して兄弟プロパティを参照できます。this

最初にそうせずに参照する場合は、オブジェクトとなる外部スコープを参照することを覚えておくことが非常に重要です。thisthiswindow

var x = 9   //this is really window.x
var bar = {
  x: 1,
  y: 2,
  foo: new function(){
    this.a = 5, //assign value
    this.b = 6,
    this.c = this.a + this.b;  // 11
  },
  z: this.x   // 9 (not 1 as you might expect, b/c *this* refers `window` object)
};
于 2014-05-07T10:15:56.010 に答える
2

代わりに次のコードを使用しますが、機能します。また、変数は配列にすることもできます。(@ Fausto R.)

var foo = {
  a: 5,
  b: 6,
  c: function() {
    return this.a + this.b;
  },

  d: [10,20,30],
  e: function(x) {
    this.d.push(x);
    return this.d;
  }
};
foo.c(); // 11
foo.e(40); // foo.d = [10,20,30,40]
于 2016-06-17T01:23:37.093 に答える
2

オブジェクトがオブジェクトを返す関数として記述されていて、ES6オブジェクト属性の「メソッド」を使用している場合は、次のことが可能です。

const module = (state) => ({
  a: 1,
  oneThing() {
    state.b = state.b + this.a
  },
  anotherThing() {
    this.oneThing();
    state.c = state.b + this.a
  },
});

const store = {b: 10};
const root = module(store);

root.oneThing();
console.log(store);

root.anotherThing();
console.log(store);

console.log(root, Object.keys(root), root.prototype);
于 2016-08-13T15:40:36.513 に答える
2

ES6のすっきりとした方法は次のとおりです。

var foo = (o => ({
    ...o,
    c: o.a + o.b
  }))({
    a: 5,
    b: 6
  });
  
console.log(foo);

私はそれを次のようなことをするために使用します:

const constants = Object.freeze(
  (_ => ({
    ..._,
    flag_data: {
      [_.a_flag]: 'foo',
      [_.b_flag]: 'bar',
      [_.c_flag]: 'oof'
    }
  }))({
    a_flag: 5,
    b_flag: 6,
    c_flag: 7,
  })
);

console.log(constants.flag_data[constants.b_flag]);

于 2018-06-12T23:16:56.727 に答える
1

このソリューションはどうですか?これは配列を持つネストされたオブジェクトでも機能します

      Object.prototype.assignOwnProVal
     = function (to,from){ 
            function compose(obj,string){ 
                var parts = string.split('.'); 
                var newObj = obj[parts[0]]; 
                if(parts[1]){ 
                    parts.splice(0,1);
                    var newString = parts.join('.'); 
                    return compose(newObj,newString); 
                } 
                return newObj; 
            } 
            this[to] = compose(this,from);
     } 
     var obj = { name : 'Gaurav', temp : 
                  {id : [10,20], city:
                        {street:'Brunswick'}} } 
     obj.assignOwnProVal('street','temp.city.street'); 
     obj.assignOwnProVal('myid','temp.id.1');
于 2016-11-21T18:47:22.710 に答える
1

この正確なシナリオがカバーされていなかったので、オプションを投入しました。いつ更新したくない場合、または更新したくない場合は、ES6IIFEが適切に機能します。cab

var foo = ((a,b) => ({
    a,
    b,
    c: a + b
}))(a,b);

私のニーズのために、ループで使用されることになる配列に関連するオブジェクトがあるので、いくつかの一般的なセットアップを1回だけ計算したいので、これが私が持っているものです:

let processingState = ((indexOfSelectedTier) => ({
    selectedTier,
    indexOfSelectedTier,
    hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                         .some(t => pendingSelectedFiltersState[t.name]),
}))(tiers.indexOf(selectedTier));

のプロパティを設定する必要があり、プロパティをindexOfSelectedTier設定するときにその値を使用する必要があるため、hasUpperTierSelection最初にその値を計算し、それをパラメーターとしてIIFEに渡します。

于 2018-02-13T19:14:40.440 に答える
1

これは、オブジェクトでの「this」の動作の例です。

this.prop = 'external';
global.prop = 'global.prop';
const that = this;

const a = {
  prop: 'internal',
  prop1: this.prop, //external

  log() {
    return this.prop //internal
  },
  log1: () => {
    return this.prop //external
  },
  log2: () => {
    return function () {
      return this.prop; //'global.prop' in node; 'external' in chrome
    }()
  },
  log3: function () {
    return (() => {
      return this.prop; //internal
    })()
  },
}
于 2021-11-06T21:18:21.553 に答える
0

他のアプローチは、オブジェクトにプロパティを割り当てる前に、最初にオブジェクトを宣言することです。

const foo = {};
foo.a = 5;
foo.b = 6;
foo.c = foo.a + foo.b;  // Does work
foo.getSum = () => foo.a + foo.b + foo.c;  // foo.getSum() === 22

これにより、オブジェクト変数名を使用して、すでに割り当てられている値にアクセスできます。ファイル
に最適です。config.js

于 2019-06-09T15:40:19.067 に答える
0

2つの怠惰な解決策

ここにはすでに優れた答えがあり、私はこれについての専門家ではありませんが、私は怠惰なことの専門家であり、私の専門家の目には、これらの答えは十分に怠惰ではないようです。

最初:無名関数からオブジェクトを返します

TJクラウダーヘンリーライトソンラファエルロシャからのごくわずかなバリエーションが答えます。

var foo = (() => {

  // Paste in your original object
  const foo = {
    a: 5,
    b: 6,
  };
  
  // Use their properties
  foo.c = foo.a + foo.b;

  // Do whatever else you want

  // Finally, return object
  return foo;
})();

console.log(foo);

ここでのわずかな利点は、引数などを気にせずに、元のオブジェクトをそのまま貼り付けることです(IMHOラッパー関数はこの方法で非常に透過的になります)。

2番目:setTimeoutを使用する

foo.cすぐに必要ない場合は、ここでこれが機能する可能性があります。

var foo = {
  a: 5,
  b: 6,
  c: setTimeout(() => foo.c = foo.a + foo.b, 0)
};

// Though, at first, foo.c will be the integer returned by setTimeout
console.log(foo);
// But if this isn't an issue, the value will be updated when time comes in the event loop
setTimeout( () => console.log(foo), 0);

于 2021-01-05T18:31:54.653 に答える
0

みんなの娯楽のためだけに:

var foo = (                        (This={
    a: 5,
    b: 6,                          })=>({...This,
    c: This.a + This.b             }))(
);

console.log(foo);

于 2022-01-25T23:45:15.960 に答える
-1

注:このソリューションはTypescriptを使用します(必要に応じてTSがコンパイルされるバニラJSを使用できます)

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

    // this method is just to check/test this solution 
    check(){
        console.log(this.def.qwe);
    }
}

// these two lines are just to check
let instance = new asd();
instance.check();

ここでは、クラス式を使用して、必要なネストされたオブジェクトリテラルインターフェイスを取得していました。これは、作成中にオブジェクトのプロパティを参照できるようにするためのIMHOの次善の策です。

注意すべき主な点は、このソリューションを使用している間、オブジェクトリテラルから得たものとまったく同じインターフェイスを使用できることです。また、構文はオブジェクトリテラル自体に非常に近いものです(関数を使用する場合など)。

以下を比較してください

私が提案した解決策

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

オブジェクトリテラルで十分だった場合の解決策

var asd = {
    def : {
        ads:'asd',
        qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
    }
}

もう一つの例

このクラスでは、オブジェクトリテラルでは不可能な、複数の相対パスを組み合わせることができます。

class CONSTANT {
    static readonly PATH = new class {
        /** private visibility because these relative paths don't make sense for direct access, they're only useful to path class
         *
         */
        private readonly RELATIVE = new class {
            readonly AFTER_EFFECTS_TEMPLATE_BINARY_VERSION: fs.PathLike = '\\assets\\aep-template\\src\\video-template.aep';
            readonly AFTER_EFFECTS_TEMPLATE_XML_VERSION: fs.PathLike = '\\assets\\aep-template\\intermediates\\video-template.aepx';
            readonly RELATIVE_PATH_TO_AFTER_EFFECTS: fs.PathLike = '\\Adobe\\Adobe After Effects CC 2018\\Support Files\\AfterFX.exe';
            readonly OUTPUT_DIRECTORY_NAME: fs.PathLike = '\\output';
            readonly INPUT_DIRECTORY_NAME: fs.PathLike = '\\input';
            readonly ASSETS_DIRECTORY_NAME: fs.PathLike = '\\assets';
        };
    }
}
于 2018-06-19T13:33:36.723 に答える
-1

ネイティブJSを使用する場合は、他の回答が適切なソリューションを提供します。

ただし、次のような自己参照オブジェクトを作成する場合は、次のようにします。

{ 
  a: ...,
  b: "${this.a + this.a}",
}

その構文をサポートし、ネイティブオブジェクトを返すself-referenced-objectというnpmライブラリを作成しました。

于 2019-04-27T08:56:59.730 に答える
-4
var x = {
    a: (window.secreta = 5),
    b: (window.secretb = 6),
    c: window.secreta + window.secretb
};

これは@slicedtoadの答えとほとんど同じですが、関数を使用しません。

于 2019-10-31T08:04:13.530 に答える