关于 call 和 apply, 以前也思考良久, 很多时候都以为记住了, 但是, 我太难了. 今天我特地写下笔记, 希望可以完全掌握这个东西, 也希望可以帮助到任何想对学习这个东西的同学.
一. apply 函数定义与理解, 先从 apply 函数出发
在 MDN 上, apply 的定义是:
"apply()方法调用一个具有给定 this 值的函数, 以及作为一个数组 (或类似数组对象) 提供的参数."
我的理解是: apply 的前面有个含有 this 的对象, 设为 A,apply()的参数里, 也含有一个含有 this 的对象设为 B. 则 A.apply(B), 表示 A 代码执行调用了 B,B 代码照常执行, 执行后的结果作为 apply 的参数, 然后 apply 把这个结果所指代表示的 this 替换掉 A 本身的 this, 接着执行 A 代码.
比如:
- var aa = {
- _name:111,
- _age:222,
- _f:function(){
- console.log(this)
- console.log(this._name)
- }
- }
- var cc = {
- _name:0,
- _age:0,
- _f:function(){
- console.log(this)
- console.log(this._name)
- }
- }
- cc._f.apply(aa)// 此时 aa 表示的 this 就是 aa 本身
- cc._f.apply(aa._f)// 此时 aa._f 表示的 this 就是 aa._f 本身
- /**
- * 此时 aa._f()表示的 this, 就是执行后的结果本身. aa._f()执行后, 没有返回值, 所以应该是 undefined, 而 undefined 作为 call 和 apply 的参数时, call 和 apply 前面的方法 cc._f 的 this 会替换成全局对象 Windows.
- * 参考 MDN:https://developer.mozilla.org/zh-CN/docs/web/JavaScript/Reference/Global_Objects/Function/apply 的参数说明
- */
- cc._f.apply(aa._f())
执行结果:
1. 参数为 aa
这两行的打印的都是来自 cc._f 方法内的那两句 console .aa 的时候算是初始化, 里面的 aa._f 方法没有执行.
2. 参数为 aa.f
这两行的打印的都是来自 cc._f 方法内的那两句 console .aa.f 的时候应该也算是初始化, 或者是整个函数当参数传但是不执行这个参数, 即 aa._f 方法没有执行.
3. 参数为 aa.f()
这四行的打印, 前面两行来自 aa._f() 方法执行打印的; 后面两行是来自 cc._f()方法打印的.
后两行解析: aa._f()执行后, 没有返回值, 所以是 undefined, 在 apply 执行解析后, cc._f()的 this 变成的 Windows, 所以打印了 Windows.Windows 里面没有_name 这个属性, 所以 undefined.
二. apply 与 call 的区分
1.apply()
A.apply(B, [1,2,3]) 后面的参数是 arguments 对象或类似数组的对象, 它会被自动解析为 A 的参数;
对于 A.apply(B) / A.call(B) , 简单讲, B 先执行, 执行后根据结果去执行 A. 这个时候, 用 A 去执行 B 的内容代码, 然后再执行自己的代码.
比如:
- var f1 = function(a,b){
- console.log(a+b)
- }
- var f2 = function(a,b,c){
- console.log(a,b,c)
- }
- f2.apply(f1,[1,2])//1 2 undefined
先执行 f1,f1 执行后 (f1 是 f1, 不是 f1() 执行方法, 所以 console.log(a+b)这行代码并没有执行, 相当于, 初始化了代码 f1), 由于没有返回值, 所以结果是 undefined,f2 执行的时候 this 指向 Windows; 参数中的 "[1,2]", 解析后变成 f2 的参数 "1,2,undefined", 执行 f2 方法后, 打印出 1,2,undefined 三个值
2.call()
A.call(B, 1,2,3) 后面的参数都是独立的参数对象, 它们会被自动解析为 A 的参数;
比如:
- var f1 = function(a,b){
- console.log(a+b)
- }
- var f2 = function(a,b,c){
- console.log(a,b,c)
- }
- f2.call(f1,[1,2])//[1,2] undefined undefined
- f2.call(f1,1,2)//1 2 undefined
参数中的 "[1,2]", 因为传入了一个数组, 相当于只传入了第一个参数, b 和 c 参数没有传. 解析后变成 f2 的参数 "[1,2],undefined ,undefined", 执行 f2 方法后, 打印出 [1,2],undefined ,undefined 三个值.
三. apply 与 call 带来的便利
1. push();
push 参数是类似 (a,b,c,d,e) 如此传输的, 如果在一个数组的基础上进行传输另一个数组的内容, 可以如下:
- //apply 用法
- var arr = new Array(1,2,3)
- var arr1 = new Array(11,21,31)
- Array.prototype.push.apply(arr,arr1)
- console.log(arr)//[1, 2, 3, 11, 21, 31]
- //call 用法
- var arr = new Array(1,2,3)
- var arr1 = new Array(11,21,31)
- Array.prototype.push.call(arr,arr1[0],arr1[1],arr1[2])
- console.log(arr)//[1, 2, 3, 11, 21, 31]
2. 数组利用 Math 求最大和最小值
apply 和 call 的第一个参数, 如果是 null 或者 undefined, 则 apply 或 call 前面的函数会把 this 指向 Windows
- //apply 的用法
- var _maxNum = Math.max.apply(null,[1,3,2,4,5])
- console.log(_maxNum)//5
- var _minNum = Math.min.apply(null,[1,3,2,4,5])
- console.log(_minNum)//1
- //call 的用法
- var _maxNum = Math.max.call(null,1,3,2,4,5)
- console.log(_maxNum)//5
- var _minNum = Math.min.call(null,1,3,2,4,5)
- console.log(_minNum)//1
四. 总结
简而言之, apply 和 call 函数的第一个参数都是用来替换 this 指向的对象; apply 的第二个参数使用 arguments 或者类似数组的参数进行传参, call 的第二个或以上的参数, 使用独立单位, 一个一个进行传参; 执行顺序是 apply 或 call 的第一个参数先执行得到结果, 然后执行 apply 或 call 前面的函数, 执行的时候用已经执行的结果所指代的 this 去执行. apply 和 call 的使用除了参数上的使用方式不同外, 功能是一模一样的.
以上内容纯属个人理解, 有误勿喷请指出! 谢谢!
来源: https://www.cnblogs.com/Chansea/p/11936094.html