分配时的JavaScript评估顺序

时间:2017-07-21 22:01:46

标签: javascript assignment-operator operator-precedence

JavaScript在什么时候确定作业的左侧 - 是在评估右侧之前还是之后?

例如,这段代码做了什么?

var arr = [{thing:1},{thing:2},{thing:3},{last:true}];
arr[arr.length - 1].newField = arr.pop();

2 个答案:

答案 0 :(得分:2)

首先评估赋值运算符的左侧。

ES2015的规范可以在"Runtime Semantics: Evaluation" portion of the "Assignment Operators" section中找到,可以大致概括为:

  1. 评估LHS以确定参考
  2. 评估RHS以确定值
  3. 将值分配给参考
  4. 关于数组.pop()示例,它看起来可能会将最初的最后一项分配给最后一项中的字段 - 但这只会在首先评估RHS时发生,而不是LHS。

    实际发生的是左侧首先产生对原始最后一个对象{last:true}的引用。在此之后,array.pop()在从数组末尾删除它后返回相同的对象。然后进行赋值,使对象最终看起来像obj = {last:true, newField:obj}。由于原始示例中未保留对obj的引用,

    将分配扩展到代码,并添加一些额外的变量以便我们检查行为,可能看起来像这样:

    function pseudoAssignment() {
      // left-hand side evaluated first
      var lhsObj = arr[arr.length - 1];
      var lhsKey = 'newField';
    
      // then the right-hand side
      var rhsVal = arr.pop();
    
      // then the value from RHS is assigned to what the LHS references
      lhsObj[lhsKey] = rhsVal;
    
      // `(a = b)` has a value just like `(a + b)` would
      return rhsVal;
    }
    
    var arr = [{thing:1},{thing:2},{thing:3},{last:true}];
    _lastObj = arr[arr.length - 1];
    
    // `arr[arr.length - 1].newField = arr.pop();`
    _result = pseudoAssignment();
    
    console.assert(_lastObj.newField === _lastObj,
      "The last object now contains a field recursively referencing itself.")
    console.assert(_result === _lastObj,
      "The assignment's result was the object that got popped.")
    console.assert(arr.indexOf(_lastObj) === -1,
      "The popped object is no longer in the array.")
    

答案 1 :(得分:0)

监视此分配期间发生的事情的一种很好的方法是在阵列上定义代理:

var arr = [{thing:1},{thing:2},{thing:3},{last:true}];

arr = new Proxy(arr, {
    get: function (obj, key) {
        console.log('getting ', key);
        return obj[key];
    },
    set: function (obj, key, value) {
        console.log('setting ', key, ' to ', value);
        return obj[key] = value;
    }
});

arr[arr.length - 1].newField = arr.pop();

现在控制台将显示何时访问数组属性(包括数字索引,lengthpop方法)以及何时设置它们。

前两行说明首先评估左侧:

  

得到长度
  得到3

在执行pop期间生成其他行:

  

流行   得到长度
  得到3
  将长度设置为3