在 es5 标准中, 我们经常需要把 arguments 对象转换成真正的数组
- // 你可以这样写
- var arr = Array.prototype.slice.call(arguments)
- // 你还可以这样写
- var arr = [].slice.call(arguments)
- // 你要是不怕麻烦, 你还可以这样写
- var arr = [].__proto__.slice.call(arguments)
以上三种写法是等价的.
- // 当你了解原型链, 你就知道
- Array.prototype === [].__proto__ // true
- // [].slice 调用的是实例 [] 的原型对象中的 slice 方法
- [].slice === [].__proto__.slice // true
Array.prototype.slice.call(arguments)原本调用 slice 的是 Array.prototype, 而 call(arguments)使得调用 slice 方法的对象改成 arguments, 你可以想象成
- Array.prototype.slice.call(arguments) ~ arguments.slice()
- Array.prototype.slice.call(arguments, [begin[, end]]) ~ arguments.slice([begin [, end]])
我们可能会想 arguments 原型对象是 Object.prototype, 并没有 slice 方法, slice 方法从哪里来?
这是因为 call(arguments)不仅是改变了 this 的指向, 还使得 arguments 对象继承了 Array.prototype 中的 slice 方法.
下面是 Array.prototype.slice()源码: 指路 GitHub 地址 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;
- }
arguments 可以转换为数组对象也是因为
我们可以看到 arguments 对象成员属性类似数组, 且有 length 属性, 那是不是这样类似的对象都可以调用 slice 呢, 我们试验一下
- var obj = {
- 0: 'foo',
- 1: 'bar',
- 2: 'arg',
- length: 3
- }
- console.log(Array.prototype.slice.call(obj))
- // ["foo", "bar", "arg"]
这是可以的!
*PS:es6 语法中新增了 Array.from(), 所以上述类型的对象可以 Array.from(obj)就直接转化成数组!
来源: https://www.cnblogs.com/threeEyes/p/10478762.html