call
call接收多个参数,第一个参数为函数上下文也就是this,后边参数为函数本身的参数
let Person={
name:'Tom',
say(){
console.log(this)
console.log(`我叫${this.name}`)
}
}
Person.say() //{ name: 'Tom', say: [Function: say] } //我叫Tom
let Person1={
name:'Tom1'
}
Person.say.call(Person1) //{ name: 'Tom1' } //我叫Tom1
通过第一次打印和第二次打印结果发现,Person1中模拟实现了say方法,并打印出来。
Function.prototype.MyCall = function(context) {
//context就是demo中的Person1
console.log(this) //当前this指向调用Mycall的say方法
context.say = this //创建一个虚拟的say方法,将其指向say方法
context.say()
}
// 测试
Person.say.MyCall(Person1)//我叫Tom1
缺陷:call方法支持多参数或者无参数,创建的虚拟方法指定了,函数执行后,没有将创建的虚拟方法删除
实现call
let Person = {
name: 'Tom',
say(age) {
console.log(this)
console.log(`我叫${this.name}今年${age}`)
}
}
// Person.say()
let Person1 = {
name: 'Tom1'
}
// Person.say.call(Person1)
Function.prototype.MyCall = function (context=window,...args) {
//context就是demo中的Person1
// 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
console.log(this)
//为添加的虚拟方法取一个唯一名
const fn=mySymbol(context)
context[fn] = this //Mycall里边的this就是我们虚拟的say方法
context[fn](...args) //执行fn
delete context[fn] //删除方法
}
// 测试
Person.say.MyCall(Person1,18) //我叫Tom1
function mySymbol(obj){
//为添加的虚拟方法取一个唯一值为函数名
let unique=Date.now().toString(32).slice(0, 8)
if(obj.hasOwnProperty(unique)){
//如果该函数名存在递归调用
return mySymbol(obj)
}else{
return unique
}
}
实现apply
apply与call类似,只是将多参数合并为一个数组
Function.prototype.MyApply = function (context=window,...args) {
//context就是demo中的Person1
// 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
console.log(this)
//为添加的虚拟方法取一个唯一名
const fn=mySymbol(context)
context[fn] = this //Mycall里边的this就是我们虚拟的say方法
context[fn](args) //执行fn
delete context[fn] //删除方法
}
实现bind
bind与call,apply区别很大,该方法返回一个新函数,接收多个参数,支持柯里化形式传参
Function.prototype.myBind = function (context = window, ...args) {
const that = this
const fn = function () {
context = this instanceof that ? this : context
return that.apply(context, [...args, ...arguments])
}
if (this.prototype) {
fn.prototype = Object.create(this.prototype)
}
return fn
}