编程技术文章分享与教程

网站首页 > 技术文章 正文

理解apply()和call()方法

hmc789 2024-11-21 15:52:54 技术文章 2 ℃

apply和call都属于函数对象的方法,因此所有函数都可以用这两个方法。

apply方法用于解决这样一个问题:一个对象如何调用不属于它的方法?

例如:

var o = {

a:1,

b:2

}

function add(i, j){

console.log(i + j);

}

对象o如何调用add方法?最简单的思路是直接将add方法添加到对象o中。

o.plus = add;

这样就可以调用了

o.plus(o.a, o.b); // 3

这么做的问题是对象o被修改了,不好。那么如何在不修改对象o的前提下实现此目的呢?答案就是使用apply。

add.apply(o, [o.a, o.b]); // 3

apply的作用可以理解为:将某个方法应用到某个对象上。

所有方法(函数)的调用一定是作为某个对象的方法进行调用的,apply就是用于指定调用函数的对象。

apply接收两个实参,第一个就是指定的对象,或者是this。this表示apply执行时的作用域环境,如果是在全局环境下调用apply,那么this指全局对象,如果是在局部环境下(也就是某个函数里)调用,那么this指该局部环境(也就是某个函数的作用域)。如果传入的参数是null或undefined,会被自动转换为全局对象。

假设上述代码都在全局环境下,那么下列三种写法是一样的:

add.apply(o, [o.a,o.b]); // 3, 由对象o调用

add.apply(this, [o.a,o.b]); // 3, 在全局作用域下调用(或者说在Global/window对象上调用)

add.apply(null, [o.a,o.b]); // 3, 在全局作用域下调用(或者说在Global/window对象上调用)

但是!在ES5严格模式下,无论第一个参数传入的是什么,都会被统一的转换为this,即第一个参数只能是this。

第二个参数是调用函数时所传入的参数,必须是一个数组,或者直接传入arguments对象。可选填。

call方法的作用和apply是完全一样的,其区别仅在于call的参数写法不同,除第一个参数和apply是一样的,而其余参数需要逐一列举出来。

add.call(o, o.a, o.b); // 3

有了apply和call,我们可以将函数指派给任何对象,或者说任何对象都能够调用任何函数(道理上没错,至于能不能起作用,完全取决于实际代码)。

简单总结:

foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments) == this.foo(arg1, arg2, arg3)

来看一个实用案例:

求数组中的最大/最小值

var arr = [1, 2, 3]; // 数组对象本身没有求最大/最小值的方法,因此借用Math对象的方法

var maxNum = Math.max.apply(this,arr); // 只能用apply,不能用call

console.log(maxNum); // 3

apply和call还可以实现对象之间的继承。显然,对象应该由构造函数的形式创建,才能运用这两个方法。

这里借用了阮一峰老师的例子。

// 一个"动物"对象

function Animal{

this.species = "动物";

}

// 一个"猫"对象 function Cat(name, color){

this.name = name;

this.color = color;

}

// 在"猫"的构造函数中绑定"动物"

function Cat(name, color){

Animal.apply(this); // Animal中的this现在指向Cat

// 构造一个实例,看看"猫"是否继承了"动物"的属性

var cat = new Cat("大毛", "黄色");

alert(cat.species); // 动物,说明"猫"继承了"动物"的属性

这些简单例子仅能帮助理解apply和call的基本用法,要想熟练使用,发挥其真正的威力,还得多看高手源码、多实践。

标签列表
最新留言