今天在一个前端群组里,看到有人发出一个问题:
var o = new Object();function foo(obj){ var obj = o; obj.name = '123'; obj = new Object(); obj.name = '456'; } foo(o); console.log(o.name)
如上代码所示,在不改变任何条件和数据的情况下,有没有可能输出“456”?
没多久,群组中人就开始下结论,正常情况下是不能的。
原因吗,稍微知道引用类型的使用方式的人都知道的,new Object(),改变了obj的指向,永远没法获得456。
正常情况下不可能输出456,那在什么样的错误情况下能够输出456呢?毕竟程序员就是擅长写BUG的吗,应该能够搞得非正常情况的吧。
然后,手残的自己突然想到前两天刚学习的Proxy。我们现在是赋值时出的问题,那么能不能从元数据上解决问题呢?尝试一下:
//demo_01var o = new Object(); o = new Proxy(o,{ set(target, key, value,receiver){ if(Object.is('name',key)) return Reflect.set(target, key, `456`,receiver); return Reflect.set(target, key, value , receiver); } })function foo(obj){ var obj = o; obj.name = '123'; obj = new Object(); obj.name = '456'; } foo(o); console.log(o.name)
完美,成功地输出了456。
什么?你不知道Proxy是什么?点击这里 –> ES6 拦截器,Proxy
那么,现在就是嘚瑟的时间了,准备将结果发送到群组炫耀下。先翻看下聊天记录,呦呵,已经有人给出了一个答案,比我还快。好吧,先看看人家的答案:
//demo_02var o = new Object();Object.defineProperty(o,'name',{ set(val){ this.value = '456'; }, get(){ return this.value; } })function foo(obj){ var obj = o; obj.name = '123'; obj = new Object(); obj.name = '456'; } foo(o); console.log(o.name)
厉害的小伙子,跟我想到了一起去了,都是在getter和setter上做文章,都是在元级别上处理数据。
这位同学同时贴出一篇文章,说是从这里获取的灵感,狠戳这里,一起欣赏下吧,写得的确很不错 –> 无懈可击的钩子
接下来,也贴下我的答案吧,就当时凑个热闹吧。等等,有人表示不服了,说他是在投机取巧。demo_02代码完全等价与demo_03代码:
//demo_03var o = new Object();function foo(obj){ var obj = o; obj.name = '123'; obj = new Object(); obj.name = '456'; } foo(o); o.name = '456'; console.log(o.name);
当demo_02的方法中最后一行代码”obj.name = ‘456’;”进行修改时,demo_02的代码中的”this.value = ‘456’;”也得随之修改。
说的好有道理,我们的确是在投机取巧,我写得demo_01也是同样的问题,还好没点回车键,不然就没脸了。
那么有没得什么办法可以解决这里问题,实现真正的输出456
话说我们现在的问题是什么呢?问题就是处在了new Object()上,它修改了obj的this指向,那么我们有没有什么办法规避呢?
什么?你问我为什么this指向改变了,我只能说,你真的得好好学习JS了,看看这篇文章吧,作者的笔风好有趣,从一个士兵说起new都做了什么
我记得在Proxy的handler中有个construct方法,如果我能在Object构造器中修改它的this。想法很好,但是失败了,没能实现。如果,有哪位能在这个思路上走下去,求告知答案 >_<
查看聊天记录,那位同学又给出了一种解决方法:
var o = new Object();var _Object = Object;Object = function(){ return o; }function foo(obj){ var obj = o; obj.name = '123'; obj = new Object(); obj.name = '456'; } foo(o); console.log(o.name)Object = _Object;
这次这位同学先重写了Object对象,让它返回o这个对象,这就避免了this指向的变动,有才啊,佩服。默默收藏<_<
以上是关于new从一个BUG说起 的详细内容。更多信息请关注PHP中文网其他相关文章!