Array.prototype.slice.call(arguments)

Posted by Ray on 2018-01-27

作用

一句话概括就是将 arguments 转化为真正的数组输出出去。何为真正的数组?真正的数组是相对于“伪数组”来说的,常见的有 NodeList 与 HTMLCollection 还有 函数的参数 arguments。 这些伪数组最大的共同特点就是他们都具有 length 属性,并且属性名为数字,但是并不能用真正数组的那些像是 push(),pop(),slice(),这些方法。

V8源码

v8/src/js/array.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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);
%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;
}

大体的意思

1
2
3
4
5
6
7
8
function slice(start, end) {   
var len = this.length, result = [];
//省略对调用start和end情况的判断
for(var i = start; i < end; i++) {
result.push(this[i]);
}
return result;
}

对于我们的 Array.prototype.slice.call(arguments)就是没有往 slice中传入 start 和 end 默认是从0 开始到最大长度为止。

什么是arguments

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数的条目,第一个条目的索引从0开始。

1
2
3
4
5
function fn (a,b,c){
console.log(arguments.length)
}

fn(1,2,3)

输出:

这就是一个伪数组,我想让他成为真正数组怎么办呢

什么是call

1
2
3
4
5
6
7
8
9
10
function fn(){
console.log(this.a)
}
let obj = {
a:1
}

fn()

fn.call(obj)

输出:

1
2
undefinded
1

简要的说 call 可以用来改变函数中的this指向,看了之前的slice的源码,发现只要你有 length 属性 那么 slice 会根据对象的数字属性名来得到对应的值并将它作为数组的元素。

那么就可以得出 Array.prototype.slice.call(arguments)得到的就是一个 function 参数数组了

1
2
3
4
5
6

function fn(a,b,c){
let args = Array.prototype.slice.call(arguments);
console.log(args)
}
fn(1,2,3)

打印结果:

1
[ 1, 2, 3 ]

thunkify 源码中的应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function thunkify(fn) {
return function() {
var args = Array.prototype.slice.call(arguments);
var ctx = this;

return function(done) {
var called = false;
args.push(function() {
if (called) return;
called = true;
done.apply(null, arguments);
});
try {
fn.apply(ctx, args);
} catch (err) {
done(err);
}
}
}
}
本文为原创文章作为学习交流笔记,如有错误请您评论指教
转载请注明来源:https://isliulei.com/article/Array-prototype-slice-call-arguments/