call要领真是一个有意思的东西,它能够转变函数挪用时this的值。而我们晓得,在函数里,this指向了挪用这个函数的环境对象,比方一道典范面试题:
var num = 2;
var obj = {
num: 1,
show: function () {
console.log(this.num)
}
};
var foo = obj.show;
obj.show();/* 显现1;show是被obj挪用的,所以this指向obj */
foo();/* 显现2;相当于global.foo(),所以this指向global,假如在浏览器里global就是window */
换句话说,假如一个对象obj上有要领foo,你能够经由过程obj.foo()
挪用;假如没有obj上没有要领foo,obj.foo()
是会报错的,然则,运用foo.call(obj)
,能够强行到达obj.foo()
的结果,比方:
function foo(){
console.log(this.num);
}
var obj = {
num: 1
}
foo.call(obj);// 1
Array.prototype.slice.call
的用途就是如许,能够在array-like(类数组,就是长得像数组,但不是数组)的对象上强行运用slice要领,比方:Array.prototype.slice.call(arguments)
就是把arguments
对象转化为数组。固然,除了arguments
,我们还能在HTMLCollection
或NodeList
身上运用。那末究竟什么算是类数组呢?
有length属性的对象。
比方:
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason',
length: 3
}
var arr = [].slice.call(obj1);
console.log('arr: ', arr);/* [ 'Tom', 'Jack', 'Jason' ] */
那假如没有length呢?
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason'
}
var arr = [].slice.call(obj1);//* [] */
本来没有length属性的对象也会被转为数组,只不过以为它length=0罢了。
那假如对象的属性没有根据0-n递次乖乖排好呢?
var obj1 = {
1: 'Tom',
3: 'Jack',
5: 'Jason',
7: 'Dave',
foo: 'bar',
length: 6
}
var arr = [].slice.call(obj1);/* [ , 'Tom', , 'Jack', , 'Jason' ] */
本来转化的时刻,会以length
为基本,天生一个长度为length
的数组,obj
的属性是数组的有用index
的话,就会把对应值填入到对应位置,其他的位置找不到值,就会填入undefined
。
所以前面的说法实在不对,一切的对象都能够被视为类数组,有length
的视为长度为length
的数组,没有的,视为长度为0的数组。
以length
属性为基本
这句话很主要。
别的,call
要领的参数假如是原始值范例
,会传入它的自动包装对象
:
var arr = [].slice.call('hello');
等价于:
var arr = [].slice.call(new String('hello'));/* [ 'h', 'e', 'l', 'l', 'o' ] */
由于new String('hello')就是
{
0: "h",
1: "e",
2: "l",
3: "l",
4: "o",
length: 5
}
以上就是Array.prototype.slice.call
的一些细节,那末除了slice
以外,Array
对象另有许多其他的要领,这些要领是否是也能用到对象身上呢?
Array.prototype.join
join要领是把数组转化为字符串的要领,具体表现不再赘述,看两个例子:
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason',
length: 6
}
var arr = [].join.call(obj1, '-');// Tom-Jack-Jason---
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason',
}
var arr = [].join.call(obj1, '-'); // ''
照样那句话,以length
为基本,没有length
属性的,视为长度为0的数组。
Array.prototype.push
这个要领比较好玩:
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason',
length: 6
}
var arr = [].push.call(obj1, 'Dave');
console.log('arr: ', arr);// 7,由于push要领返回的是push以后array的操作数
console.log('obj: ', obj1);// { '0': 'Tom', '1': 'Jack', '2': 'Jason', '6': 'Dave', length: 7 }
能够看到obj1
里新增属性6
,值为'Dave'
,而且length
也更新为7
,这说明挪用push
时会对原有对象举行修正。
我们能够应用这个特征,比方当我们须要一个obj1
的类数组副本时:
var obj = {
foo: 'foo',
bar: 'bar',
cei: 'cei'
};
var copy = {};
for (var i in obj) {
[].push.call(copy, obj[i])
}
console.log(copy);// { '0': 'foo', '1': 'bar', '2': 'cei', length: 3 }
假如,没有传入length
呢?
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason'
}
var arr = [].push.call(obj1, 'Dave');
console.log('arr: ', arr);// 1
console.log('obj: ', obj1);// { '0': 'Dave', '1': 'Jack', '2': 'Jason', length: 1 }
这里的行动有些诡异,不过也更好地诠释了以length为基本这句话:
没有length
的时刻,以为数组长度为0
,而且会对obj
举行修正,把属性0的值改成Dave
.
那末,会闻一知十的话,关于pop
, shift
和unshift
这三个要领的行动应该能设想得出来,就不再赘述了。
Array.prototype.reverse
var obj1 = {
0: 'Tom',
1: 'Jack',
2: 'Jason',
length: 6
}
var arr = [].reverse.call(obj1);
console.log('arr: ', arr);// { '3': 'Jason', '4': 'Jack', '5': 'Tom', length: 6 }
console.log('obj: ', obj1);// { '3': 'Jason', '4': 'Jack', '5': 'Tom', length: 6 }
reverse
的话,arr === obj1
Array.prototype.sort
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].sort.call(obj1);
console.log('arr: ', arr);// { '0': 'a', '1': 'b', '2': 'c', length: 6 }
console.log('obj: ', obj1);// { '0': 'a', '1': 'b', '2': 'c', length: 6 }
sort
也一样,arr === obj1
Array.prototype.concat
concat
的表现就不是我们意料之中的了:
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var add = {
foo: 'foo',
bar: 'bar'
}
var arr = [].concat.call(obj1, add);
console.log('arr: ', arr);// [ { '0': 'c', '1': 'b', '2': 'a', length: 6 }, 'foo', 'bar' ]
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].concat.call(obj1, 'foo', 'bar');
console.log('arr: ', arr);// [ { '0': 'c', '1': 'b', '2': 'a', length: 6 }, 'foo', 'bar' ]
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
能够看到obj1
并不会转变,不会像push
一样会接着构成一个类数组的对象.
Array.prototype.splice
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].splice.call(obj1, 0, 1);
console.log('arr: ', arr);// [ 'c' ]
console.log('obj: ', obj1);// { '0': 'b', '1': 'a', length: 5 }
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].splice.call(obj1, 1, 0, 'foo','bar');
console.log('arr: ', arr);// []
console.log('obj: ', obj1);// { '0': 'c', '1': 'foo', '2': 'bar', '3': 'b', '4': 'a', length: 8 }
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].splice.call(obj1, 1, 1, 'foo','bar');
console.log('arr: ', arr);// [ 'b' ]
console.log('obj: ', obj1);// { '0': 'c', '1': 'foo', '2': 'bar', '3': 'a', length: 7 }
splice
的行动回归了,它现在对obj1
产生影响,而且是我们估计的模样
Array.prototype.every
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].every.call(obj1, function (val) {
return val === 'a' || val === 'c'
});
console.log('arr: ', arr);// false
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
Array.prototype.filter
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].filter.call(obj1, function (val) {
return val === 'a' || val === 'c'
});
console.log('arr: ', arr);// [ 'c', 'a' ]
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
Array.prototype.forEach
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].forEach.call(obj1, function (val) {
return val + ' add';
});
console.log('arr: ', arr);// undefined
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
Array.prototype.map
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].map.call(obj1, function (val) {
return val + ' add';
});
console.log('arr: ', arr);// [ 'c add', 'b add', 'a add', , , ]
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }
Array.prototype.reduce
var obj1 = {
0: 'c',
1: 'b',
2: 'a',
length: 6
}
var arr = [].reduce.call(obj1, function (pre, cur) {
return pre + ' ' + cur
});
console.log('arr: ', arr);// 'c b a'
console.log('obj: ', obj1);// { '0': 'c', '1': 'b', '2': 'a', length: 6 }