JavaScript中的call()和apply()

82 篇文章 7 订阅

JavaScript中的call()和apply()

函数的角色:普通函数,对象,构造器`
先举一个例子

<script>
	function f1(){
		console.log(this);
	}
	f1();
</script>

现在要问大家,调用了函数 f1 之后的输出结果是什么?
答案是:window


顺带提一下JavaScript执行模式,对你的理解可能会加深一步。

JavaScript执行模式有两种:正常模式,严格模式。

我们平常使用都是正常模式,但在严格模式下,我们执行上面的代码就会出现问题!

严格模式的使用:

<script>
	"use strict";//进入严格模式
	function f1(){
		console.log(this);
	}
	f1();
</script>

大家会发现输出的结果是undefined,此时我们改一下代码,把 f1函数 的调用改成window.f1();就会发现正常输出了结果,打印出了window对象。


进入重点

先大概理解一下这三点:
  1. call和apply作用其实是一样的。
  2. call和apply的不同在于传值的不同。
  3. call把参数作为离散的值来传,apply则必须把参数放在一个数组里来传。

接下来我们通过call和apply来调用f1函数。【注意:这里使用call和apply时,不是在严格模式下,严格模式下使用,输出的undefined】

<script>
	function f1(){
		console.log(this);
	}
	f1.call();
	f1.apply();
	
	// 两个输出的都是window对象
</script>

上面的f1函数是无参的,那如果有参数呢?【这点是有变化的,需要注意。】
通过call和apply来调用有参数的f1函数?
用例子说话 (为了区别改一下函数名字,改为f2函数):

<script>
	function f2(a,b){
		console.log((a + b) + " : " + this);
	}
	f2(1,2);
	f2.call(1,2);
	f2.call(null,1,2);
	f2.apply(null,[1,2]);
	f2.apply(obj,[1,2]);
</script>

输出结果:

3 : [object Window]
NaN : 1
3 : [object Window]
3 : [object Window]
ReferenceError: obj is not defined

到现在,如果你运行了上面的代码,你可能会有疑问,不过不用急,先看下面的问题。

问题1:

f2.call(null,1,2);这里面的null起了什么作用。

答案1:

null值,代表的就是指向当前的函数调用者,f2函数的调用者就是window(在console的输出中有显示),函数被window调用,显然合情合理。

问题2:

为什么在apply中传入了obj,却显示obj is not defined?

答案2:

由 答案1 我们可以推出来一点,第一参数传过去之后肯定指向了函数的调用者,那么问题来了,我们传过去的obj是调用者吗?我们甚至没有定义它。
于此同理,我们看到,第二个f2.call(1,2)的输出显示的函数调用者为 1 ,【输出的this是1】

看了这个例子,想必你已经理解了重点开头的三条的含义。

总结一下:call和apply都是Function对象的原型上定义的方法,它的作用是调用当前函数,并且可以通过call和apply来改变当前函数中的this的指向。
call的签名:call ( thisArg, arg1, arg2…);
apply的签名:apply ( thisArg, [item1, item2, item3…] );

  1. 当函数中没有形参,用这二者调用时也可一个参数都不给,包括thisArg,默认this指向window。
  2. 如果必须传参数,当通过call和apply调用时,参数必须在对象的后边,且第一个参数必须是对象,至少要给null(指向window)

注:通过thisArg传另一个对象,来改变this关键字的当前指向。(以前this指向调用者,现在指向指定的对象)。


如果你还是感觉模糊的话,看完下面的这个例子,想必你就会彻底明白。
这是一个对call和apply调用中this指向进行解释的代码截图
输出结果:

per.sayHi();				-->		你好:东哥,28
per.sayHi.call(null);		-->		你好:,undefined
per.sayHi.call(per);		-->		你好:东哥,28
per.sayHi.call(stu);		-->		你好:黎明,18
per.sayHi.apply(stu);		-->		你好:黎明,18

我只说一点,想必大家就明白了,在这个例子中,我们改变了this的指向,原本指向Person,而per.sayHi.call(stu);则改变了这一指向。所以Student才可调用sayHi()方法


说了这么多,call和apply有什么用呢?

call和apply的作用有二:一为方法借用,二用在JavaScript继承

在这里我们只讲第一个方法借用

案例1:求一个数组的最大值

<script>
	var max = Math.max(1,2,33,55,11);
	console.log(max);
<script>

这是一个简单的求最大值的函数,但是如果我们传入的不是数,而是数组呢?
你肯定会脱口而出:不能传入数组,会报错。
那有没有方法可以传入呢?答案是有,用我们的apply。

<script>
	//修改代码
	var ary = [1,3,44,5,77,6];
	var m = Math.max.apply(null,ary);
	console.log(m);
<script>

在求最大值时,max只接受离散的值,不接受数组,如果我们要传数组,就可以使用apply()传入数组对象。

案例2:把伪数组转换为普通数组

<script>
	var wsz = {0:'james',1:'zs',2:'zsf',length:3};//伪数组
	var realAry = [ ].slice.call(wsz);
	console.log(realAry);
	var realAry = [ ].slice.apply(wsz);
	console.log(realAry);
</script>
注:
realAry = [ ].slice.call(wsz); <=> realAry = Array.prototype.slice.call(wsz);
  1. 简单解释一下伪数组:
    伪数组最后有一个length,此length非这个数组的属性,而是这个数组的一个key,且值必须等于前边所有key的和,伪数组的遍历基本和普通数组相同。
  2. 普通数组对象里,length是数组的一个属性。

而上面的代码就借助我们的apply,把一个伪数组转换成了一个普通数组

-----------------------讲完了,溜了溜了??????----------------------

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值