一些细节操作,有兴趣吗

前言

之前简单分析过apply与call之间的简单区别和用法,并没有对他们的做进一步的深究,赶上今天上课老师出差让我们自习,借用这个时间,来分享我关于apply和call的一些学习总结,用apply和call来借用原生方法,和apply、call之间传入参数为什么要设计成不一样,这两个问题进行分享。

借用原生方法

在JavaScript里面,对象的地位或许有点低,为什么这么说呢?因为数组和字符串都有很多用来遍历或者修饰的方法,而对象却没有那么多。那怎么办,总得生存下去呀,这个时候对象“自力更生”,通过call和apply来借用数组或者字符串的方法,来弥补自己不被“重视”的不足。

我们想想对象是不是和数组在很多方面都很类似,比图说下面的这个对象我们可以视它为一个“类数组对象”:

1
2
3
4
5
6
7
var likeObjectArr = {
0:'hua',
1:'jin',
2:['photo', 'trip'],
length: 3
}
console.log(likeObjectArr[1]) // jin

所谓类数组对象,就是指有自己的非负数的整型键。由于对象上不存在length属性,但是数组上有这个属性,所以最好是在这个对象上添加一个表示这个对象长度的length属性,要不然就无法使用Array上的一些方法。

那么,我们就可以利用call或apply来使用数组的方法,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var likeArr = {
0:'hua',
1:'jin',
2:['photo', 'trip'],
length: 3
}
// 裁剪对象
console.log(Array.prototype.slice.call(likeArr, 1,3))
// [ 'jin', [ 'photo', 'trip' ] ]

// 查看对象中是否含有某个值
console.log(Array.prototype.indexOf.call(likeArr,'jin') !== -1)
// true

// 吐出最后的一个对象值(直接对原值产生影响)
Array.prototype.pop.call(likeArr)
console.log(likeArr)
// '0': 'hua', '1': 'jin', length: 2 }

// 反转对象(直接对原值产生影响)
console.log(Array.prototype.reverse.call(likeArr))
// { '0': 'jin', '1': 'hua', length: 2 }

这里我们时刻注意到,类数组对象在使用数组的方法时,那个length属性是不受影响的,你可以忽视它,它的存在只是告诉数组方法这个类数组对象的“长度”。这几个例子只是抛砖引玉,还有很多方法都可以用上去,这里就让大家自己去探索啦~

参数传入差异的原因

也许我们会奇怪,apply和call都是一个作用,还为啥要设计两种不一样的参数传入方法呢?ECMA当然不会吃饱了没事干要这么做,一切的设计在某方面都是有作用的,这次我来给大家解答疑惑,虽然说不一定就因为这一点原因,但是希望能给大家带来思考。

假如我们要判断一个数组中最大的数,这个时候我们会怎么做?想都不用想,用max呀:

1
let maxNum = Math.max(1,3,12,52,5) // 52

但是如果我们又一个数组要判断呢,我开始也是这么想的:

1
2
let array = [1,3,12,52,5]
let maxNum = Math.max(array) // NaN

WTF? 这不是一样传入的吗?怎么会出错?不存在的呀!!!

原来,有一种函数叫变参函数,这种函数可以接受任意数量的参数,在函数内部通过使用arguments来获取传入的参数,像上面的Math.max一样,就是典型的变参函数,它接受的不是一个数组,而是多个参数。这个时候,要解决上面的问题,就要用到了apply的特殊用法。

1
Math.max.apply(null, [1,3,5,65]) == Math.max(1,3,5,65)

我们用个==来表示apply的特殊用法,apply可以通过将自己的“数组”参数,转化为实际函数当中的“单个参数”,这就完美解决了我们上面遇到的问题:

1
2
let array = [1,3,12,52,5]
let maxNum = Math.max.apply(null,array) // 52

到这里你大概能知道apply的存在的意义吧~没错,它很多时候会被用来解决变参函数的参数传入问题。

总结

这篇文章主要是讲解一些apply和call不被新手知道的几个点,特别是借用方法,这个在看很多大佬的源码当中经常看到,这个时候我们就不会一脸懵逼啦,还有简单解释下apply和call的传参差异的原因,如有错误欢迎指正~

No one can call back yesterday. Yesterday will not be called again. :)