call()&apply()
call
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
apply
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
call和apply可以用来重新定义函数的执行环境,也就是this的指向; call 和 apply 都是为了改变某个函数运行时的
context 即上下文而存在的 换句话说,就是为了改变函数体内部 this 的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
我们可以将call()和apply()看做是某个对象的方法,通过调用方法的形式来间接调用函数。这么说有些抽象
call和apply的区别并不大,了解了一个,另一个自然就懂了,所以我在这里不重点讨论他们的区别,本篇文章的讨论,以call为主
一个简单的栗子
当call()没有传递参数时,默认参数是window
this的默认也是window
所以在上面的例子中以下三个等效
我们重点看下这个
obj使handleName的this指向发生了变化,从原来的window变到了obj
我们可以在函数handleName打印this,已观察this的变化
看下输出
上面的例子中,函数handleName有一个方法call,call不是函数handleName通过原型继承得到的,
输出
输出里不存在call方法
这是一个关于call最简单的一个栗子,如果理解了,我们继续向下看
调用了Hero1下doSth的call方法,并传入Hero2,改变了doSth下this的指向,最终导致doSth下this.name由“欧阳锋”变成了“洪七公”
我们稍微扩展一下,上面的代码做一下改动
梳理一下:
Hero1和Hero2函数名大写了,没错这两个是自定义的构造函数,
通过Hero1实例化一个函数ofy
通过Hero2实例化一个函数hqg
调用函数ofy的doSth方法,
我们打印一下ofy函数
所以oyf.doSth(‘九阴真经’)可以打印“欧阳锋学习九阴真经”
看这个
doSth下this的指向变为了hqg,所以this.name是“洪七公”,doSth中的形参就是“降龙十八掌”,所以
最终打印输出=>洪七公学习降龙十八掌
一个call的经典案例
我们先看下输出
对以上的输出和结果感到意外吗?
分析一下
首先是调用的add的call方法,并传入了第一个参数sub,
执行的还是add方法,但是add方法内this的指向变了,this指向了sub,所以会出现上面的输出
为什么结果是4?
调用的是add方法,add方法中的this指向的是sub(又说了一遍),然而add.call,还传入了第二个和第三个参数(3,1)
他们分别是add方法中的a和b,a+b就是3+1=>4
call 和 apply 最大的好处方便我们解耦,对象不需要和方法有任何的耦合性,能使我们写出更好的面相对象程序。
大家如果看一些 js 框架底层的话会看到好多地方都有大量用到。