使用数组的slice方法将类数组转换为数组
原理:slice将类数组通过下标操作放进了array里面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
28Array.prototype.slice = function(begin, end){
end = (typeof end != 'undefined') ? end :this.length
var i, cloned = [], size , len = this.length;
// 处理不合法的开始索引
var start = begin || 0;
start = (start > 0) ? start : Math.max(len + start, 0);
// 处理不合法的结束索引
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;
}
}call的模拟实现
实现思路:- 将函数设置为对象的属性: a.fn = fx
- 执行函数: a.fn()
删除函数: delete a.fn
1
2
3
4
5
6
7
8Function.prototype.call = function(context){
// 获取调用call的函数,用this来实现
context.fn = this;
// 执行函数
context.fn();
// 删除函数
delete context.fn
}上面的函数中实现了基本的call方法,但是被执行的方法fn不能接受参数,下面进行改进。
1
2
3
4
5
6
7
8
9
10Function.prototype.call = function(context){
context.fn = this;
var args = [];
// 去除第一个指定this的参数
for (var i = 1; i < arguments.length; i++){
argus.push('arguments[' + i + ']');
}
eval('context.fn('+ args +')'); // 需要将args中的元素一个个传递给fn,使用eval方法来实现。
delete context.fn
}上面的实现还需要注意以下三点:
- this的值可以传入为null或者undefined,此时采用的是默认绑定,指向的是全局对象,在浏览器中指向的是window对象
- this的参数可以是基本的数据类型,在原始的call方法中会采用Object函数进行对象化包装
函数是可以有返回值的
1
2
3
4
5
6
7
8
9
10
11Function.prototype.call = function(context){
context = context ? Object(context) : window;
context.fn = this;
var args = []
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var results = eval('context.fn('+ args +')');
delete context.fn;
return results;
}以上是ES3的实现方式,下面我们来看看ES6的实现方式
1
2
3
4
5
6
7
8Function.prototype.call = function(context){
context = context ? Object(context) : window;
context.fn = this;
let args = [...arguments].slice(1);
let results = context.fn(...args);
delete context.fn;
return results;
}
以上我们实现了call的方法,下面我们来实现apply的方法,apply的实现和call类似
es3实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18Function.prototype.apply = function(context, arr) {
context = context ? Object(context) : window;
context.fn = this;
var results;
// 判断是否传入了第二个参数
if (!arr) {
context.fn();
} else {
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push('arguments['+ i +']')
}
eval('context.fn('+ args +')')
}
delete context.fn;
return results;
}es6实现
1
2
3
4
5
6
7
8
9
10
11
12Function.prototype.apply = function(context, arr) {
context = context ? Object(context) : window;
context.fn = this;
let result;
if (!arr) {
context.fn();
} else {
result = context.fn(...arr);
}
delete context.fn;
return result;
}
call && apply实现
Last updated: