一道阿里笔试题引发的思考

//情况1
let a={n:1} let b=a; a.x=a={n:2}; console.log('a',a); //{n:2} console.log('b',b); //{n:1,x:{n:2}} //情况2 let a={n:1} let b=a; a=a.x={n:2}; console.log('a',a); console.log('b',b);

这是一道阿里的笔试题,自己最开始碰到的时候也是一脸懵逼,然后看了各种人的解释,貌似是懂了,但是别人一问,我又傻逼了,总感觉没有屡清楚

最近呢看到B站上一个老师讲解这道题目的时候,通过画图分析堆栈呢,答案是给出来了,但是自己分析了一下,感觉不太对

//大佬的解释是,对于连等操作,是从左往右的,并且赋值操作呢,是分三步来的,1,定义变量,2,创建值,3,将二者关联起来,所以大佬的逻辑是,

1,a.x={n:2},此时b=a,所以b={n:1,x:{n:2}} a={n:2} 从结果看,是对的,但是如果把题目换成情况二呢

此时,如果从左往右算的话,a={n:2,x:a}  b={n:1}

但是事实上,上面两种情况的结果是一样的

后面又看了别人得到解释,是这样的,这里涉及到运算符的优先级问题具体优先级可以参考MDN上的一张表(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence

点运算符权重是19,而赋值权重是3,也就是说点操作符优先级高

1,a.x 结果就是a=b={n:1,x:undefined}

2,连等,从又向左,这样,两种情况的结果就是一样的了。

a.x其实已经指向了堆里面的一个地方了,所以,当a.x={n:2}时,通过作图,是很容易得出结论的

 

其实对于这个题目的解释,感觉两种结论都可以解释的通,但是关于js的连等的执行顺序到底是从右向左还是从左向右,一直有疑惑,并且在想有没有办法可以证明,网上一搜,还真有相关的证明套路,哈哈,实在是让人惊喜,赶紧贴上链接:

https://blog.csdn.net/four_lemmo/article/details/80794827?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-4-80794827.nonecase

说实话,很怕链接失效,还是把文章复制下来吧。从下面的证明来看,从右向左是 比较靠谱的说法了。

 

一、证明等号的执行顺序
猜测:由于js堆内存和栈内存的存在。a = 1 和 a = {n:1} 这个段代码。如果是从左往右执行,那么如果是赋值对象的话,需要对a进行多次操作。耗费性能。

我们知道js对象的数据属性和访问器属性。我们可以利用这个代码来解析 = 的操作

示例demo:

var c = {
            _name:'c',
        }
        Object.defineProperty(c,'name',{
            get:function () {
                console.log('get c.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set c.name value ')
                this._name = value;
            }
        })
 
        var b = {
            _name:'b',
        }
        Object.defineProperty(b,'name',{
            get:function () {
                console.log('get b.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set b.name value ')
                this._name = value;
            }
        })
        c.name = b.name
执行结果:



说明:等号的执行先执行右边,再执行左边的

二、验证连等操作
var a = {n:1};
var b = a;
a.x = a = {n:2};
 
console.log(a);
console.log(b);
实际结果:



那么连等操作。究竟是怎么样的执行顺序?

a = b = c的执行顺序到底是什么?

b = c; a = b
b = c; a = c;
我们继续来用对象的访问属性来测试

var a = {
            _name:'a',
        }
        Object.defineProperty(a,'name',{
            get:function () {
                console.log('get a.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set a.name value ')
                this._name = value;
            }
        })
 
        var c = {
            _name:'c',
        }
        Object.defineProperty(c,'name',{
            get:function () {
                console.log('get c.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set c.name value ')
                this._name = value;
            }
        })
 
        var b = {
            _name:'b',
        }
        Object.defineProperty(b,'name',{
            get:function () {
                console.log('get b.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set b.name value ')
                this._name = value;
            }
        })
        a.name = b.name = c.name
执行结果:



赋值和读值的操作都执行了一次。

那么猜测:在执行前,会将等式的最后一项保存在内存或者变量中来继续后续的连等操作

继续猜测?a = b = {n:1} 是否指向同一个对象?

 var a = {
            _name:'a',
        }
        Object.defineProperty(a,'name',{
            get:function () {
                console.log('get a.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set a.name value ')
                this._name = value;
            }
        })
 
        var b = {
            _name:'b',
        }
        Object.defineProperty(b,'name',{
            get:function () {
                console.log('get b.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set b.name value ')
                this._name = value;
            }
        })
 
        a.name = b.name = {n:1},
        a.name.n = 2;
        console.log(b.name);
结果:



连等操作会保存同一引用

那我们在使用连等操作的时候一定要想清楚连等的便利性带来的意外效果,才要真正学会使用他

三、对象原型属性的读写
var testProtoObj = {
            _key:1,
        }
        Object.defineProperty(testProtoObj,'key',{
            get:function () {
                console.log('get testProtoObj.key value ')
                return this._key;
            },
            set:function (value) {
                console.log('set testProtoObj.key value ')
                this._key = value;
            }
        })
 
        var testProto = {
            _name:testProtoObj
        }
        Object.defineProperty(testProto,'name',{
            get:function () {
                console.log('get testProto.name value ')
                return this._name;
            },
            set:function (value) {
                console.log('set testProto.name value ')
                this._name = value;
            }
        })
        var demo  = {};
        demo.__proto__ = testProto;
        demo.name.key = 2;
        demo.name = 1;

————————————————
版权声明:本文为CSDN博主「four_lemmo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/four_lemmo/java/article/details/80794827

 

posted @ 2020-06-15 00:06  yang_nick  阅读(130)  评论(0编辑  收藏  举报