likes
comments
collection
share

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

作者站长头像
站长
· 阅读数 20

前言

在阅读发布-订阅设计模式的文章时,看到了这样一行代码:

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

它的作用是:获取arguments中的第一个参数

我的思考:

1、为什么不直接使用arguments.shift()呢?

2、call的作用是什么?

思考

1、为什么不直接使用arguments.shift()呢?

原因arguments是一个类数组,并没有shift方法

打印一下arguments

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

可以看到它并没有shift方法。

我们打印下Array.prototype

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

可以看到数组的原型对象上是有shift方法的。

所以通过Array.prototype.shift.call(arguments)来获取第一个参数。

但对这代码又有了新的疑惑:

我:为啥这里要用到call函数呢?

友:改变this指向

我有点懂了,以下是我的理解:

使用call函数的作用是将this指向arguments,也就是让arguments调用了shift方法。

接下来就来聊聊JS中的callapply

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])

输出:

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

以上相当于在obj对象上调用fn函数,所以this指向obj,故this.a就输出1。

再来看个例子:

const arr1 = [1,2],
arr2 = [3,4];

Array.prototype.push.apply(arr1,arr2)

看下输出结果:

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

代码分析:

this指向了arr1arr2是参数数组,就是在arr1上调用了push方法,并传递了参数arr2,即将arr2中的参数循环遍历pusharr1中。

其实到这就基本理解了callapply的作用了。

3、自定义call和apply

每个函数上都可以调用callapply方法,故我们可以将自定义的方法写在函数的原型上。

思路:

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)

【JS】一行代码`Array.prototype.shift.call(arguments)`引发的思考

看输出结果已经成功改变了this的指向。