[].slice.call()与Array.prototype.slice.call()将类数组转化为真正的数组
在ES6以前,将一个伪数组转换为真正数组通常情况下都是使用[ ].slice.call()方法
补充:ES6的方法为 Array.from()
1、区别
[].slice === Array.prototype.slice // true
[]为创建数组,当[].slice的时候,自然会去找原型链
[].__proto__.slice === Array.prototype.slice // true
-
Array.prototype.slice是定义的方法,可以被重写
-
[].silce是使用定义的方法
-
自身的属性不同(因为原型与[]的区别)
Object.getOwnPropertyNames(Array.prototype)
// (33) ["length", "constructor", "concat", "copyWithin", "fill", "find", "findIndex", "lastIndexOf", "pop", "push", "reverse", "shift", "unshift", "slice", "sort", "splice", "includes", "indexOf", "join", "keys", "entries", "values", "forEach", "filter", "flat", "flatMap", "map", "every", "some", "reduce", "reduceRight", "toLocaleString", "toString"]
Object.getOwnPropertyNames([]) // ["length"]
所以在本质上[]和Array.prototype没有本质区别,但是调用上是有区别的,但是根据专业检测,[]要更快一点
2、slice
slice()方法返回一个从开始到结束(不包括结束)选择的数组的一部分进行浅拷贝到一个新的数组对象,并且原对象不会被修改
- 如果该元素是个对象引用 (不是实际的对象),
slice
会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。 - 对于字符串、数字及布尔值来说(不是 [
String
]、[Number
] 或者 [Boolean
]对象,slice
会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。
slice
这个方法在不接受任何参数的时候会返回 this
本身
arguments
是属于函数内部的变量,其值是函数参数列表,一个类数组对象,是具有长度属性的,但并不是数组,不具备slice()这个方法,那就意味着 arguments.slice()
行不通
3、call
call() 是所有函数都具备的方法,其作用有两个,即调用函数并改变函数内部this指向。
通过call()
将[].slice中的this指向了arguments
,使其拥有了slice
方法,就实现了对象转数组
function list() {
console.log(arguments); // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
return Array.prototype.slice.call(arguments);
}
console.log(list(1, 2, 3)); // [1, 2, 3]
var arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
}
console.log([].slice.call(arrayLike)); // ["a", "b", "c"]
Array.from(arrayLike); // ["a", "b", "c"]
为什么将arguments的call给slice就可以变成数组?内部到底发生了什么
我们可以实现一个自己的slice(),就明白了
4 、Myslice()
Array.prototype.Myslice = function (begin,end){
var start = begin || 0; //判断begin时候存在 不存在给0 这里判断可以加强
var len = this; //获取this.length 这里得到了call进来的对象
start = (start >= 0) ? start : Math.max(0, len + start); //判断参数是不是是不是大于1,负数情况下的begin取值
end = (typeof end == 'number') ? Math.min(end, len) : len; //判断end是不是大于this.length的长度
if(end<0){
end = end + len //判断负值的情况
}
var result = new Array();
for (let i = 0; i < end.length; i++) {
result.push(this[i])
}
return result;
}
JavaScript sclie的源码
Array.prototype.slice = function(begin, end) {
end = typeof end !== 'undefined' ? end : this.length
if (Object.prototype.toString.call(this) === '[object Array]') {
return _slice.call(this, begin, end)
}
var i,
cloned = [],
size,
len = this.length
var start = begin || 0
start = start >= 0 ? start : Math.max(0, len + start)
var upTo = typeof end == 'number' ? Math.min(end, len) : len
if (end < 0) {
upTo = len + end
}
size = upTo - start
if (size > 0) {
cloned = new Array(size)
if (this.charAt) {
for (i = 0; i < size; i++) {
cloned[i] = this.charAt(start + i)
}
} else {
for (i = 0; i < size; i++) {
cloned[i] = this[start + i]
}
}
}
return cloned
}