js模拟实现call函数和apply函数
fun.call()
作用:call() 改变函数中的this,直接调用函数,可以看成调用函数的另一种方式
语法:fun.call(thisArg, arg1, arg2, ...)
手写前,我们要知道的事情
- 所有函数都可以调用call,所以需要在
Function.prototype
上添加 - call函数的第一个参数为不传或为null或为undefined时,执行window
- 后续的参数为obj.getName函数的参数,可以传递任意个参数
- call 函数的作用是改变this指向
- 执行call前面的函数 --> obj.getName
使用场景:
- 实现构造函数继承
- 判断复杂类型:Object.prototype.toString.call({}) === ‘[object Object]’
- 伪数组转数组:Array.prototype.slice.call(伪数组)
手写call
let obj = {
name: 'ls',
getName: function (...rest) {
// console.log(this == window);
console.log(this.name, ...rest);
}
}
let person = {
name: 'zs'
}
Function.prototype.myCall = function (context, ...rest) {//...rest代表接收任意多个参数,上一个数组
if (typeof this !== 'function') {
throw new Error(this + 'is not a function')
}
context = context || window
// 改变this指向 ,这里的 context 为 person
//给context这个对象添加一个函数fn,将this赋值给fn,这里的this为obj.getName
/*相当于
let person = {
name: 'zs',
fn:obj.getName
}
那么在调用person.fn()的时候,getName方法找到this就是指向person的
*/
context.fn_call = this;
let result = context.fn_call(...rest)//...rest代表扩展rest这个数组
delete context.fn_call;
return result
}
obj.getName.myCall(person, 1, 2, 3)//zs 1 2 3
obj.getName.call(person, 1, 2, 3)//zs 1 2 3
console.log(Object.prototype.toString.call([1,23]));//[object Array]
console.log(Object.prototype.toString.myCall([1,23]));//[object Array]
fun.apply
语法:func.apply(thisArg, [argsArray])
argsArray:数组或类数组
既然会了call,那么apply也就简单了,无非就是第二个参数为数组的形式
let obj = {
name: 'ls',
getName: function (...rest) {
// console.log(this == window);
console.log(this.name, ...rest);
}
}
let person = {
name: 'zs'
}
Function.prototype.myApply = function (context, arr) {
if (typeof this !== 'function') {
throw new Error(this + 'is not a function')
}
if(arr && !Array.isArray(arr)){
throw new Error(' CreateListFromArrayLike called on non-objectat')
}
context = context || window
context.fn_applu = this;
let result
if(!(context instanceof Object)){
// 基本数据类型
result = this()
}else if(arr && Array.isArray(arr)){
result = context.fn_applu(...arr)
}else{
result = context.fn_applu()
}
delete context.fn_applu
return result
}
console.log(Math.min.apply(person,[1,4,2]));//1
console.log(Math.min.myApply(person,[4,6,1]));//1
console.log(Math.min.apply(1));//Infinity
console.log(Math.min.myApply(1));//Infinity