最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • (JS)this关键字详解(二)

    正文概述 掘金(前端五月天)   2020-11-28   434

    绑定this的方法

    call

    Function.prototype.call()

    单个参数

    函数实例的call方法可以改变函数体内this的指向。

    var x="in window";
    var obj={
        x:"in obj",
        fun:function(){
        console.log(this.x);
    }
    };
    
    obj.fun(); //"in obj"
    obj.fun.call(window);//"in window"
    

    上面代码表示,函数call接受指定参数作为函数内this的执行环境(指向)。

    call接受的参数应该是一个对象,如果该参数是原始类型的值,那么这个原始值会自动转化为对应的包装对象,再传入call方法。

    var f = function () {
      return this;
    };
    
    f.call(5)
    // Number {[[PrimitiveValue]]: 5}
    

    上面代码中,call的参数为5,不是对象,会被自动转成包装对象(Number的实例),绑定f内部的this

    多个参数

    call方法可以接受多个参数

    func.call(thisValue, arg1, arg2, ...)
    

    call方法第一个参数为this要指向的对象,后面的参数则是函数执行时所需要的实参。

    function add(a, b) {
      return a + b;
    }
    
    add.call(this, 1, 2) // 3
    

    上述代码表示,call方法指定函数addthis的执行环境,并且传入参数1,2,返回结果3.

    应用

    call方法的一个应用是调用对象的原生方法

    下面代码是利用call解决函数重名问题的一个例子。

    var obj = {};
    obj.hasOwnProperty('toString') // false
    
    // 覆盖掉继承的 hasOwnProperty 方法
    obj.hasOwnProperty = function () {
      return true;
    };
    obj.hasOwnProperty('toString') // true
    
    Object.prototype.hasOwnProperty.call(obj, 'toString') // false
    

    开始时,对象objhasOwnProperty方法是继承自Object对象的,当被不小心覆盖时,会导致不必要的错误。所以可以使用call,将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。

    apply

    Function.prototype.apply() apply方法与call方法作用基本相似,唯一的区别就是,它以数组的形式接收函数执行时的参数

    func.apply(thisValue, [arg1, arg2, ...])
    

    apply方法的第一个参数也是this所要指向的那个对象,如果设为nullundefined,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。

    应用

    (1) 找出数组最大元素

    结合apply方法和Math.max方法可以返回数组中的最大元素

    var arr=[12,421,43,123,42];
    Math.max.apply(null,arr); //421
    
    (2) 将数组的空元素变为undefined

    通过apply方法,利用Array构造函数将数组的空元素变成undefined

    var arr=[12,,43];
    Array.apply(null,arr);[12,undefined,43];
    

    空元素与undefined的区别在于,数组的forEach方法会跳过空元素,而不会跳过undefined

    var arr=[12,,13];
    arr.forEach(item=>console.log(item));//12  13
    
    Array.apply(null,arr).forEach(item=>console.log(item))
    //12 undefined 13
    
    (3) 转换类似数组的对象

    另外,利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。

    Array.prototype.slice.apply({0: 1, length: 1}) // [1]
    Array.prototype.slice.apply({0: 1}) // []
    Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
    Array.prototype.slice.apply({length: 1}) // [undefined]
    

    上面代码的apply方法的参数都是对象,但是返回结果都是数组,这就起到了将对象转成数组的目的。从上面代码可以看到,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键

    (4)绑定回调函数的对象
    var o = new Object();
    
    o.f = function () {
      console.log(this === o);
    }
    
    var f = function (){
      o.f.apply(o);
      // 或者 o.f.call(o);
    };
    
    // jQuery 的写法
    $('#button').on('click', f);
    

    上面代码中,页面中有一个按钮,点击以后,控制台将会显示true。使用了apply()方法(或者call()方法)不仅绑定函数执行时所在的对象,还会立即执行函数,因此不得不把绑定语句写在一个函数体内。更简洁的写法是采用下面介绍的bind()方法。

    bind

    Function.prototype.bind() bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。

    var d=new Date();
    d.getTime();  1606483094579
    var print=d.getTime;
    print();//Uncaught TypeError: this is not a Date object.
    

    使用bind可以将d.getTime方法里的this绑定到某个对象上

    var d=new Date();
    d.getTime();  1606483094579
    var print=d.getTime.bind(d);
    print(); //1606483094579
    

    上面代码中,bind()方法将getTime()方法内部的this绑定到d对象,这时就可以安全地将这个方法赋值给其他变量了。

    使用其他对象的方法

    var obj1={
        name:"obj1",
        show:function(){
            console.log(this.name);
        }
    };
    var obj2={
        name:"obj2"
    };
    
    obj1.show(); //obj1
    var showobj=obj1.show.bind(obj2);
    show(); //obj2
    

    注意

    (1)每次都返回一个新函数

    bind()方法每次运行,都会产生一个新函数,所以在写监听事件时,不能写成以下形式。

    element.addEventListener('click', o.m.bind(o));
    

    上面代码表示,该click事件绑定bind()方法生成的一个匿名函数,,这样会导致无法取消绑定(removeEventListener)。

    可参考写成如下形式

    var listener = o.m.bind(o);
    element.addEventListener('click', listener);
    //  ...
    element.removeEventListener('click', listener);
    

    给函数一个名字,就能解决这个问题。

    (2)结合call()方法

    利用bind()可以改写一些JavaScript原生方法的使用形式。

    var arr=[1,2,3,4,5];
    arr.slice(0,3); //[1,2,3];
    //等同于
    Array.prototype.slice.call(arr,0,3);
    

    通过改写后

    var slice=Function.prototype.call.bind(Array.prototype.slice);
    slice(arr,0,3); //[1,2,3]
    

    上面代码的含义就是,将Array.prototype.slice变成Function.prototype.call方法所在的对象,调用时就变成了Array.prototype.slice.callpoppush的改写

    var arr=[1,2,3,4];
        var pop=Function.prototype.call.bind(Array.prototype.pop);
        var push=Function.prototype.call.bind(Array.prototype.push);
        pop(arr); //[1,2,3]
        push(arr,9,8,7); //[1,2,3,9,8,7]
    
    改写bind使用形式

    如果再进一步,将Function.prototype.call方法绑定到Function.prototype.bind对象,就意味着bind的调用形式也可以被改写。

    function f() {
      console.log(this.v);
    }
    
    var o = { v: 123 };
    var bind = Function.prototype.call.bind(Function.prototype.bind);
    bind(f, o)() // 123
    

    上面代码的含义就是,将Function.prototype.bind方法绑定在Function.prototype.call上面,所以bind方法就可以直接使用,不需要在函数实例上使用。

    上一篇 this关键字详解一

    最后,希望能和大家一起进步!

    起源地下载网 » (JS)this关键字详解(二)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元