函數(shù)篇(上)
安全的類型檢測(cè)
JavaScript 內(nèi)置的類型檢測(cè)機(jī)制并非完全可靠。事實(shí)上榨惰,發(fā)生錯(cuò)誤否定及錯(cuò)誤肯定的情況也不在少數(shù)拜英。比如說 typeof操作符吧,由于它有一些無法預(yù)知的行為琅催,經(jīng)常會(huì)導(dǎo)致檢測(cè)數(shù)據(jù)類型時(shí)得到不靠譜的結(jié)果居凶。Safari(直至第4版)在對(duì)正則表達(dá)式應(yīng)用typeof操作符時(shí)會(huì)返回"function",因此很難確定某個(gè)值到底是不是函數(shù)
再比如藤抡,instanceof 操作符在存在多個(gè)全局作用域(像一個(gè)頁面包含多個(gè) frame)的情況下侠碧,也是問題多多。
如何解決上面的這些問題呢缠黍?
大家知道弄兜,在任何值上調(diào)用 Object 原生的 toString()方法,都會(huì)返回一個(gè)[object NativeConstructorName]格式的字符串。每個(gè)類在內(nèi)部都有一個(gè)[[Class]]屬
性挨队,這個(gè)屬性中就指定了上述字符串中的構(gòu)造函數(shù)名谷暮。
示例:
alert(Object.prototype.toString.call(value));
//判斷是不是數(shù)組
function isArray(value){
return Object.prototype.toString.call(value) == "[object Array]";
}
//判斷是不是函數(shù)
function isFunction(value){
return Object.prototype.toString.call(value) == "[object Function]";
}
//判斷是不是正則
function isRegExp(value){
return Object.prototype.toString.call(value) == "[object RegExp]";
}
作用域安全的構(gòu)造函數(shù)
什么是構(gòu)造函數(shù)?
構(gòu)造函數(shù)其實(shí)就是一種用new 操作符調(diào)用的函數(shù)盛垦,并且該函數(shù)的作用域會(huì)指向新創(chuàng)建的的對(duì)象實(shí)例
示例:
//新建一個(gè)Person函數(shù)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
}
//創(chuàng)建一個(gè)person構(gòu)造函數(shù)湿弦,這時(shí)Person的this就指向于person
var person = new Person("Nicholas", 29, "Software Engineer");
這是一個(gè)正常的構(gòu)造函數(shù)對(duì)吧,但是如果你忘記寫了new操作符呢腾夯?我們一起來看看
示例:
//新建一個(gè)Person函數(shù)
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
}
//創(chuàng)建一個(gè)person構(gòu)造函數(shù)颊埃,但是忘記了寫new操作符,這時(shí)候this指向誰呢蝶俱?
var person = Person("Nicholas", 29, "Software Engineer");
答案是Person函數(shù)的上一層作用域班利,在此處也就是windows
那么這個(gè)問題如何讓解決呢?
解決方案就是創(chuàng)建一個(gè)作用域安全的構(gòu)造函數(shù)榨呆。
示例:
//創(chuàng)建一個(gè)Person函數(shù)
function Person(name, age, job){
// 判斷this是不是Persoon的實(shí)例
if (this instanceof Person){
this.name = name;
this.age = age;
this.job = job;
} else {
// 如果不是就new Person
return new Person(name, age, job);
}
}
//這個(gè)函數(shù)會(huì)在沒有寫new操作符的情況下自動(dòng)創(chuàng)建一個(gè)帶有new 操作符的構(gòu)造函數(shù)
最后的結(jié)果是罗标,調(diào)用 Person 構(gòu)造函數(shù)時(shí)無論是否使用 new 操作符,都會(huì)返回一個(gè) Person 的新實(shí)例积蜻,這就避免了在全局對(duì)象上意外設(shè)置屬性闯割。
惰性載入函數(shù)
惰性載入表示函數(shù)執(zhí)行的分支僅會(huì)發(fā)生一次。有兩種實(shí)現(xiàn)惰性載入的方式竿拆,第一種就是在函數(shù)被調(diào)用時(shí)再處理函數(shù)宙拉。在第一次調(diào)用的過程中,該函數(shù)會(huì)被覆蓋為另外一個(gè)按合適方式執(zhí)行的函數(shù)丙笋,這樣任何對(duì)原函數(shù)的調(diào)用都不用再經(jīng)過執(zhí)行的分支了谢澈。
示例:
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
createXHR = function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
createXHR = function(){
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
createXHR = function(){
throw new Error("No XHR object available.");
};
}
return createXHR();
}
第二種實(shí)現(xiàn)惰性載入的方式是在聲明函數(shù)時(shí)就指定適當(dāng)?shù)暮瘮?shù)。這樣御板,第一次調(diào)用函數(shù)時(shí)就不會(huì)損失性能了锥忿,而在代碼首次加載時(shí)會(huì)損失一點(diǎn)性能。
示例:
var createXHR = (function(){
if (typeof XMLHttpRequest != "undefined"){
return function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
return function(){
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
return function(){
throw new Error("No XHR object available.");
};
}
})();
這個(gè)例子中使用的技巧是創(chuàng)建一個(gè)匿名稳吮、自執(zhí)行的函數(shù)缎谷,用以確定應(yīng)該使用哪一個(gè)函數(shù)實(shí)現(xiàn)。實(shí)際的邏輯都一樣灶似。不一樣的地方就是第一行代碼(使用 var 定義函數(shù))、新增了自執(zhí)行的匿名函數(shù)瑞你,另外每個(gè)分支都返回正確的函數(shù)定義酪惭,以便立即將其賦值給 createXHR()。