zoukankan      html  css  js  c++  java
  • 《Javascript高级程序设计》读书笔记之bind函数详解

    为什么需要bind

    var name = "The Window";
    var object = {
        name: "My Object",
        getNameFunc: function () {
            return function () {
                return this.name;
            }
        }
    };
    
    alert(object.getNameFunc()()); //"The Window"

    object.getNameFunc()返回一个匿名函数,在全局环境调用该函数,this指向的全局对象

    解决这一问题,可以像下面这样,将匿名函数外部作用域中this对象保存在闭包能够访问到的变量中

    var name = "The Window";
    var object = {
        name: "My Object",
        getNameFunc: function () {
            var that = this;
            return function () {
                return that.name;
            }
        }
    };
    
    alert(object.getNameFunc()()); //"My Object"

    上述解决方法需要修改对象的方法,如果不能修改原对象的方法,该如何做呢?

    这时,我们可以像下面这样,使用apply或call方法指定函数的作用域

    var name = "The Window";
    var object = {
        name: "My Object",
        getNameFunc: function () {
            return function () {
                return this.name;
            }
        }
    };
    var func=object.getNameFunc();
    alert(func.apply(object)); //"My Object"

    通过apply、call,已经可以输出预期的My Object

    但是,每次调用时都需要以func.apply(object)的形式调用,这不是很怪么

    理想的调用方式,当然是在通过某种处理后,之后可以以func()形式调用,像下面这样

    var name = "The Window";
    var object = {
        name: "My Object",
        getNameFunc: function () {
            return function () {
                return this.name;
            }
        }
    };
    var func=object.getNameFunc();
    func=func.bind(object);
    alert(func()); //"My Object"

    ECMAScript 5中的bind

     ECMAScript 5定了了bind方法,这个方法会创建一个函数实例,其this值会被绑定到传给bind函数的值,上面代码给出了bind函数的使用方式,再给一个简单示例。

    window.color="red";
    var o={color:"blue"};
    function sayColor(){
        alert(this.color);
    }
    
    var func=sayColor.bind(o);
    func();//"blue"

    虽然大部分浏览器中已经可以使用ECMAScript 5定义的这个方法,但在少数不支持的浏览器中你还是会遇到兼容性问题,这是如何处理呢?

    通过上面apply、call方法使用示例 ,可以像下面这样提供一个解决方案

    Function.prototype.bind=Function.prototype.bind||
        function(context){
            var self=this;
            return function()
            {
                return self.apply(context,arguments);
            }
        }

    Prototype.js中的bind

    // The .bind method from Prototype.js 
    Function.prototype.bind = function(){ 
      var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift(); 
      return function(){ 
        return fn.apply(object, 
          args.concat(Array.prototype.slice.call(arguments))); 
      }; 
    };

     上述代码中,

    args=Array.prototype.slice.call(arguments)将调用bind函数时参数集合arguments转换为数组array

    object=args.shift()将args数组第一个元素取出作为当前对象

    匿名函数中,调用args.concat(Array.prototype.slice.call(arguments))是为了将调用匿名函数时传入的参数与调用bind时参数合并成一个参数数组

    以一个调用示例来看上述过程

    var obj = { x: 'prop x' };
    //args = Array.prototype.slice.call(arguments)后args = [obj, 12, 23 ]
    //object=args.shift()后,args =[12, 23] ,object =obj

    var boundExample = example.bind(obj, 12, 23);
    boundExample(36, 49); // arguments => 36, 49 ,调用args.concat(Array.prototype.slice.call(arguments))后,arguments that our example() function receives => [12, 23, 36, 49]

    Firefox中的bind

    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");
        }
    
        var aArgs = Array.prototype.slice.call(arguments, 1), 
            fToBind = this, 
            fNOP = function () {},
            fBound = function () {
              return fToBind.apply(this instanceof fNOP && oThis
                                     ? this
                                     : oThis || window,
                                   aArgs.concat(Array.prototype.slice.call(arguments)));
            };
    
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
    
        return fBound;
      };
    }

    Firefox为bind提供了一个兼容实现,主要代码与prototype.js中实现类似,不再逐句解释了

  • 相关阅读:
    【转】K/3 KIS BOS 插件入门
    [转]SQL Server 存储过程中使用 in 动态变量
    [转]Delphi 12种大小写转换的方法
    cxGrid FilterRow 添加左模糊查询,实现 %ABC%
    cxGrid 锁定一行,让该行数据不能编辑
    K/3工业单据K3BillTransfer的属性及使用方法
    VB6上创建金蝶K/3或KIS旗舰版插件
    MySQL UTF8 中文乱码处理
    两种方法自动部署代码:webhooks钩子自动部署代码方法一 及定时任务自动部署二 简介
    Linux查看进程的4种方法
  • 原文地址:https://www.cnblogs.com/GongQi/p/4041460.html
Copyright © 2011-2022 走看看