Javascript 对象文本/初始值设定项中的自引用

Javascript 对象文本/初始值设定项中的自引用,javascript,object-literal,Javascript,Object Literal,有没有办法让下面这样的东西在JavaScript中工作 var foo = { a: 5, b: 6, c: this.a + this.b // Doesn't work }; 在当前表单中,此代码显然抛出了一个引用错误,因为this没有引用foo。但是,有没有办法让对象文本的属性中的值依赖于前面声明的其他属性?那么,我唯一能告诉您的是: var foo={ a:5, b:6, 获取c(){ 返回这个.a+这个.b; } } console.log(foo.c)/

有没有办法让下面这样的东西在JavaScript中工作

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

在当前表单中,此代码显然抛出了一个引用错误,因为
this
没有引用
foo
。但是,有没有办法让对象文本的属性中的值依赖于前面声明的其他属性?

那么,我唯一能告诉您的是:

var foo={
a:5,
b:6,
获取c(){
返回这个.a+这个.b;
}
}

console.log(foo.c)//11
您可以执行以下操作:

var foo = {
   a: 5,
   b: 6,
   init: function() {
       this.c = this.a + this.b;
       return this;
   }
}.init();
这将是对象的某种一次性初始化


请注意,您实际上是在将
init()
的返回值赋值给
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 foo = {
    a: 5,
    b: 6
};
foo.c = foo.a + foo.b;
所有其他方法都只是做同样事情的更间接的方法。(Felix的特别聪明,但需要创建和销毁一个临时函数,增加了复杂性;或者在对象上留下一个额外的属性,或者[如果你
删除该属性]该对象上的后续属性访问。)

如果需要将其全部放在一个表达式中,则可以不使用临时属性:

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 = 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对象


只需实例化一个匿名函数:

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

你可以这样做

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定义为包含打印函数的对象,可以允许函数引用该对象。这意味着,如果需要将打印函数传递到其他地方,则不必将其“绑定”到对象

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

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将始终返回相同的对象,而不管函数在哪个上下文中运行。使用
createMyObject()
的自版本时,上述代码将正常运行并记录0、1、2和3

一些闭包应该解决这个问题

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

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


然后,在函数末尾执行
()
,这将导致对整个foo对象进行求值,实例化其中的所有变量,并将返回对象添加为
foo()
的属性。所有这些的关键是作用域

您需要将要定义为自己的实例化对象的属性的“父”(父对象)封装为自己的实例化对象,然后可以使用关键字
this

非常非常重要的是要记住,如果您未事先这样做就引用了
,那么
将引用外部范围。。。这将是
窗口
对象

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)
};

在对象文本上创建新函数并调用构造函数似乎与原来的问题完全不同,这是不必要的

在对象文字初始化期间不能引用同级属性

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 
计算属性的最简单解决方案如下(无堆、无函数、无构造函数):


这里发布的其他答案更好,但这里有一个替代方案:

  • 在初始化时设置值(不是getter或派生的等)
  • 不需要任何类型的
    init()
    或对象文本之外的代码
  • 是对象文字,而不是工厂函数或其他对象创建机制
  • 不应有任何性能影响(初始化时除外)
自动执行匿名函数和窗口存储

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

当然,它会污染
window
,但我无法想象有人编写的脚本需要
window.temp
持久化。如果你是偏执狂,可能是
tempMyApp

它也很难看,但偶尔也有用。例如,当您使用具有严格初始化条件的API时,不想进行重构,因此作用域是正确的


当然,它是干的。

只是为了思考——将对象的属性放在时间线之外:

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);

作为补充,在ES6中,我们有一些类(在撰写本文时,只有最新的浏览器支持,但在Babel、TypeScript和其他Transpiler中可用)


我使用下面的代码作为替代,它可以工作。变量也可以是数组。(@Fausto R.)

如果你的目标
var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();
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]
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);
const foo = {
    a: 5,
    b: 6,
    get c() {
        delete this.c;
        return this.c = this.a + this.b
    }
};
foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
      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');
var foo = ((a,b) => ({
    a,
    b,
    c: a + b
}))(a,b);
let processingState = ((indexOfSelectedTier) => ({
    selectedTier,
    indexOfSelectedTier,
    hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                         .some(t => pendingSelectedFiltersState[t.name]),
}))(tiers.indexOf(selectedTier));
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();
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';
        };
    }
}
{ 
  a: ...,
  b: "${this.a + this.a}",
}
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
var x = {
    a: (window.secreta = 5),
    b: (window.secretb = 6),
    c: window.secreta + window.secretb
};