zoukankan      html  css  js  c++  java
  • call、apply、bind

    1.call

    我们知道,函数可通过调用call方法改变其内部的this指向,默认this指向window或global,下面来一段简单的代码:

    function foo(){
      return this.a;
    }
    var obj = {
      a:1
    };
    console.log(foo.call(obj));// 1

    从结果来看,foo函数中的this绑定了obj,并返回了obj中a属性的值。

    2.apply

    apply与call基本相同,掌握了call也就理解了apply,只不过apply方法的第二个参数是用了一个数组的形式进行传递。

    function sum(b,c){
      return this.a + b + c;
    };
    var obj = {
      a:1
    };
    console.log(sum.apply(obj,[2,3]));// 6

    以上两个是改变函数this指向最常用也是最简单的两个方法。

    现在我想在每两秒输出一次count的值,count值不断递增,通常我们是这样做的

     var obj = {
         count:0,
         timer:function(){
          var _this = this;
          setInterval(function(){
            _this.count++;
            console.log(obj.count);
          },2000);
         }
       };
    obj.timer();// 1, 2, 3,...

    我们用_this引用上下文obj,以用于在setInterval回调函数中能访问到obj,这样写是没有错,但是我们现在有另外一种方式可以实现,es6中提供了箭头函数,使用箭头函数我们无须写function关键字,也不用担心this所在的作用域,请看

    var obj = {
     	count:0,
     	timer:function(){
     	 setInterval(()=>{
     	 	this.count++;
     	 	console.log(obj.count);
     	 },2000);
     	}
    };
    obj.timer();// 1, 2, 3,...

    这样写出了少写一行代码以外,也不用担心对this的困惑了。但是有一点,箭头函数虽好,但它是一个匿名函数,如果我们要在函数内部调用函数本身,该怎么办呢,

    也许你会说,用callee,可是callee已将近被废弃,我们最好还是不要用的好。

    如果你的代码要在函数内部调用自己时,可以给函数起一个名字,也就是用具名函数吧。但如果用具名函数,那this怎么办呢!这可真是一个鱼和熊掌不能兼得的问题呀!

    不过你忘记了,如题,我们还有一个方法没有用到,那就是es5中的bind!这可是个好东西了,有了它,我们的代码可以这样

    var obj = {
     	  count:0,
     	  timer:function(){
     	 	setInterval(function foo(){
     	 		this.count++;
     	 		console.log(obj.count);
     	 	  }.bind(this),2000);
     	  }
     };
     obj.timer();// 1, 2, 3,...

    据说源码比较复杂,下面的代码是MDN提供的bind实现方式

      Function.prototype.bind = function (oThis) {
        if (typeof this !== "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 fBound && oThis
                                     ? this
                                     : oThis,
                                   aArgs.concat(Array.prototype.slice.call(arguments)));
            };
     
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
      };
    

    在Function的原型链上扩展的bind方法,返回一个新的函数。

    this instanceof fBound && oThis? this: oThis;//用于判断函数是否被new调用,如果是this指向new出的实例,不是则使用bind中的第一个参数,为null则忽略
    fNOP.prototype = this.prototype; //用一个空的fn继承this的原型
    fBound.prototype = new fNOP(); //返回的函数与调用bind的函数共享原型链

    我在chrome测试时,发现bind中如果传递null,输入结果不是我期望的,使用chrome默认的bind则不会,这说明上面贴出的代码与源码实现还是有很大差异的,如果要针对IE可再加上if(!Function.prototype.bind)判断,在IE兼容模式下7、8、11兼容性视图会输入undifined

    下面是我的测试代码:

    function test(something,a,b){
    	this.a = something+a+b;
    };
    var obj = {};
    var newFn = test.bind(obj,1,2);
    var res= new newFn(10);
    console.log(res.a);// 13
    而使用
    var newFn = test.bind(null,1,2);// undefined
    
    
  • 相关阅读:
    Sonar+IDEA + Maven的集成
    My97DatePicker IE9中,显示全部为1
    Datatable+jeditable+Java 结合使用实现表格的单行刷新
    Datatables表格控件的使用相关网站及遇到的问题
    xss 小练习
    主页面布局 随浏览器大小变化而变化
    使用angular中自定义的directive实现删除确认框
    使用css和js完成模态弹窗功能
    ckplayer插件的使用
    使用JQuery进行表格分页查询
  • 原文地址:https://www.cnblogs.com/dzyBlog/p/4901615.html
Copyright © 2011-2022 走看看