【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考
前言
在阅读发布-订阅设计模式的文章时,看到了这样一行代码:
它的作用是:获取arguments
中的第一个参数
我的思考:
1、为什么不直接使用arguments.shift()
呢?
2、call
的作用是什么?
思考
1、为什么不直接使用arguments.shift()
呢?
原因:arguments
是一个类数组,并没有shift
方法
打印一下arguments
:
可以看到它并没有shift方法。
我们打印下Array.prototype
:
可以看到数组的原型对象上是有shift方法的。
所以通过Array.prototype.shift.call(arguments)
来获取第一个参数。
但对这代码又有了新的疑惑:
我:为啥这里要用到call函数呢?
友:改变this指向
我有点懂了,以下是我的理解:
使用call
函数的作用是将this指向arguments
,也就是让arguments
调用了shift
方法。
接下来就来聊聊JS
中的call
和apply
2、call和apply的理解
相同点:
- 都可以改变this指向
- 立即执行。
不同点:
- apply方法接收两个参数,第一个是函数运行的作用域,第二个是参数数组。如:
fn.apply(obj,[arg1,arg2,...])
- call方法第一个参数也是函数运行的作用域,但它的参数是列举出来的。如
fn.call(obj,arg1,arg2,...)
举个例子:
const obj = {
a: 1,
b: 2
}
function fn(a) {
console.log('a:' + a)
console.log('this.a:' + this.a)
}
fn.call(obj, 5)
fn.apply(obj, [5])
输出:
以上相当于在obj对象上调用fn函数,所以this
指向obj
,故this.a
就输出1。
再来看个例子:
const arr1 = [1,2],
arr2 = [3,4];
Array.prototype.push.apply(arr1,arr2)
看下输出结果:
代码分析:
this
指向了arr1
,arr2
是参数数组,就是在arr1
上调用了push
方法,并传递了参数arr2
,即将arr2
中的参数循环遍历push
到arr1
中。
其实到这就基本理解了call
和apply
的作用了。
3、自定义call和apply
每个函数上都可以调用call
和apply
方法,故我们可以将自定义的方法写在函数的原型上。
思路:
1、判断第一个参数是否传入,默认为window
2、第一个参数传入,即改变this
指向,我们需要在这个新的对象上添加一个fn
函数,并且立即执行它,完成后删除它。
自定义call
Function.prototype.myCall = function(context, ...args) {
context = context || window // 不传入参数,默认window
// 将函数挂载到目标函数上
context.fn = this; // this指向调用函数
// 立即执行函数,并保存返回值
const result = context.fn(...args)
// 删除挂载在目标对象上的函数,还原原本的目标对象
delete context.fn
return result
}
context
:重定义this
指向...args
:传递的参数(args
),列队形式传递,故...args
自定义apply
Function.prototype.myApply = function(context, args) {
context = context || window
context.fn = this
const res = context.fn(...args)
delete context.fn
return res
}
context
:重定义this
指向args
:传递的参数(args
),数组形式,即直接写args
应用
const obj = {
a: 1
}
function a(a) {
console.log("this.a:" + this.a)
console.log("传递的参数a:" + a)
}
a.myCall(obj, 6)
看输出结果已经成功改变了this
的指向。
转载自:https://juejin.cn/post/7213653429415903287