博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一道赋值面试题引发的思考
阅读量:6686 次
发布时间:2019-06-25

本文共 2464 字,大约阅读时间需要 8 分钟。

本篇主要说一些基础知识点,关于多项赋值顺序,对象引用等,期间插入一点es6只是以及解决问题的思路。

开头先来做一道面试题

part1

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

最后输出的是什么? 先不说答案,我们来分析一下

L2(第二行) 我们把a赋值给b, 由于a是对象类型,这就意味着b和a指向同一个内存地址

L3 a.x = a = { n: 2}

这里我们有个疑惑,这句语句执行顺序是 a = {n: 2} && a.x = {n:2} 还是 a.x = {n:2} && a= {n:2} 还是这种 a = {n: 2} && a.x = a

我们这里可以借助 Object.defineProperty 或 ES6的 Proxy来验证多项赋值的顺序是怎样的

const obj = new Proxy({}, {  set(target, key, value, r) {    console.log(key, value)    if (key === 'a') Reflect.set(target, key, 'isA', r);    else Reflect.set(target, key, value, r);  }});obj.b = obj.a= {
n: 1};// 输出:// "a" {n: 1}// "b" {n: 1}obj.a; // isAobj.b; // {n: 1}复制代码

所以我们可以得出 赋值的顺序是从右边开始到左边的。而且是直接 a = {n: 1}, a.x = {n:1 },而不是 a.x = a 这样去赋值

现在我们再借助 Proxy 来分析一开始part1这道题,用obj.a, obj.b 来代替原题目的 a和b。

var obj = new Proxy({}, {  get: function (target, key, receiver) {    console.log(`getting ${key}!`);    return Reflect.get(target, key, receiver);  },  set: function (target, key, value, receiver) {    console.log(`setting ${key}!`);    return Reflect.set(target, key, value, receiver);  }});obj.a = {
n: 1 };// getting a;obj.b = obj.a; // getting a; setting b;obj.a.x = obj.a = {
n:2 }; // getting a; setting a;复制代码

可以看到 obj.a.x = obj.a = {n: 2}这段语句执行时,会先输出一个 getting a 再输出 setting a

这就意味着在对 obj.a.x 赋值时,程序是先获取 obj.a指向的对象的内存地址,此时触发了 getting a,然后再对右边 obj.a 进行赋值,触发了 setting a, 赋值完最后一步才是对 obj.a.x赋值 {n:2 }

重点: 在对obj.a.x赋值的时刻已经获取了obj.a该对象指向的内存地址,所以后面a就算指向其他地址,也和这里的obj.a.x无关。此时指向该地址的还有obj.b

我们再用三张图来捋一捋整理的思路

执行 obj.a = {n: 1}; obj.b = obj.a后obj对应的引用是这样的

执行 obj.a.x = xxx

执行obj.a.x = obj.a = {n:2}

至此,这道面试题相信大家都有答案了,可以自己去控制台验证一下。 假如这时候再执行 obj.a.n = 3, 打印obj.b会输出什么呢?

part2

接下来我们来看另一道题,关于对象循环引用的

var a = { n: 1}a.b = a;复制代码

这里的a明显是循环引用,那么我们要怎样才能判断一个对象是否是循环引用呢?

其实这道题我一开始除了递归判断外没有很好的解决方案,后面是群里一个叫话费的大佬说(这道题也是他出的)直接用 JSON.stringify,微信小游戏的源码里面就是这么去判断。

JSON.stringify 如果遇到参数里有循环引用的,就会抛出一个循环调用的错误 Uncaught TypeError: Converting circular structure to JSON

那如果不用JSON.stringify或者想要自己实现一个去检测循环调用,该怎么写呢?(面试官和部门前端leader最喜欢这么问)

一般遇到这种,最简单的方法就是去找这个方法的 polyfill, 。我找的是 json3的 polyfill 里面大概是遍历对象存到stack数组,再在解析的时候去判断是否有循环引用的情况。

照着他的思路大概写了一个,其实就是前面说到的简单递归判断

var stack = [];function fn(obj) {    var len;    for (len = stack.length; len--;) {        if (stack[len] === obj) throw TypeError()    }    stack.push(obj);    for (let k in obj) {        const value = obj[k]        if (typeof value === 'object') fn(value);    }}复制代码

最后第一次讲关于语言知识点的,如果发现有错误的地方 欢迎指出~

谢谢惠顾,请笑纳

转载地址:http://tueao.baihongyu.com/

你可能感兴趣的文章
一些关于Hibernate延迟加载的误区
查看>>
设计模式之缺省适配模式
查看>>
qsort函数辅助函数compare函数的编写
查看>>
项目选题报告答辩总结模板
查看>>
uva 10972 RevolC FaeLoN
查看>>
zookeeper实现队列_Queue
查看>>
转 delete 和 delete []的真正区别
查看>>
outline
查看>>
javaScript引入方式
查看>>
[摘录]验证视图MAC失败 Validation of ViewState MAC Failed
查看>>
asp.net mvc生命周期学习
查看>>
C++ explicit关键字避免隐式转换
查看>>
HDU 1212 Big Number 【大数求余模拟】
查看>>
静态类(static)与java值传递、引用传递小测
查看>>
小怪受击身体变红特效代码
查看>>
C语言中函数strcpy ,strncpy ,strlcpy的用法
查看>>
Android深入浅出系列之Bluetooth—蓝牙操作(一)
查看>>
MapReduce入门
查看>>
软件测试作业03
查看>>
vs 代码格式化
查看>>