相信很多人應該都有想對瀏覽器 JavaScript引擎
所提供的原生類別 (例如 Object、Array、String) 與物件擴充
原則上大部分只需要增加 function (method) 即可
但是要達成目的有些問題是要注意的
問題
1. 為什麼不用 JavaScript OO強化模組建立擴充模組?
JavaScript OO強化模組雖有提供繼承能力
但是繼承原生類別所建立的模組卻有先天缺陷
原因在於部分原生類別 (function) 的 function只接受該類別建立的物件呼叫
即使是繼承該類別的子類別亦不可
否則就會接到錯誤例外 (Error Exception) 無法執行
因此僅有針對該類別的原型 (prototype) 作擴充一途
實驗:
P = new Date(); function Test(){}; Test.prototype = P; T = new Test(); T.getDate(); // Error
2. 對原生類別擴充新成員的時候會如何?
如果有使用過 for each迴圈
JavaScript中語法 for (attrName in object) { ... }
應該會知道 for each迴圈會將物件中的所有成員列舉出來
在 JavaScript中,不管成員的值是什麼都算是成員
但像是陣列 (Array) 物件含有許多 method
例如 slice、sort,都是 Array 的成員
但使用 for each迴圈的時候卻都不會被列舉
又例如 Object 也有許多的成員 function,也不會被列舉出來
這是因為原生類別幾乎所有固定成員
幾乎都被設定為不可列舉 (non-enumerable)
因此 for each迴圈就不會將這些成員列舉
如果對原生物件增加新成員,新成員卻不會被認為是不可列舉的
這就會造成非常大的影響
尤其現在許多應用當中會直接使用 Object物件
並且對這些物件使用 for each迴圈對成員做一致性處理
原本並不預期會出現的成員,卻因為新成員加入而擾亂
致使程式出現意料不到的錯誤
3. 擴充成員名稱與原有名稱相同應該如何?
基本上會使用這樣的方式
大概都是希望對原有的 function作擴充
不過這樣的方式在 JavaScript當中做起來是很麻煩的
因為開發者必須要先儲存舊 function在變數中
接著在新 function中,使用這個舊 function
但要注意的是,因為舊 function已經和物件斷開連結了
因此必須要用 functoin.call 或 function.apply 呼叫
多了,程式碼會變得稍微難管理
解法
雖然說 JavaScript OO 強化模組可能不適用
但是其中的 function繼承技術還是可以拿出來用的
本文提供的解法就借用了 OO 強化模組當中的一部份
解決名稱衝突的問題,但是還有一點要注意的是
有時候只是為了補足瀏覽器平台太舊而沒有新版本提供的 function
在這情況下,並不希望將原生的 function取代掉
例如 Object.keys,Array.prototype.indexOf 等
但是另一個解法是對 jQuery做函式擴充
端看開發人員喜歡哪一種語言表示法
但是也要注意的是,如果擴充了太常使用的成員名稱
而與其他模組衝突,程式運作出問題仍是無法避免的
( 例如 jQuery-DataTable 插件,對 Object 新增 toArray
若是自行擴充 toArray,會對該插件運作產生嚴重錯誤 )
有時候並不只針對 prototype擴充
而會針對這個類別本身進行擴充
例如前述的 Object.keys
因此本文提供的解法當中可以設定一些擴充用參數
來達成多種目的
為了解決for each迴圈的成員列舉問題
當中使用了 Object.defineProperty 設定成員的列舉特性
但是需要注意的是 Object.defineProperty
在 IE瀏覽器當中,必須要 9以上才能運作
( IE 8雖有提供,但是僅針對 HTML DOM物件設定 )
所以本模組有 IE 瀏覽器瀏覽模式必須 9以上的限制
程式碼
因為當中沒用到太艱深的技術
關鍵部分也是抄過來,使用限制目前也算多
提供上來讓大家參考,看是否有人有其他好想法
當中除了擴充功能外,亦針對部分原生物件做了擴充
Remark
1. 2015/09/18,新增 String.prototype.substr 功能擴增
留言列表