call 函数
简介
call 函数的用法:
js
fn.call(obj,1,2);
- call() 函数中的第一个参数表示:想让 this 指向的对象 (obj);
- call() 函数中的第二及以后参数表示:传进去的实参;
call 函数的功能:
- 让函数立执行;
- 可改变 this 的指向;
- 可实现继承问题;
call 函数的调用
js
const user1 = {
name : '张三',
age : 10
}
const user2 = {
name: '李四',
age: 20
}
function say(){
console.log('name:', this.name)
const sum = [...arguments].reduce((res, current)=> {
res = res + current
return res
})
console.log(sum);
}
say.call(user1, 1,2,3)
say.call(user2, 4,2,3)
以上是一个 call 函数调用的示例
- 定义了两个对象分别是 user1 与 user2
- 定义say()函数,输出当前调用的 name 与剩余参数的求和结果
- 通过 call 函数执行 say 函数,分别传参 user1 与 user2
分别将当前 this 绑定至 user1 与 user2 ,输出结果为:
手写 call 函数
下面我们自己来实现 call 函数:
js
const user1 = {
name : '张三',
age : 10
}
const user2 = {
name: '李四',
age: 20
}
function say(){
console.log('name:', this.name)
const sum = [...arguments].reduce((res, current)=> {
res = res + current
return res
})
console.log(sum);
}
Function.prototype.myCall = function(ctx, ...args){
ctx = (ctx===null || undefined)? globalThis : Object(ctx)
const key = Symbol('temp');
Object.defineProperty(ctx, key, {
enumerable: false,
value: this
})
const result = ctx[key](...args)
delete ctx[key]
return result
}
say.myCall(user1,1,2,3)
- 首先还是先定义对象 obj 与 obj2,函数 say()
- 在函数原型上新增 myCall方法,接收两个参数,ctx 为必填参数表示 this 的指向,...args接收剩余参数
- 判断 ctx 的是否为 null 或者 undefined,如果是的话,当前 this 指向 globalThis, (globalThis旨在通过定义一个标准的全局属性来整合日益分散的访问全局对象的方法。该提案目前处于第四阶段,这意味着它已经准备好被纳入ES2020标准。所有流行的浏览器,包括Chrome 71+、Firefox 65+和Safari 12.1+,都已经支持这项功能。你也可以在Node.js 12+中使用它。)
-
需要给ctx 定义个属性将剩余参数传入进去,为了避免与绑定的 ctx 参数重复,使用 Symbol()定义 key 值
-
定义的 key 值通过 Object.defineProperty(obj,key,decriptor)方法传入,obj为目标对象,key 为 属性 值,descriptor是我们操作属性的具体描述,这里我们使用enumerable不可被枚举,具体包含的参数有:
- value:被定义的属性的值,默认值为undefind
- writable:是否可以被重写,也就是value属性是否可以被赋值,当writable的值为true的时候,可以被重写,反之不可以。
- enumerable:该属性是否可以被枚举,值为true可以被枚举,反之则不可以。
- configurable:该属性是否可以被删除,或者是否可以被修改,值为true可以被删除或者被修改,反之则不可以。
-
将剩余参数传递给定义好的函数
-
将定义的属性删除,return 结果出去
-
最后,使用 say().myCall(user1,1,2,3)调用,输出的结果为:
总结
使用 globalThis 可以在浏览器以及 node 环境上运行,Symbol定义唯一 key 值等操作
apply函数
简介
apply 函数跟 call 函数的区别在于穿参形式不一样,apply 函数的第二个参数是一个数组,示例:
js
const user1 = {
name : '张三',
age : 10
}
const user2 = {
name: '李四',
age: 20
}
function say(){
console.log('name:', this.name)
console.log('args:',[...arguments])
const sum = [...arguments].reduce((res, current)=> {
res = res + current
return res
})
console.log('sum:',sum);
}
say.apply(user1, [1,2,3])
say.apply(user2, [2,3,4])
运行结果:
手写 apply 函数
将 myCall 函数改造 下
js
const user1 = {
name : '张三',
age : 10
}
const user2 = {
name: '李四',
age: 20
}
function say(){
console.log('name:', this.name)
console.log('args:',[...arguments])
const sum = [...arguments].reduce((res, current)=> {
res = res + current
return res
})
console.log('sum:',sum);
}
Function.prototype.myApply = function(ctx, ...args){
ctx = (ctx===null || undefined)? globalThis : ctx
const key = Symbol('temp');
Object.defineProperty(ctx, key, {
enumerable: false,
value: this
})
console.log(...args)
// 注意该处的传参形式
const result = ctx[key](...args[0])
delete ctx[key]
return result
}
say.myApply(user2,[2,3,4])