网站首页 » 前端开发 » JavaScript » JavaScript call() 方法 和 apply() 方法详解
上一篇:
下一篇:

JavaScript call() 方法 和 apply() 方法详解

前言

最近在研究canvas时无意中遇到了call方法,于是乎一场不可避免的为期两天的厮杀就这样开始了。call() 听起来简单,但要是让你在别人的项目中遇到了,我估计你还是不怎么明白,别人为什么这样写。就拿我自己来说,一开始在网上查了了,看到一个解释是说这个方法是用来改变this 的指向的。如果单单看到这个,我想我早就应该明白了,call() 方法说真的其实很简单,但要把它真真正正的搞明白了,还是需要点时间的。下面就给大家分享下我这两天来对这个call() 方法死缠烂打的追求后,终得真爱的经历。

定义

我们先来看看call() 方法的定义 ,在网上找了很多关于call()的说法,但还是比较喜欢这个

1. Both methods allow you to explicitly specify the this value for the invocation, which
means you can invoke any function as a method of any object, even if it is not actually a
method of that object.

两个方法(call() 和 apply() ,在这里我们先不讨论apply())都允许你指定所调用函数的 this 属性指向,这就意味着你可以将任意函数当成对象方法来调用,即使这个方法在那个对象中没有定义。

2. The first argument to both call() and apply() is the object on which the function is
to be invoked; this argument is the invocation context and becomes the value of the this
keyword within the body of the function.

call() 和 apply() 的第一个参数是用于指定调用call()或者 apply() 的函数的运行空间,就各平易近人点就是调用call()或者 apply() 的函数的方法放到哪里执行,第一个参数将会变成 this 的值。

基本用法

示例一

我们来看一个简单的例子

function a(){
this.name = 'my name is A';
this.showMe = function(){
alert(this.name);
}
}

function b(){
this.name = 'my name is B';
this.showMe = function(){
alert(this.name);
}
}
var oA = new a();
var oB = new b();

oA.showMe(); //输出 my name is A
oB.showMe(); //输出 my name is B
oA.showMe.call(oB); //输出 my name is B

上面这个例子中,我们写了两个方法a方法和b方法,然后分别给这两个方法定义一个变量 name 和 一个方法 showMe();

第一个弹出 my name is A 和第二个弹出 my name is B,应该没什么疑问,我们来看看重点。为什么第三个oA.showMe.call(oB); 也是弹出my name is B 呢?

我们来回想下刚才关于call的定义中的一句话:“两个方法(call() 和 apply() ,在这里我们还不讨论apply())都允许你指定所调用函数的 this 属性指向”。看完这句话这后估计你已经有点头绪了吧。oA.showMe.call(oB); 的作用就是把oA 的 this 指向了oB。也就是说当你调oA中的方法showMe() 时由于方法里面是弹出“this.name”,而这个this 我们又用call() 方法把它指向了oB,所以当你这样写(oA.showMe.call(oB);)的时候,当然是输出了b 方法里的 name 值了。

如果你不明白上面所说的 this 指向的话,我们还可以从另一个角度来解释。oA.showMe.call(oB) ,的含义就是把 oA 对象里面的showMe() 方法放到 oB 对象中执行,说白了就相当于给 oB 添加了一个新方法,仅些而已。把 oB 原来的 showMe() 方法去掉(去掉后 oA.showMe.call(oB)  输出的结果还是一样的没变),可能会让你更加容易理解。

示例二

下面我们再来看一个例子,看完后我相信你会对这个this 有更进一步的了解。

function a(){
this.name = 'my name is A';
this.showName = function(){
alert(this.name);
}
this.showDefault = function(){
alert('my name is A');
}
}

function b(){
this.name = 'my name is B';
this.showName = function(){
alert(this.name);
}
this.showDefault = function(){
alert('my name is B');
}
}
var oA = new a();
var oB = new b();

//showName(例子一)
oA.showName(); //输出 my name is A
oB.showName(); //输出 my name is B
oA.showName.call(oB); //输出 my name is B

//showDefault(例子二)
oA.showDefault(); //输出 my name is A
oB.showDefault(); //输出 my name is B
oA.showDefault.call(oB); //输出 my name is A

上面这个例子,只是在第一个例子的基础上多加了一个方法showDefault(),showDefault()里面不出弹出this.name了,而是简单粗暴地把 name的值给弹出来了。第二个例子中弹出的是my name is A 而不是像第一个例子那样 输出 my name is B呢?关键就在于输出的是变量this.name 还是指定的字符串 ‘my name is A’。由于第二个例子中是直接输出字符串的,所以即使当前函数的this指向变了,也不会影响到它,因为它只是一个字符串。而在例子一中情况就不一样了。showName()方法里面输出的是this.name ,而这个this,已经变成了oB,所以例子一和例子二就会得到一个不同的结果了。

网友智慧

下面这个例子,肯定会让你有点意想不到。但它确确实实可以实现。

function show()
{
alert(arguments.slice(1));
}
show(1,2);

如果你直接像上面这样写,那么浏览器就会豪不客气地给你来报个错:

Uncaught TypeError: arguments.slice is not a function

为什么这报错,原因也很简单呀,正如上面这行英文所说的slice 不是一个方法,因为arguments 是一个类数组对象,没有这个方法,但如果想要实现这个,要怎么做呢?没错就是通过call方法来实现。

function show()
{
alert(Array.prototype.slice.call(arguments,1));
}
show(1,2);

这样运行代码后,就会输出一个2了。关于slice的用法可以前往底部的参考资料里点击相关链接。

知识拓展

我们可以通过 call() 方法来模拟 JAVA 语言中的继承。下面我们就来看一个例子。

//方法a
function a(){
this.name = 'my name is A';
this.showMe = function(){
alert(this.name);
}
}
//方法b
function b(){
a.call(this); //这行代码是关键,它实现了传说中的继承
}
//new 一个对象
var oB = new b();
//通过 oB 对象执行方法a里的showMe()函数。
oB.showMe();

运行代码后,浏览器就乖乖地输出了一个 my name is A,而不是给你报错。

参考资料

火狐MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/javascript-function-call-apply-usage/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

评论 END