本文在我博客上的地址: 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'));
此題這樣就算解決了,此題的精髓主要是三點:繼承
你可否想到經過屬性訪問自身
你可否想到使用原型繼承來定義訪問自身的屬性
你是否知道 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'));