为什么每次读取属性时都不会重新评估对象初始值设定项中的表达式?

时间:2014-07-19 02:49:11

标签: javascript function javascript-objects

2014年7月15日对MDN guide on working with objects的修订声明:

  

如果在顶级脚本中使用对象初始值设定项创建对象,则JavaScript每次评估包含对象文字的表达式时都会解释该对象。

但是,在下面的代码段中,评估objLit2.val2时,它不会使用最后一个值10100;它改为使用1000,它是定义objLit2时声明的值。为什么会这样?



var i = 1000;

function iPlus3() {
  alert("iPlus3");
  
  return i + 3;
}

var objLit2 = {
  val: iPlus3,
  val2: i = i + 1
};

function setValue() {
  i = 10;
  console.log("objLit2Val1", objLit2.val(), objLit2.val2); // Outputs 13 1001 and not 13 11
  
  i = 100;
  console.log("objLit2Val2", objLit2.val(), objLit2.val2); // Outputs 103 1001 and not 103 101
  
  // If `val` is interpreted at the time of the call, why is `val2` not also interpreted on each call?
}

setValue();




4 个答案:

答案 0 :(得分:2)

objLit2是一个顶级声明。因此,它会在您的脚本首次执行时进行评估。评估后,属性objLit2.val2将设置其值。除非您有意识地更改属性objLit2.val2的值,否则它不会因为您在代码中的其他位置引用objLit2而获得不同的值。

评估objLit2后,属性objLit2.val2包含一个原始数字,该数字不再与变量i有任何关联。 objLit2.val2的值独立存在,其值不会受到任何其他变量的影响。

javascript中的原语(如数字和布尔值)存储为不与任何其他变量连接的不同值。 javascript中的对象存储为对原始对象的引用。由于objLit2.val2是一个数字,它只是一个独立的值,它独立存在。

所以,你可以这样做:

var i = 1000;
var objLit2 = { val : iPlus3, val2 : i = i + 1 };
console.log(objLit2.val2);    // shows 1001
i += 1000;
console.log(objLit2.val2);    // still shows 1001

另一方面,对象存储为对原始对象的引用。所以,如果你这样做了:

var indexes = [1,2,3];
var objLit2 = { val : indexes, val2 : i = i + 1 };
console.log(objLit2.indexes);    // shows [1,2,3]
indexes[0] = 0;
console.log(objLit2.indexes);    // shows [0,2,3]

因为数组是一个对象所以当你在objLit2文字中指定数组时,它只是存储对该数组的引用(而不是数组的单独副本)。如果更改原始数组,您将在包含对该数组的引用的所有其他变量中看到该更改。


您所引用的内容将适用于在某个范围内声明的对象(如函数内部),因为每次创建范围时都会重新评估它们(例如,每次运行该函数时)。

答案 1 :(得分:1)

在初始值设定项中,i递增一次,然后将其值存储在objLit2.val2中。由于i是基本类型 - 数字 - objLit2.val2是与i不同的变量。

这与一个对象设置为另一个对象的情况形成对比。

var objLit3 = objLit2;
objLit2.val2 = 5;
console.log(objLit2.val2); // Also 5

在此处的示例中,objLit3将新的引用保存到同一个基础对象,而不是创建新的实例。数字不会发生这种情况。分配了数字的每个新变量都是内存中的新实例。

答案 2 :(得分:0)

当JavaScript创建对象文字时,该键具有一些值。这个值可能是一个函数,数字等等......在你的情况下,你需要立即提供一些值来评估价值...例如,这有点等同于发生的事情:< / p>

var i = 1000;

function demo() {
    return i = i + 1;
}

var objLit2 = {
    val2: demo()
};

答案 3 :(得分:0)

让我们逐步完成代码的摘要版本。右边显示的是每个语句中变量中存储的内容。

var i = 1000;                                   // i = 1000
var objLit2 = { val: iPlus3, val2: i = i + 1 }; // i = 1001, objLit2.val2 = 1001

i = 10;                                         // i = 10, objLit2.val2 = 1001
innerHTML = (i + 3).toString() + ' ' + '1001';  // Outputs: 13 1001
i = 100;                                        // i = 100, objLit2.val2 = 1001
innerHTML = (i + 3).toString() + ' ' + '1001';  // Outputs: 103 1001

您似乎认为语句val2 : i = i + 1表示对i的引用已分配给val2。但javascript中的number类型不是 immutable 。这意味着当一个对象(如iobjLit2)被赋予一个数字时,它将始终存储该数字的值而不是参考。

例如:

var i, val2;
i = 1000;  // i = 1000
i = i + 1; // i = 1001
val2 = i;  // i = 1001, val2 = 1001
val2++;    // i = 1001, val2 = 1002

请注意以下对象类型(以这种方式工作,因为它分配的是object类型,而不是number类型):

var objectType  = { numType: 14 }, // objectType  = { numType: 14 }
    otherObject = objectType;      // otherObject = &objectType; (reference to)

// So the following statement...
otherObject.numType = 15;          // objectType  = { numType: 15 };
// ...is equivalent to:            // otherObject = &objectType; (reference to)
objectType.numType = 15;
// since:
otherObject == objectType;