【web】從一個BUG說起

前言

今天在一個前端羣組裏,看到有人發出一個問題:

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_01
var 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_02
var 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_03
var 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指向的變動,有才啊,佩服。默默收藏<_<


努力吧,總有人能教會你點什麼

發佈了89 篇原創文章 · 獲贊 63 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章