__defineGetter__ 引起的思考

本文在我博客上的地址: http://lpgray.me/article/46/javascript

問題

那天朋友分享了一個面試題,本身當時不會,代碼以下:java

(function(){
    var u = { a: 1, b: 2 };
    var r = {
        m: function(k){
            return u[k];
        }
    }
    window.r = r;
})()

var R = window.r;
alert(r.m('a'))

很簡單,alert的結果是1。面試

可是題目倒是另一個說法,能不能經過r.m獲取到u?函數

當時聽到這個問題也凌亂了,壓根就不知道啥意思,經過r.m獲取到u?優化

實際上這個問題問的重點是當u不知道的時候,如何經過u[attribute]這種方式來得到u的自身。那麼問題就來了,你須要傳遞一個attribute,r.m(attribute) 返回 u。this

解決方案

有一個非標準的,並且將被廢棄的方法 Object.prototype.__defineGetter__ 能夠給對象指定一個參數而且綁定一個函數,當將來你在此對象的實例上調用此參數時,綁定的函數會被調用,該參數是被定義在 prototype 上,因此此參數就是一個實例屬性,那個函數被調用時,是以當前實例爲上下文。prototype

哦?那這樣的話u就是一個實例,給u綁定一個參數,當此參數調用的時候返回u自身不就好啦?code

怎麼綁定呢?u是一個Object的實例,它繼承自Object,那麼就給 Object.prototype 定義一個屬性,使得該屬性訪問時調用的函數返回 this 就能夠了,因此,解決方案以下:對象

Object.prototype.__defineGetter__('uuu', function(){ return this; });
alert(R.m('uuu'));

此題這樣就算解決了,此題的精髓主要是三點:繼承

  1. 你可否想到經過屬性訪問自身

  2. 你可否想到使用原型繼承來定義訪問自身的屬性

  3. 你是否知道 Object.prototype.__defineGetter__

優化解決方案

爲了避免污染 Object 原型鏈,咱們應該定義一個隨機的參數來返回自身,當使用以後再刪除之,那麼比較完美的方案應該是:

Object.prototype.__defineGetter__('x123c3', function(){ return this; });
alert(R.m('x123c3'));
delete Object.prototype['x123c3']

既然廢棄了,有沒有替代方法?

嗯,原本本身不太清楚,感謝網友的幫忙。

目前存在這麼一個API:Object.defineProperty(obj, 'key', { // descriptor }); 參閱API

使得能夠直接在某一對象上定義一個屬性,這個屬性能夠是添加或修改現有的屬性,前兩個參數都很好理解,obj就是要修改的對象,key就是屬性名,descriptor是一個對象,用來聲明新添屬性的一些特性,包括6個參數:

  • configurable:默認false,表示此屬性是否可用delete刪除

  • enumerable: 默認爲false,表示此屬性是否可被for...in、Object.keys遍歷到

  • value:默認undefined,此屬性的值,能夠是任何JavaScript類型

  • writable:默認爲false,此屬性是否可被改寫

  • get:默認undefined,指定一個函數,當屬性被調用時,此函數也被調用,默認爲返回屬性值

  • set:默認undefined,指定一個函數,當屬性被賦值時,此函數也被調用,僅接受一個參數,參數爲屬性被賦的值

那麼上面的解決方案能夠改成:

Object.defineProperty(Object.prototype, 'blablabla', {
    get : function(){
        return this;
    }
});
console.log(R.m('blablabla'));
相關文章
相關標籤/搜索