一道面试题引发的血案

specialCoder
  • 2.1k

Question: What is the value of foo.x?

var foo = {n: 1};
var bar = foo;
foo.x = foo = {n: 2};

foo.x//undefined

这过程之怎样的?

回复
阅读 2.2k
5 个回答
kikong
  • 19.1k
var foo = {n: 1};//A
var bar = foo;//B
foo.x = foo = {n: 2};//C

foo.x//undefined

A.执行后,生成对象 OBJ_A',变量foo指向它
B.执行后,bar和foo指向了同一个对象 OBJ_A‘
C.赋值语句,请从左向右执行赋值操作符涉及的每一个表达式求值

foo.x foo 指向 OBJ_A‘, foo.x为undefined bar指向 OBJ_A‘
foo 指向 OBJ_A‘
{n: 2} 生成对象OBJ_B'
从右向左执行赋值,每一个左边表达式不会重复求值

1 foo = {n: 2} foo变量现在指向OBJ_B',返回为OBJ_B'
2 foo.x = OBJ_B',对foo指向的对象的属性x赋值,如果当前没有这个属性那就新建然后赋值,否则直接赋值。
注意此时的foo指向的还是 OBJ_A‘,这个是在表达式求值极端就确定的,也就是对OBJ_A‘的属性x赋值,
3.最终

foo=>{n: 2}
bar=>{
    n:1,
    x:foo
}

其实上面的代码和下面的相同

var foo = {n: 1};//A
var bar = foo;//B
bar.x = foo = {n: 2};//C
foo.x//undefined

关于
左向右执行赋值操作符涉及的每一个表达式求值

从右向左执行赋值 请看下面的代码


var p={};
(function(){
    Object.defineProperty(p, 'z',{
        set:function(newValue){
            console.log("set Z");
            this.value=newValue;
        },
        get:function(){
            return this.value
        }
    });
    console.log("1")
    return p;
}()).z=(function(){
    var q={};
    Object.defineProperty(q, 'y',{
        set:function(newValue){
            console.log("set Y");
            this.value=newValue;
        },
        get:function(){
            return this.value
        }
    });
    console.log("2")
    return q;
}()).y="3";

输出
1
2
set Y
set Z

找到了一篇更全面的问答:https://www.cnblogs.com/moron...
内容如下:
以下代码输出什么? 为什么?
var a = {n:1};
var b = a;
a = {n:2};
a.x = a ;
console.log(a.x);
console.log(b.x);

var a = {n: 1}
var b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b.x)

  第一个问题:

a.x ---> {n:2,x:a};
b.x ---> undefined;

解答:a的值很清晰了,a第二次赋值以后变成了{n:2},随后添加了x属性指向自身。而对于b,在a第二次赋值以后,由于js中给变量赋值为object类型时,变量中存储的是对这个object的引用。
此时,a指向{n:2} ,而b指向了{n:1} ,a和b指向不同的对象,因此,在a上添加属性对于b无影响,b.x自然就是undefined。

第二个问题:
  解答:第三句里的主要难点在js运算符的优先级,访问属性、调用方法运算符"."的优先级高于赋值运算符。因此执行顺序是

给a添加属性x,此时a,b都是 { n:1,x:undefined },a.x 运算后的结果即为这个object(可以说也就是b)的x属性值。
把{n:2}赋值给a,此时a是 {n:2},是一个新的对象。 b是{ n:1,x:undefined }。
由于( . 运算符最先计算)一开始js已经先计算了a.x,便已经解析了这个a.x是对象A的x,所以在同一条公式的情况下再回来给a.x赋值,也不会说重新解析这个a.x为对象B的x。

所以 a.x=a 应理解为对象A的属性x指向了对象B:

(这个时候a.x 已经运算完了,不会再与a产生任何关系,a.x依旧代表那个n为1对象的x属性值,和a已经没关系了。)
把{n:2}赋值给a.x 也就是 { n:1,x:undefined }这个对象的x属性,这个时候b依旧指向这个object,因此此时,a是{n:2},b是{n:1,x:{n:2}}

你搜js连续赋值,一堆一堆的。

@specialCoder 回答的很详细。这个问题牵涉到预算符的优先级和字面量对象赋值注意事项。平时多总结,多思考这样的面试问题就不是问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏