次のようなものをJavaScriptで動作させる方法はありますか?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
this
現在の形式では、を参照していないため、このコードは明らかに参照エラーをスローしますfoo
。しかし、オブジェクトリテラルのプロパティの値を以前に宣言された他のプロパティに依存させる方法はありますか?
次のようなものをJavaScriptで動作させる方法はありますか?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
this
現在の形式では、を参照していないため、このコードは明らかに参照エラーをスローしますfoo
。しかし、オブジェクトリテラルのプロパティの値を以前に宣言された他のプロパティに依存させる方法はありますか?
さて、私があなたに話すことができる唯一のことはゲッターです:
var foo = {
a: 5,
b: 6,
get c() {
return this.a + this.b;
}
}
console.log(foo.c) // 11
これは、ECMAScript 5th Edition仕様によって導入された構文拡張であり、構文はほとんどの最新のブラウザー(IE9を含む)でサポートされています。
あなたは次のようなことをすることができます:
var foo = {
a: 5,
b: 6,
init: function() {
this.c = this.a + this.b;
return this;
}
}.init();
これは、オブジェクトのある種の1回限りの初期化になります。
init()
実際にはの戻り値をに割り当てていることに注意してください。foo
したがって、を割り当てる必要がありますreturn this
。
明白で単純な答えが欠落しているので、完全を期すために:
しかし、オブジェクトリテラルのプロパティの値を以前に宣言された他のプロパティに依存させる方法はありますか?
いいえ。ここでのすべてのソリューションは、オブジェクトが(さまざまな方法で)作成されるまで延期し、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);
匿名関数をインスタンス化するだけです。
var foo = new function () {
this.a = 5;
this.b = 6;
this.c = this.a + this.b;
};
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}
いくつかの閉鎖はこれに対処する必要があります。
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()
。
あなたはこのようにそれを行うことができます
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()
。
完了するために、ES6にはクラスがあります(これを書いている時点では最新のブラウザーでのみサポートされていますが、Babel、TypeScript、およびその他のトランスパイラーで利用できます)
class Foo {
constructor(){
this.a = 5;
this.b = 6;
this.c = this.a + this.b;
}
}
const foo = new Foo();
考えてみると、オブジェクトのプロパティをタイムラインの外に配置します。
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);
モジュールパターンを使用してそれを行うことができます。と同じように:
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オブジェクトをインスタンス化できます。
これを実現するにはいくつかの方法があります。これは私が使用するものです:
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
オブジェクトリテラルで新しい関数を作成し、コンストラクターを呼び出すことは、元の問題からの根本的な逸脱のように思われ、それは不要です。
オブジェクトリテラルの初期化中に兄弟プロパティを参照することはできません。
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
ここに投稿された他の回答の方が優れていますが、次のような選択肢があります。
init()
オブジェクトリテラル以外のタイプやコードは必要ありません自己実行型の無名関数とウィンドウストレージ
var foo = {
bar:(function(){
window.temp = "qwert";
return window.temp;
})(),
baz: window.temp
};
注文は保証されています(bar
前baz
)。
もちろんそれは汚染しますが、永続的window
である必要があるスクリプトを誰かが書いているとは想像できません。window.temp
多分tempMyApp
あなたがパラノイアなら。
それも醜いですが、時々便利です。例として、厳密な初期化条件でAPIを使用していて、リファクタリングしたくない場合は、スコープが正しくなります。
もちろん、それは乾燥しています。
プロパティはget
うまく機能し、一度だけ実行する必要がある「高価な」関数にバインドされたクロージャを使用することもできます(これは、でのみ機能しvar
、const
またはでは機能しません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)
})()
これらすべての鍵はSCOPEです。
定義するプロパティの「親」(親オブジェクト)をそれ自体のインスタンス化されたオブジェクトとしてカプセル化する必要があります。その後、キーワードを使用して兄弟プロパティを参照できます。this
最初にそうせずに参照する場合は、オブジェクトとなる外部スコープを参照することを覚えておくことが非常に重要です。this
this
window
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)
};
代わりに次のコードを使用しますが、機能します。また、変数は配列にすることもできます。(@ 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]
オブジェクトがオブジェクトを返す関数として記述されていて、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);
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]);
このソリューションはどうですか?これは配列を持つネストされたオブジェクトでも機能します
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');
この正確なシナリオがカバーされていなかったので、オプションを投入しました。いつ更新したくない場合、または更新したくない場合は、ES6IIFEが適切に機能します。c
a
b
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に渡します。
これは、オブジェクトでの「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
})()
},
}
他のアプローチは、オブジェクトにプロパティを割り当てる前に、最初にオブジェクトを宣言することです。
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
ここにはすでに優れた答えがあり、私はこれについての専門家ではありませんが、私は怠惰なことの専門家であり、私の専門家の目には、これらの答えは十分に怠惰ではないようです。
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ラッパー関数はこの方法で非常に透過的になります)。
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);
みんなの娯楽のためだけに:
var foo = ( (This={
a: 5,
b: 6, })=>({...This,
c: This.a + This.b }))(
);
console.log(foo);
注:このソリューションは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';
};
}
}
ネイティブJSを使用する場合は、他の回答が適切なソリューションを提供します。
ただし、次のような自己参照オブジェクトを作成する場合は、次のようにします。
{
a: ...,
b: "${this.a + this.a}",
}
その構文をサポートし、ネイティブオブジェクトを返すself-referenced-objectというnpmライブラリを作成しました。
var x = {
a: (window.secreta = 5),
b: (window.secretb = 6),
c: window.secreta + window.secretb
};
これは@slicedtoadの答えとほとんど同じですが、関数を使用しません。