IE 里有很多原生的 Javascript 函数实际上都不是一个标准的 Function 对象,例如 window.alert,window.setTimeout 以及 IE8 的 window.console.log 等。在需要对这样的函数进行包装的时候,会因为它们都没有 Function 对象应该有的 .apply() 及 .call() 方法而难以做到。

这段代码为了兼容旧版本没有 console 的浏览器,尝试将 console.log 包装为 $.log,但是基于上述原因它在 IE 里无法执行。

$ = {};

if (console && console.log) {
    $.log = function() {
        console.log.apply(console, arguments);
    };
} else {
    $.log = function() {};
}

由于 window 和 console 这样的原生对象都是只读的,所以无法使用类似这样的代码简单地为其添加 .apply() 方法。

console.log.apply = Function.apply;

解决办法是使用 Function.apply.apply() 将 Function.apply 函数对象 apply 到 console.log 上。

$ = {};

if (console && console.log) {
    $.log = function() {
        Function.apply.apply(console.log, [console, arguments]);
    };
} else {
    $.log = function() {};
}

这段代码和第一段代码完全等价。

如果觉得不容易理解,可以看看这个 .apply() 函数比较清晰的例子。这两行代码也完全等价。

[1, 2, 3, 4].slice(0, 2);
Array.prototype.slice.apply([1, 2, 3, 4], [0, 2]);
标签: