jQuery 1.4 源碼 449 行(core.js 431 行),判斷是否為函數的方法如下(思路來源於 Douglas Crockford 的《The Miller Device》):
isFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
},
同時 jQuery 的作者也作了部分注釋:
See test/unit/core.js for details concerning isFunction. Since version 1.3, DOM methods and functions like alert aren't supported. They return false on IE (#2968).
即:此方法在 IE 下無法正確識別 DOM 方法和一些函數(例如 alert 方法等)。
為什麼會這樣呢?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>修復 jQuery 中 isFunction 方法的 BUG</title>
</head>
<body>
<h3>使用 typeof 運算符檢測各種方法:</h3>
<script>
document.writeln('typeof eval: ' + typeof eval + '<br>');
document.writeln('typeof confirm: ' + typeof confirm + '<br>');
document.writeln('typeof confirm: ' + typeof window.open + '<br>');
document.writeln('typeof alert: ' + typeof alert + '<br>');
document.writeln('typeof window.alert: ' + typeof window.alert + '<br>');
document.writeln('typeof document.getElementById: ' + typeof document.getElementById + '<br>');
document.writeln('typeof document.createElement: ' + typeof document.createElement + '<br>');
</script>
<h3>測試原始的 isFunction 函數方法</h3>
<script>
var isFunction = function( fn, name ) {
return document.writeln('isFunction(' + name + '): ' + (Object.prototype.toString.call(fn) === "[object Function]") + '<br>');
}
isFunction(eval,'eval');
isFunction(confirm, 'confirm');
isFunction(window.open, 'window.open');
isFunction(alert, 'alert');
isFunction(window.alert, 'window.alert');
isFunction(document.getElementById, 'document.getElementById');
isFunction(document.createElement, 'document.createElement');
isFunction(isFunction, 'isFunction');
</script>
<h3>測試修復後 isFunction 函數方法</h3>
<script>
var isFunction = (function() {
return typeof document.getElementById === "object" ?
isFunction = function(fn, name){
try {
return document.writeln('isFunction(' + name + '): ' + (/^s*bfunctionb/.test("" + fn)) + '<br>');
} catch (x) {
return document.writeln('isFunction(' + name + '): ' + (false) + '<br>');
}
}:
isFunction = function(fn, name){
return document.writeln('isFunction(' + name + '): ' + ("[object Function]" === Object.prototype.toString.call(fn)) + '<br>');
};
})()
isFunction(eval,'eval');
isFunction(confirm, 'confirm');
isFunction(window.open, 'window.open');
isFunction(alert, 'alert');
isFunction(window.alert, 'window.alert');
isFunction(document.getElementById, 'document.getElementById');
isFunction(document.createElement, 'document.createElement');
isFunction(isFunction, 'isFunction');
</script>
</body>
</html>
[Ctrl+A 全選 注:如需引入外部Js需刷新才能執行]
會發現在 IE 下用 typeof 檢測 alert、confirm 方法以及 DOM 的方法顯示 object,而其他浏覽器下顯示 function。
那如何完善這個問題呢?
typeof 檢測某個方法(例如:document.getElementById) 是否是 object,如何是,則重寫 isFunction 函數;
怎樣重寫呢?正則判斷傳入的對象字符串後(”" + fn),是否起始位置含有 function,即:/^s*bfunctionb/.test(” + fn)。
OK,看下根據以上思路修改後的 isFunction 函數:
代碼如下:
var isFunction = (function() { // Performance optimization: Lazy Function Definition return "object" === typeof document.getElementById ? isFunction = function(fn){ try { return /^s*bfunctionb/.test("" + fn); } catch (x) { return false } }: isFunction = function(fn){ return "[object Function]" === Object.prototype.toString.call(fn); };})()