详解this、call和apply

this

和其他言语差别,JavaScript的this老是指向一个对象,而详细指向哪一个对象是在运行时基于函数的实行环境动态绑定的,而非函数被声明时的环境。

this的指向

撤除不常常运用的witheval,this的指向大抵可分为以下四种:

  • 作为对象的要领挪用

  • 作为一般函数挪用

  • 组织器挪用

  • Function.prototype.callFunction.prototype.apply挪用

<!–more–>

作为对象的要领挪用

当函数作为对象的要领被挪用时,this指向该对象。

var obj={
  a:1,
  getA:function(){
    alert(this===obj);//true
    alert(this.a);//1
  }
};

obj.getA();

作为一般函数挪用

当函数不作为对象的属性被挪用时,也就是一般函数体式格局,此时this老是指向全局对象。在浏览器中,这个全局对象是window

window.name='globalName';

var getName1=function(){
    return this.name;
};

var myObject={
    name:'sven',
    getName:function(){
        return this.name;
    }
};

var getName=myObject.getName;

alert(getName1());//globalName
alert(getName());//globalName

组织器挪用

当用new运算符挪用函数时,该函数总会返回一个对象,通常情况下,组织器里的this就指向返回的这个对象。

var MyClass=function(){
    this.name='sven';
};

var obj=new MyClass();
alert(obj.name);//sven

然则假如组织器显式地返回了一个object范例的对象,那末此次运算结果最终会返回这个对象,而不是我们之前期待的this:

var MyClass=function(){
    this.name='sven';
    return{
        name:'anne';
    }
};

var obj=new MyClass();
alert(obj.name);//anne

假如组织器不显式地返回任何数据,或许是返回一个非对象范例的数据,就不会形成上述问题:

var MyClass=function(){
    this.name='sven';
    return 'anne';
};

var obj=new MyClass();
alert(obj.name);//sven

call和apply挪用

call和apply能够动态的地转变传入函数的this:

var obj1={
    name:'sven',
    getName:function(){
        return this.name;
    }
};

var obj2={
    name:'anne'
};

console.log(obj1.getName());
console.log(obj1.getName.call(obj2));

call和apply

callapply作用如出一辙,区分在于传入参数的情势差别。apply接收两个参数,第一个参数指定了函数体内this对象的指向,第二个参数第二个参数为一个带下标的鸠合,这个鸠合能够为数组,也能够为类数组。

JavaScript的参数在内部就是用一个数组来示意的,从这个意义上来讲,applycall的运用率更高。call是包装在apply上的一颗语法糖,假如我们明白晓得函数接收多少个参数,而且想一览无余地表达形参和实参的对应关联,那末也能够用call来传送参数。

当运用call或许apply时,假如我们传入的第一个参数是null,函数体内的this会指向默许的宿主对象,在浏览器中就是window,但假如是在严厉形式下,函数体内的this照样为null

有时刻我们运用call或许apply的目标并不在于指定this的指向,而是尚有用处,比方借用其他对象的要领,那末我们就能够传入null来替代某个详细的对象。

call和apply的用处

转变this的指向

Function.prototype.bind

        Function.prototype.bind=function() {
        var self=this,
            context=[].shift.call(arguments),//须要绑定的this上下文
            args=[].slice.call(arguments);//盈余的参数转成数组
        return function(){
            return self.apply(context,[].concat.call(args,[].slice.call(arguments)));//实行新的函数体的时刻,会把之前传入的context看成新函数体内的this,而且组合两次离别传入的参数,作为新函数的参数
        }
    };

    var obj={
        name:'sven'
    };

    var func=function(a,b,c,d){
        alert(this.name);
        alert([a,b,c,d]);
    }.bind(obj,1,2);

    func(3,4);

运用其他对象的要领

第一种场景是借用组织函数,能够完成一些相似继续的结果:

var A=function(name){
    this.name=name;
};

var B=function(){
    A.apply(this,arguments);
};

B.prototype.getName=function(){
    return this.name;
};

var b=new B('sven');
console.log(b.getName());

第二种场景:函数的参数列表arguments是一个类数组对象,虽然它也有下标,但她并不是真正的数组,所以不能举行排序操纵或许往鸠合里增加一个新的元素。这类情况下我们常常会借用Array.prototype对象上的要领。比方想往arguments里插进去一个元素,通常会借用Array.prototype.push

(function(){Array.prototype.push.call(arguments,3)})(1,2);

在操纵arguments时,我们常常异常频仍地找Array.prototype借用要领。

  • 转化为数组:Array.prototype.slice

  • 截去头元素:Array.prototype.shift

    原文作者:司想君
    原文地址: https://segmentfault.com/a/1190000004553064
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞