深入理解javascript的bind

来源:互联网 发布:学ue4编程多重要 编辑:程序博客网 时间:2024/04/29 14:29

bind有两个功能

  • 实现this绑定
  • 实现柯里化

1.实现this绑定

function f(){return this.a;}var g = f.bind({a : "test"});console.log(g()); // testvar o = {a : 37, f : f, g : g};console.log(o.f(), o.g()); // 37, test

第一个bind将{a:”test”}对象绑定到f函数的this上。使得f函数返回了this.a即返回了{a:”test”}的a属性。

第二个调用o.g()时,g指针指向了var定义的g函数,由于g函数已经绑定了{a:”test”}对象,打印出test。

1.实现柯里化currying

什么是柯里化捏?

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。
var foo = {x: 888};var bar = function () {    console.log(this.x);}.bind(foo);               // 绑定bar();                     // 888

下面是一个 bind 函数的模拟,testBind 创建并返回新的函数,在新的函数中将真正要执行业务的函数绑定到实参传入的上下文,延迟执行了。

Function.prototype.testBind = function (scope) {    var fn = this;                    //// this 指向的是调用 testBind 方法的一个函数,     return function () {        return fn.apply(scope);    }};var testBindBar = bar.testBind(foo);  // 绑定 foo,延迟执行console.log(testBindBar);             // Function (可见,bind之后返回的是一个延迟执行的新函数)testBindBar();                        // 888

bind方法实现源码

先看一个案例

function foo() {this.b = 100;return this.a;}var func = foo.bind({a:1});func(); // 1new func(); // {b : 100}

new 一个func和直接执行func的区别是什么呢?
new一个func之后,会建立一个空对象,空对象的prototype是foo的prototype,空对象的b属性是100,会忽略掉return的a属性,把当前对象返回。所以返回的就是新建的这个对象{b:100}了。

所以说,new一个新对象之后,对于bind,返回值被覆盖了。

if (!Function.prototype.bind) {//这里 oThis和作为bind函数后的第一个参数传入,上例中是{a:1}Function.prototype.bind = function(oThis) {//这里的this是调用bind方法的对象,上例中是foo。if (typeof this !== 'function') {// closest thing possible to the ECMAScript 5// internal IsCallable functionthrow new TypeError('What is trying to be bound is not callable');}//通过arguments获取多余的参数,即第二个参数及以后的参数。bind函数将多余的参数当作方法的形参var aArgs = Array.prototype.slice.call(arguments, 1),fToBind = this,fNOP = function() {},//fBound作为整个bind函数返回对象,上例中就是func对象fBound = function() {//这里的this是bind返回的对象实例指向的this,上例中就是func调用时指向的this。return fToBind.apply(this instanceof fNOP? this : oThis,aArgs.concat(Array.prototype.slice.call(arguments)));};/*下两句代码实现了object.create的作用。*///新建一个function 它的原型指向this的原型fNOP.prototype = this.prototype;//fBound.prototype = new fNOP();return fBound;};}

其中这段代码:

//这里的this是bind返回的对象实例指向的this,上例中就是func调用时指向的this。return fToBind.apply(this instanceof fNOP? this : oThis,aArgs.concat(Array.prototype.slice.call(arguments)));};

1.按照例子,如果说直接调用

func()

那么func 的this就指向了window对象,window对象肯定不在fNOP的原型链上,则返回oThis。即,指向var func = foo.bind({a:1});的{a:1}对象。

2.如果这样调用

new func(); 

我们知道new方法返回一个新对象,新对象的prototype属性指向构造器的prototype属性,即指向foo的prototype属性。

而在bind源码里,fNOP.prototype = this.prototype;这里this是指向的foo对象。那么这里的this也是指向的foo对象。那么this instanceof fNOP返回true,就这么成功的覆盖了bind最原始的返回对象啦。

0 0
原创粉丝点击