如果我们在JavaScript中填充fn.bind(),为什么还要检查“this”的类型?

时间:2016-01-19 01:24:05

标签: javascript prototypal-inheritance

我在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的类型?

2 个答案:

答案 0 :(得分:8)

  

如果fn不是函数,那么fn.bind永远不会通过原型继承达到Function.prototype.bind

是的,但这不是this可以设置的唯一方式。例如,如果我们在.call函数本身上使用.applybind方法,或者做一些非常疯狂的事情,比如将它分配给其他对象,那么它的行为将与本机不同功能

使用本机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及以后:

  
      
  1. 目标成为值。
  2.   
  3. 如果IsCallable(目标 false ,则抛出 TypeError 例外。
  4.   

答案 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.callFunction.prototype.applyReflect.apply等内容的原因。您可以使用它们在任何对象上调用bind,无论它是否可以调用。

反过来也是可能的。您可以拥有一个继承自Function.prototype并且不可调用的对象。例如:

Object.create(Function.prototype) instanceof Function; // true
typeof Object.create(Function.prototype) === "function"; // false

因此,您无法做出任何假设。如果希望polyfill符合ES5,则必须检查对象是否可调用。在ES5中,检查typeof是否返回"function"的确如此(但在ES3中,它可能不适用于主机对象)。