[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
时间: 2024-10-18 07:29:53

[JavaScript] this、call和apply详解的相关文章

JavaScript 身份证号有效验证详解及实例代码

JavaScript 身份证号有效验证详解及实例代码 这篇文章主要介绍了JavaScript 身份证号有效验证详解及实例代码的相关资料,需要的朋友可以参考下 JavaScript验证身份证号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <%@ page language="jav

[转] 从此不再惧怕URI编码:JavaScript及C# URI编码详解

混乱的URI编码 JavaScript中编码有三种方法:escape.encodeURI.encodeURIComponent C#中编码主要方法:HttpUtility.UrlEncode.Server.UrlEncode.Uri.EscapeUriString.Uri.EscapeDataString JavaScript中的还好,只提供了三个,C#中主要用的就有这么多,还没有列出其他编码(HTML),一多就弄不明白,弄不明白就心生恐惧,心生恐惧就变得苦逼,本文就向大家详细解释在JavaSc

javascript中=、==、===区别详解

javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题,却有着大影响,所以决定深入分析下.1.= 赋值运算符 //例: var n=1; console.log(n);//1 n=n+1; console.log(n);//2 2.== 值比较运算符 值比较运算符在表达式两边的数据类型不一致时,会隐式转换为相同数据类型,然后对值进行比较. //例: var a=

javascript常用经典算法实例详解

javascript常用经典算法实例详解 这篇文章主要介绍了javascript常用算法,结合实例形式较为详细的分析总结了JavaScript中常见的各种排序算法以及堆.栈.链表等数据结构的相关实现与使用技巧,需要的朋友可以参考下 本文实例讲述了javascript常用算法.分享给大家供大家参考,具体如下: 入门级算法-线性查找-时间复杂度O(n)--相当于算法界中的HelloWorld ? 1 2 3 4 5 6 7 8 9 10 //线性搜索(入门HelloWorld) //A为数组,x为要

Javascript 调试利器 Firebug使用详解

Javascript 调试利器 Firebug使用详解 有时候,为了更清楚方便的查看输出信息,我们可能需要将一些调试信息进行分组输出,那么可以使用console.group来对信息进行分组,在组信息输出完成后用console.groupEnd结束分组. 我们测试一下把刚才的4个输出作为一个分组输出,修改代码为: 复制代码 代码如下: console.group('开始分组:'); console.debug('This is console.debug!'); console.info('Thi

javascript实现的运动框架详解

javascript实现的运动框架详解: 所谓的运动框架简单的说就是让元素的某一个属性值能够有渐进性的变化.运动框架的使用在实际功能中有大量的应用,最常见的比如客服系统,当拖动滚动条的时候,一般客服系统能够以弹性方式跟随,下面就简单介绍一下如何实现此效果: 代码实例如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author"

Javascript 严格模式(strict mode)详解

Javascript 严格模式详解 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode).顾名思义,这种模式使得Javascript在更严格的条件下运行. 设立"严格模式"的目的,主要有以下几个: - 消除Javascript语法的一些不合理.不严谨之处,减少一些怪异行为; - 消除代码运行的一些不安全之处,保证代码运行的安全: - 提高编译器效率,增加运行速度: - 为未来新版本的Javascript做好

常用 JavaScript 小技巧及原理详解

善于利用JS中的小知识的利用,可以很简洁的编写代码 1. 使用!!模拟Boolean()函数 原理:逻辑非操作一个数据对象时,会先将数据对象转换为布尔值,然后取反,两个!!重复取反,就实现了转换为布尔值的效果. 2. 使用一元加(+)模拟Number()函数 原理:对非数值类型的数据使用一元加(+),会起到与Number()函数相同的效果. null转换为0 undefined转换为NaN false转换为0,true转换为1 对于字符串: 空字串转换为0 含有数字或者浮点数或者十六进制格式的数

JavaScript基础与案例开发详解pdf

下载地址:网盘下载 <Java Script基础与案例开发详解>根据JavaScript在各种类型的应用开发中(如B2B.B2C.C2C)的使用情况,有针对性地安排了丰富的案例,从基本的表格操作.表单操作,到构建浏览器端的富文本编辑器,再到实现像Windows那样的复杂UI的操作,每一个案例都能让读者从中学习到主流的JavaScript开发技巧. 针对初学者,<Java Script基础与案例开发详解>也讲解了JavaScript的基本语法,所以即使没有任何编程语言基础,读者也能够