欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

关于new从一个BUG说起

程序员文章站 2022-03-19 16:57:39
...


前言

今天在一个前端群组里,看到有人发出一个问题:

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操作符做了什么工作呢?

话说我们现在的问题是什么呢?问题就是处在了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说起 的详细内容,更多请关注其它相关文章!