Javascript 对象字面量/初始值设定项中的自引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4616202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:17:39  来源:igfitidea点击:

Self-references in object literals / initializers

javascriptobject-literal

提问by kpozin

Is there any way to get something like the following to work in JavaScript?

有什么办法可以让类似下面的东西在 JavaScript 中工作吗?

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

In the current form, this code obviously throws a reference error since thisdoesn't refer to foo. But isthere any way to have values in an object literal's properties depend on other properties declared earlier?

在当前形式中,此代码显然会引发引用错误,因为this没有引用foo. 但是,有什么办法可以在对象文本的属性值依赖于其他属性声明更早?

回答by CMS

Well, the only thing that I can tell you about are getter:

好吧,我唯一能告诉你的是getter

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

console.log(foo.c) // 11

This is a syntactic extension introduced by the ECMAScript 5th Edition Specification, the syntax is supported by most modern browsers (including IE9).

这是 ECMAScript 第 5 版规范引入的语法扩展,大多数现代浏览器(包括 IE9)都支持该语法。

回答by Felix Kling

You could do something like:

你可以这样做:

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

This would be some kind of one time initialization of the object.

这将是对象的某种一次性初始化。

Note that you are actually assigning the return value of init()to foo, therefore you have to return this.

请注意,您实际上是在分配init()to的返回值foo,因此您必须return this

回答by T.J. Crowder

The obvious, simple answer is missing, so for completeness:

缺少显而易见的简单答案,因此为了完整性:

But isthere any way to have values in an object literal's properties depend on other properties declared earlier?

但是,有什么办法可以在对象文本的属性值依赖于其他属性声明更早?

No. All of the solutions here defer it until after the object is created (in various ways) and then assign the third property. The simplestway is to just do this:

不。这里的所有解决方案都将它推迟到创建对象之后(以各种方式),然后分配第三个属性。在最简单的方法是只是这样做:

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

All others are just more indirect ways to do the same thing. (Felix's is particularly clever, but requires creating and destroying a temporary function, adding complexity; and either leaves an extra property on the object or [if you deletethat property] impacts the performanceof subsequent property accesses on that object.)

所有其他人只是做同样事情的更间接的方式。(Felix 的特别聪明,但需要创建和销毁一个临时函数,增加了复杂性;并且要么在对象上留下一个额外的属性,要么[如果您使用delete该属性] 会影响对该对象的后续属性访问的性能。)

If you need it to all be within one expression, you can do that without the temporary property:

如果您需要将其全部放在一个表达式中,您可以在没有临时属性的情况下做到这一点:

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

Or of course, if you need to do this more than once:

或者当然,如果您需要多次执行此操作:

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

then where you need to use it:

那么你需要在哪里使用它:

var foo = buildFoo(5, 6);

回答by zzzzBov

Simply instantiate an anonymous function:

简单地实例化一个匿名函数:

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

回答by voscausa

Now in ES6 you can create lazy cached properties. On first use the property evaluates once to become a normal static property. Result: The second time the math function overhead is skipped.

现在在 ES6 中你可以创建惰性缓存属性。首次使用时,该属性评估一次以成为正常的静态属性。结果:第二次跳过数学函数开销。

The magic is in the getter.

魔法就在吸气剂中。

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

In the arrow getter thispicks up the surrounding lexical scope.

在箭头 getter 中this拾取周围的词法范围

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  

回答by Henry Wrightson

Some closure should deal with this;

一些关闭应该处理这个问题;

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

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

All the variables declared within fooare private to foo, as you would expect with any function declaration and because they are all in scope, they all have access to each other without needing to refer to this, just as you would expect with a function. The difference is that this function returns an object that exposes the private variables and assigns that object to foo. In the end, you return just the interface you want to expose as an object with the return {}statement.

其中声明的所有变量foo都是私有的foo,正如您对任何函数声明所期望的那样,并且因为它们都在范围内,因此它们都可以相互访问而无需引用this,就像您对函数所期望的那样。不同之处在于此函数返回一个对象,该对象公开私有变量并将该对象分配给foo。最后,您只返回您想作为对象与return {}语句公开的接口。

The function is then executed at the end with the ()which causes the entire foo object to be evaluated, all the variables within instantiated and the return object added as properties of foo().

然后在最后执行该函数,()这会导致评估整个 foo 对象,实例化内的所有变量,并将返回对象添加为 的属性foo()

回答by davedambonite

You could do it like this

你可以这样做

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

That method has proven useful to me when I had to refer to the object that a function was originally declared on. The following is a minimal example of how I used it:

当我不得不引用最初声明函数的对象时,这种方法对我很有用。以下是我如何使用它的最小示例:

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

By defining self as the object that contains the print function you allow the function to refer to that object. This means you will not have to 'bind' the print function to an object if you need to pass it somewhere else.

通过将 self 定义为包含打印函数的对象,您允许该函数引用该对象。这意味着如果您需要将它传递到其他地方,您将不必将打印函数“绑定”到一个对象。

If you would, instead, use thisas illustrated below

如果您愿意,请使用this如下所示的

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

Then the following code will log 0, 1, 2 and then give an error

然后下面的代码会记录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!

By using the self method you guarantee that print will always return the same object regardless of the context in which the function is ran. The code above will run just fine and log 0, 1, 2 and 3 when using the self version of createMyObject().

通过使用 self 方法,您可以保证无论运行函数的上下文如何,print 都将始终返回相同的对象。上面的代码将运行得很好,并在使用createMyObject().

回答by monzonj

For completion, in ES6 we've got classes (supported at the time of writing this only by latest browsers, but available in Babel, TypeScript and other transpilers)

为了完成,在 ES6 中我们有类(在撰写本文时仅受最新浏览器支持,但在 Babel、TypeScript 和其他转译器中可用)

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

const foo = new Foo();

回答by Rafael Rocha

You can do it using the module pattern. Just like:

您可以使用模块模式来做到这一点。就像:

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

With this pattern you can instantiate several foo objects according to your need.

使用此模式,您可以根据需要实例化多个 foo 对象。

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

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

回答by ken

There are several ways to accomplish this; this is what I would use:

有几种方法可以做到这一点;这就是我会使用的:

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