手写call和apply在面试题汇总里面还是挺常见的,这里记录下自己练习时候的笔记
手写call
call根据MDN解释,是传入this指向以及多个参数,执行之后返回结果,具体语法是function.call(thisArg, arg1, arg2, ...)
。
thisArg:是传入的this指向
targ1, arg2, ...:传入的参数,call是可以传入多个
这里call有2种使用方法:
- foo.call() 此时没有传入新的this指向,那么默认为指向window,需注意严格模式下为undefined
- foo.call(a) 正常使用call,此时this指向为a
Function.prototype.myCall = function(context) {
if(typeof this !== 'function') {
// 判断当前调用者是否为函数
return
}
// 保存传入的this指向,这里会出现没有传入this指向的问题,那么that就是默认的window
that = context || window
// 保存当前调用的函数
that.fn = this
// 通过slice来截取传入的参数
const args = [...arguments].slice(1)
// 传入参数调用函数
const result = that.fn(...args)
// 删除掉fn属性
delete that.fn
// 返回结果
return result
}
实际测试手写call
// 当不传入或者传入undefined的时候,指向window
var test = function(){
console.log(this===window);
}
test.myCall();//true
test.myCall(undefined);//true
// 借用别人的方法
var foo = {
name:'day',
sayName:function(){
console.log(this.name);
}
}
var bar={
name:'Taec'
};
// 这里将this改为bar,那么输出的this.name的this就是bar
foo.sayName.myCall(bar); // Taec
// 实现继承
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Dog (name){
// 使用call来借用构造函数完成继承
// 这里的传参是直接传参
Animal.myCall(this, name);
}
var dog = new Dog("dogdog");
dog.showName(); //dogdog
手写apply
apply的原理和call一样,只是后面的传参是接收数组形式,具体语法func.apply(thisArg, [argsArray])
,更多信息可以参考MDN。
Function.prototype.myApply = function(context) {
if(typeof this !== 'function') {
// 判断当前调用者是否为函数
return
}
// 保存传入的this指向
that = context || window
// 保存当前调用的函数
that.fn = this
let result
// 这里开始判断传入的参数是否存在,此时参数是一个数组形式[thisArg,[传参]]
// 那么如果arguments[1]即传参存在的时候,就是需要传参调用保存的函数
// 如果不存在就直接调用函数
if (arguments[1]) {
result = that.fn(...arguments[1])
} else {
result = that.fn()
}
return result
}
实际测试手写apply
// 当不传入或者传入undefined的时候,指向window
var test = function(){
console.log(this===window);
}
test.myApply();//true
test.myApply(undefined);//true
// 借用别人的方法
var foo = {
name:'day',
sayName:function(){
console.log(this.name);
}
}
var bar={
name:'Taec'
};
// 这里将this改为bar,那么输出的this.name的this就是bar
foo.sayName.myApply(bar); // Taec
// 实现继承
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Dog (name){
// 使用call来借用构造函数完成继承
// 这里需要注意,根据apply的使用,这里的传参是需要使用数组传参
// 如果不是数组,那么输出的就是字符串的第一个字符
Animal.myApply(this, [name]);
}
var dog = new Dog("dogdog");
dog.showName(); //dogdog