zoukankan      html  css  js  c++  java
  • this、call和apply

    this

    和其他语言不同,JavaScript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

    this的指向

    除去不常用的witheval,this的指向大致可分为以下四种:

    • 作为对象的方法调用

    • 作为普通函数调用

    • 构造器调用

    • Function.prototype.call或Function.prototype.apply调用

    作为对象的方法调用

    当函数作为对象的方法被调用时,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

    call和apply作用一模一样,区别在于传入参数的形式不同。apply接受两个参数,第一个参数指定了函数体内this对象的指向,第二个参数第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组。

    JavaScript的参数在内部就是用一个数组来表示的,从这个意义上来说,apply比call的使用率更高。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

  • 相关阅读:
    打开安装 好的Microsoft Dynamics CRM 4.0 报错误为 Caller does not have enough privilege to set CallerOriginToken to the specified value 的解决办法
    基于 Windows Server 2008 的计算机对 Microsoft Dynamics CRM 4.0 的支持
    Microsoft Dynamics CRM 4.0 如何添加自定义按钮
    Microsoft Dynamics CRM 4.0 Plugin 取值,赋值,查询
    C# 中的 enum(枚举) 类型使用例子
    vue事件的绑定
    表单验证2
    node中模块
    node模块的引入
    node中的读文件
  • 原文地址:https://www.cnblogs.com/depsi/p/5081365.html
Copyright © 2011-2022 走看看