call()方法在数组中的一次应用分析
call()方法在数组中的一次应用分析
weixin_34212762 2019-05-16 14:04:45 348 收藏
版权
在阅读别人代码时, call和apply是常客。今天遇到一行代码 [].slice.call(arguments) 让我想真正了解一下它的含义。
一、看一下它的作用
let arr = [1, 2, 3, 4]
console.log([].slice.call(arr))
复制代码
结果:
可以看到, 结果是它本身.
添加参数:
可以看到添加参数后,生效的是前两位。所以猜测,其作用是和slice()函数基本一样。
根据call()的定义, 其根本是改变this指向,那么第一个参数就是slice()的this,后续则为参数。
为了更好的理解,我们重写Array的slice方法并打印:
结果
所以我们可以基本确定他是改变slice()的this。那么真的是么?我们一起看看源码
二、slice()源码简单分析
我们来看看Array的slice源码。 源码地址:V8 Array.js 587行
function ArraySlice(start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");
var array = TO_OBJECT(this);
var len = TO_LENGTH(array.length);
var start_i = TO_INTEGER(start);
var end_i = len;
if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);
if (start_i < 0) {
start_i += len;
if (start_i < 0) start_i = 0;
} else {
if (start_i > len) start_i = len;
}
if (end_i < 0) {
end_i += len;
if (end_i < 0) end_i = 0;
} else {
if (end_i > len) end_i = len;
}
var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0));
if (end_i < start_i) return result;
if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
%NormalizeElements(array);
if (IS_ARRAY(result)) %NormalizeElements(result);
SparseSlice(array, start_i, end_i - start_i, len, result);
} else {
SimpleSlice(array, start_i, end_i - start_i, len, result);
}
result.length = end_i - start_i;
return result;
}
复制代码
观察可知。Array的slice方法会通过TO_OBJECT(this)方法把传入的内容转换为数组。所以我们之前的分析是到位的。 因为大部分其封装的方法没有找到,所以只能靠命名判断(吐血.jpg)。
三、思考开始
但这儿我们可以猜到,那我们传入字符是否能转换成数组并返回呢?我们来试一试
一、使用[].slice.call(Str)
结果如我们所料,他可以让我们字符串转换成数组返回。
二、使用 slice方法.
如果我们直接使用slice方法
答案肯定是不行的,因为String和Array都有各自的slice()方法,如果要实现只有重写String方法,或者将Array的slice方法赋给String对象。
所以为了更好的利用slice()的方法,第二种方法显得更加麻烦。这也是第一种方法的妙用,这就更能加深我个人对call和apply的使用印象(apply应用同理)。
三、那么我们传入一个对象可以吗?
一起试试
答案是可以但是,有几个条件。 再次观察源码可知:
1) 需要Length长度
2) 需要Key值为下标(应该是TO_OBJECT()方法生成是以for...in循环,依靠下标遍历生成的,望大佬能指正)
所以这两种方法都只能返回一个空数组。