因为call语法和作用与 apply 方法类似。
只有一个区别,call 接受的是一个参数列表,而 apply 接受的是一个包含多个参数的数组。
所以放到一起。
call
- 将函数设为传入参数的属性
- 指定this到函数并传入给定参数执行函数
- 如果不传入参数或者参数为null,默认指向为 window / global
- 删除参数上的函数
Function.prototype.call = function (context) {
/** 如果第一个参数传入的是 null 或者是 undefined, 那么指向this指向 window/global */
/** 如果第一个参数传入的不是null或者是undefined, 那么必须是一个对象 */
if (!context) {
//context为null或者是undefined
context = typeof window === 'undefined' ? global : window;
}
context.fn = this; //this指向的是当前的函数(Function的实例)
let args = [...arguments].slice(1);//获取除了this指向对象以外的参数, 空数组slice后返回的仍然是空数组
let result = context.fn(...args); //隐式绑定,当前函数的this指向了context.
delete context.fn;
return result;
}
/*
方法2
原理就是将函数作为传入的上下文参数(context)的属性执行,这里为了防止属性冲突使用了 ES6 的 Symbol 类型
*/
const selfCall = function(context , ...args){
let func = this;
context || (context = window)
if(typeof func !== 'function') throw new TypeError('this is not function');
let caller = Symbol("caller");
context[caller] = func;
let res = context[caller](...args);
delete context[caller];
return res
}
手写apply
apply的实现和call很类似,但是需要注意他们的参数是不一样的,apply的第二个参数是数组或类数组.
Function.prototype.apply = function (context, rest) {
if (!context) {
//context为null或者是undefined时,设置默认值
context = typeof window === 'undefined' ? global : window;
}
context.fn = this;
let result;
if(rest === undefined || rest === null) {
//undefined 或者 是 null 不是 Iterator 对象,不能被 ...
result = context.fn(rest);
}else if(typeof rest === 'object') {
result = context.fn(...rest);
}
delete context.fn;
return result;
}
如有侵权,请联系我