我在fn.bind()
的{{3}}中看到了这样的内容:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
// other code omitted here...
};
}
我不明白为什么我们必须检查this
的类型...因为如果我们说fn.bind()
和fn
是一个函数,那么它会起作用,如果fn
不是函数,fn.bind
永远不会通过原型继承达到Function.prototype.bind
。那么我们为什么要检查this
的类型?
答案 0 :(得分:8)
如果
fn
不是函数,那么fn.bind
永远不会通过原型继承达到Function.prototype.bind
。
是的,但这不是this
可以设置的唯一方式。例如,如果我们在.call
函数本身上使用.apply
或bind
方法,或者做一些非常疯狂的事情,比如将它分配给其他对象,那么它的行为将与本机不同功能
使用本机ES5方法考虑以下代码:
var notAFunction = {};
var someObject = {};
Function.prototype.bind.call(notAFunction, someObject);
这将抛出TypeError
,如下所示:
TypeError:在不兼容的对象上调用Function.prototype.bind
这个额外的检查基本上是尽可能地从本机函数模拟这种健全性检查。
那么我们为什么要检查
this
的类型?
你在技术上必须,因为这种情况对于大多数理智的代码来说都是边缘情况,但是为了使polyfill表现得更接近ES5规范,它是不错。由于ES5浏览器甚至不会运行此代码,因此现代浏览器也没有性能损失。
此行为is defined in the ECMA-262 5.1 Edition specification及以后:
- 让目标成为此值。
- 如果IsCallable(目标) false ,则抛出 TypeError 例外。
醇>
答案 1 :(得分:3)
并非所有可调用对象都继承自(或等于)Function.prototype
。例如:
typeof document.createElement('object') === "function"; // true
document.createElement('object') instanceof Function; // false
即使从Function.prototype
继承的对象也可以bind
遮蔽:
var f = function() {};
f.bind = 123;
f.bind === Function.prototype.bind; // false
但是,您可能希望能够在这些可调用对象上调用Function.prototype.bind
。这就是我们拥有Function.prototype.call
,Function.prototype.apply
或Reflect.apply
等内容的原因。您可以使用它们在任何对象上调用bind
,无论它是否可以调用。
反过来也是可能的。您可以拥有一个继承自Function.prototype
并且不可调用的对象。例如:
Object.create(Function.prototype) instanceof Function; // true
typeof Object.create(Function.prototype) === "function"; // false
因此,您无法做出任何假设。如果希望polyfill符合ES5,则必须检查对象是否可调用。在ES5中,检查typeof
是否返回"function"
的确如此(但在ES3中,它可能不适用于主机对象)。