標籤:
這是一篇[javascript the good parts]的讀書筆記。
我們知道可以利用javascript 的prototype 特性為原始類型編寫拓展模組。利用如下方法:
Object.prototype.method = function(name, func) { Object.prototype[name] = func}
為javascript 裡的所有對象添加一個便捷的擴充方法method. 這個便捷方法省去了我們每次都手工輸入Object.prototype.xxxx
現在我們要為string 類型添加一個拓展方法,叫做deentityify,作用是把形如 < 或者 &qout; 這樣的字串替換成他原來的樣子。
很自然的,我們需要一個存著替換規則的表:
var entity = { qout: ‘"‘, lt: ‘<‘, gt: ‘>‘}
但是現在的問題是,這個表應該讓他存在哪呢?
方案1.存在全域變數裡。
方案2.就存在deentityify 這個函數裡。
方案1不可行?,因為全域變數是邪惡的?? 我們應該盡量避免使用全域變數。
那就試試方案2:
String.method(‘deentityify‘, function(){ var entity = { quot: ‘"‘, lt: ‘<‘, gt: ‘>‘ } return this.replace(/&[^&;]+);/g, function(a, b) { var r = entity[b]; return typeof r === ‘string‘ ? r : a; })})var s = "<">"s.deentityify() //<">
結果是正確的,但是有個問題,每次調用deentityify 的時候,entity 都被求值一次,這顯然會增加開銷。
看來方案2也不是最理想的,有沒有什麼規避的方法呢?設想,如果讓entity 只求值一次,然後把他的結果儲存下來,以後每次調用deentityify 的時候直接使用entity的結果,而不是每次調用都去把他再求值一次。這可以做到嗎?
當然可以,答案就是使用閉包:
String.method(‘deentityify‘, function(){ var entity = { quot: ‘"‘, lt: ‘<‘, gt: ‘>‘ } return function () { return this.replace(/&[^&;]+);/g, function(a, b) { var r = entity[b]; return typeof r === ‘string‘ ? r : a; }) }}())
相比方案2直接返回結果,閉包的方案是返回一個函數,然後立即對他求值,求值的結果作為deentityify 的值。
感覺有點繞,但是這樣的一個好處是,entity 只在String.method() 這裡被求值,以後,每次用deentityify 的時候,我們都只是直接使用entity 的值,而不用每次都求值了。這就是閉包的威力。
[javascript] 使用閉包編寫模組