早上看到《JavaScript 每周導讀》【第三期】一文,裡面發現一篇文章(Extending JavaScript – The Right Way),覺得還不錯,翻譯過來跟大家共用,本文並不是逐字逐句進行翻譯,盡量說得通俗易懂。
原文地址:Extending JavaScript – The Right Way
以下是譯文
JavaScript已經內建了很多強大的方法,但有時你需要的某個功能在內建的方法中沒有,我們怎麼來優雅地擴充JavaScript功能呢。
例如我們想增加一個capitalize()方法來實現首字母大寫,通常我們這樣寫:
if(!String.prototype.capitalize){ String.prototype.capitalize = function() { return this.slice(0,1).toUpperCase() + this.slice(1).toLowerCase(); }}
上面的代碼可以正常使用,但如果在某個地方有下面的代碼:
var strings = "yay";for(i in strings) console.log(i + ":" + strings[i]);
我們得到的結果是這樣的:
0: y1: a2: ycapitalize: function () { return this.slice(0, 1).toUpperCase() + this.slice(1).toLowerCase(); }
這顯然不是我們想要的結果,輸出了我們增加的方法的原因是我們增加的方法的enumerable屬性預設為true。
我們可以通過簡單地把枚舉屬性(enumerable)設定為false避免這個問題,使用defineProperty方法進行功能的擴充:
if(!String.prototype.capitalize){ Object.defineProperty(String.prototype, 'capitalize', { value: function() { return this.slice(0,1).toUpperCase() + this.slice(1).toLowerCase(); }, enumerable: false });}
現在我們再運行這段代碼:
var strings = "yay";for(i in strings) console.log(i + ":" + strings[i]);
我們得到的結果是:
0: y1: a2: y
要注意的是,用迴圈沒有輸出的並不代表不存在,我們可以通過下面的代碼查看到定義:
var strings = "yay";console.log(strings.capitalize)
會輸出:
function () { return this.slice(0, 1).toUpperCase() + this.slice(1).toLowerCase(); }
用這種方式擴充JavaScript功能比較靈活,我們可以用這種方式來定義我們自己的對象,並設定一些預設值。
以下是另外幾個擴充方法,你可以在自己的項目中使用:
String.pxToInt()
把"200px"這樣的字串轉換為數字 200 :
if(!String.prototype.pxToInt){ Object.defineProperty(String.prototype, 'pxToInt', { value: function() { return parseInt(this.split('px')[0]); }, enumerable: false });}
String.isHex()
判斷一個字串是否是16進位表示的,如"#CCC" 或 "#CACACA"
if(!String.prototype.isHex){ Object.defineProperty(String.prototype, 'isHex', { value: function() { return this.substring(0,1) == '#' && (this.length == 4 || this.length == 7) && /^[0-9a-fA-F]+$/.test(this.slice(1)); }, enumerable: false });}
String.reverse()
字串反轉:
if(!String.prototype.reverse){ Object.defineProperty(String.prototype, 'reverse', { value: function() { return this.split( '' ).reverse().join( '' ); }, enumerable: false });}
String.wordCount()
統計單詞數量,用空格分開
if(!String.prototype.wordCount){ Object.defineProperty(String.prototype, 'wordCount', { value: function() { return this.split(' ').length; }, enumerable: false });}
String.htmlEntities()
html標籤如<和>編碼為特殊字元
if(!String.prototype.htmlEntities){ Object.defineProperty(String.prototype, 'htmlEntities', { value: function() { return String(this).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); }, enumerable: false });}
String.stripTags()
去掉HTML標籤:
if(!String.prototype.stripTags){ Object.defineProperty(String.prototype, 'stripTags', { value: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, enumerable: false });}
String.trim()
去掉首尾空格:
if(!String.prototype.trim){ Object.defineProperty(String.prototype, 'trim', { value: function() { return this.replace(/^\s*/, "").replace(/\s*$/, ""); }, enumerable: false });}
String.stripNonAlpha()
去掉非字母字元:
if(!String.prototype.stripNonAlpha){ Object.defineProperty(String.prototype, 'stripNonAlpha', { value: function() { return this.replace(/[^A-Za-z ]+/g, ""); }, enumerable: false });}
Object.sizeof()
統計對象的大小,如{one: “and”, two: “and”}為2
if(!Object.prototype.sizeof){ Object.defineProperty(Object.prototype, 'sizeof', { value: function() { var counter = 0; for(index in this) counter++; return counter; }, enumerable: false });}
PS
這種方式擴充JS原生對象的功能還是挺不錯的,但除非必要(項目中用的很多),不建議直接在原生對象上擴充功能,會造成全域變數汙染。
另外,文中的pxToInt()方法是沒什麼必要的,JS中的parseInt()可以直接完成這樣的功能:parsetInt("200px")===200
htmlEntities方法貌似有問題,下面另提供一個:
if(!String.prototype.htmlEntities){ Object.defineProperty(String.prototype, 'htmlEntities', { value: function() { var div = document.createElement("div"); if(div.textContent){ div.textContent=this; } else{ div.innerText=this; } return div.innerHTML; }, enumerable: false });}