zoukankan      html  css  js  c++  java
  • [JavaScript] this、call和apply详解

        在JavaScript编程中,理解this、call和apply是道槛,如果能正确的理解它们的本质及其应用。那么在以后的JavaScript中会得心应手。

    this

        跟别的语言大相径庭的是,JavaScript的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

    this 的指向

        具体到实际应用中,this的指向可以分为以下4中。

    • 作为对象的方法调用

    当函数作为对象的方法被调用时,this指向该对象:

    var obj={
    
        num:1,
    
        getNum:function(){
    
            alert( this === obj); //输出:true
    
            alert( this.a ); //输出:1
    
        }
    
    };
    
    
    
    obj.getNum();
    • 作为普通函数调用

    当函数不作为对象的属性被调用时,也就是我们常说的普通函数调用方式,此时的this总是指向全局对象。在浏览器的JavaScript里,这个全局对象是window对象。

    window.name = 'globalName';
    
    
    
    var myObj={
    
        name:'khadron',
    
        getName:function(){
    
            return this.name;
    
        }
    
    };
    
    
    
    var getName = myObj.getName;
    
    
    
    console.log( getName() ); //输出:globalName

    在ECMAScript5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined:

    function func(){
    
        'use strict'
    
        alert( this ); //输出:undefined
    
    };
    
    
    
    func();
    • 构造器调用

    JavaScript中没有类,但是可以从构造器中创建对象,同时也提供了new运算符,使得构造器看起来更像是一个类。

    出了宿主提供的一些内置函数,大部分JavaScript函数都可以当作构造器使用。构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用new运算符调用函数时,该函数总返回一个对象,通常情况下,构造器里的this就是指向返回的这个对象:

    var MyClass=function(){
    
        this.name = 'khadron';
    
    };
    
    
    
    var obj = MyClass();
    
    alert( obj.name ); //输出:khadron

    但用new调用构造器=时,还需要注意有一个问题,如果构造函数显示地返回一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的this:

    var MyClass = function(){
    
        this.name = 'khadron';
    
        return {    //显示地返回一个对象
    
            name: 'q'
    
        };
    
    };
    
    
    
    var obj=new MyClass();
    
    alert( obj.name ); //输出: q

    如果构造器不显示地返回任何数据,或者返回一个非对象类型的数据,就不会造成上述问题:

    var MyClass = function(){
    
        this.name='khadron';
    
        return 'q'; //返回string类型
    
    };
    
    
    
    var obj = new MyClass();
    
    alert( obj.name ); //输出:khadron
    • Function.prototype.call或Function.prototype.apply调用

    跟普通函数调用相比,用Function.prototype.call或Function.prototype.apply可以动态地改变传入函数的this:

    var obj1={
    
        name: 'khadron',
    
        getName:function(){
    
            return this.name;
    
        }
    
    };
    
    
    
    var obj2={
    
        name:'q'
    
    };
    
    
    
    console.log( obj1.getName() ); //输出:khadron
    
    console.log( obje1.getName.call( obj2 )); //输出:q

    丢失 this 问题

    我们先看下面的代码:

    var obj={
    
        name:'khadron',
    
        getName:function(){
    
            return this.name;
    
        }
    
    }
    
    console.log(obj.getName()); //输出:khadron
    
    
    
    var getNameFunc=obj.getName();
    
    console.log(getNameFunc()); //输出:undefined

    当调用obj.getName时,getName方法是作为obj对象的属性被调用的,此时的this指向obj对象,所以obj.getName()输出’khadron’。

    当另外一个变量getNameFunc来引用obj.getName,并且调用getNameFunc时,此时是普通函数调用方式,this指向是全局变量window,所以程序执行的结果是undefined。

    call 和 apply

        ECAMScript3给Function的原型定义了两个方法,他们是Function.prototype.call和Function。prototype.apply。在实际开发中,特别是在一些函数式风格的代码编写中,call 和 apply方法尤为有用。

    call 和 apply 的区别

        call 和 apply 的作用一模一样,区别仅在于传入参数形式的不同。

        apply接受两个参数,第一个参数制定了函数体内this对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数:

    var func = function(a,b,c){
    
        alert( [a,b,c] ); // 输出:[1,2,3]
    
    };
    
    
    
    func.apply( null,[]1,2,3 );

        在上段代码中,参数1,2,3被放在数组中一起传入func函数,它们分别对相应func参数列表中的a、b、c。

        call传入的参数数量不固定,跟apply相同的是,第一个参数也是代表函数体内的this指向,从第二个参数开始往后,每个参数被一次传入函数:

    var func = function(a,b,c){
    
        alert( [a,b,c] ); //输出:[1,2,3]
    
    };
    
    
    
    func.call( null,1,2,3 );
    

        当调用一个函数时,JavaScript的解释器并不会计较形参和实参的数量、类型以及顺序上的区别,JavaScript的参数在内部就是一个数组来表示的。

        call是包装在apply上面的一课语法糖,如果我们明确地知道函数接受多少个参数,而且想一目了然地表达形参和实参的对应关系,那么也可以用call来传递参数。

    当调用call或者apply的时候,如果我们传入的第一个参数为null,那么函数体内的this会指向默认的宿主对象,在浏览器中则是window:

    var func = function(a,b,c){
    
        alert( this === window ); //输出true
    
    };
    
    
    
    func.apply( null,[1,2,3] );
    

        但如果是在严格模式下,函数体内的this指向为null

    var func = function(a,b,c){
    
        'use strict'
    
        alert( this === null ); //输出true
    
    }

        有时候我们使用call 或者 apply 的目的不在于指定this指向,而是另有用途,比如借用其他对象的方法,我们可以传入null来代替某个具体的对象:

    Math.max.apply( null, [1,2,4,5,3]); //输出5
  • 相关阅读:
    AS中Loading 的加载
    视频类的相关加载
    2012、10、05 听课笔记
    2012、09、27 听课笔记
    小程序的编写—2
    小程序的编写—1
    2012、9、28 听课笔记
    GCD
    CFHTTP
    获取当前时间字符串
  • 原文地址:https://www.cnblogs.com/Khadron/p/5862208.html
Copyright © 2011-2022 走看看