本文需要读者熟悉call和apply的基本使用以及this的指向相关知识
首先来看一段代码
<script>
var value = 'window'
var obj = {
value:'obj'
}
function show(){
console.log(this.value)
}
show()
show.call(obj)
show.call(null)
</script>

接着思考下面的代码
<script>
var value = 'window'
var obj = {
value:'obj'
}
function show(){
console.log(this.value)
}
obj.show = show
obj.show()
delete obj.show
</script>
这段js代码中后面三行(script标签以上)模拟了show.call(obj)的功能,先在obj上定义一个属性,属性值是show函数,熟悉this指向的同学就会明白此时执行obj.show()的话show方法是obj对象上的一个方法,那么此时show方法内部的this指向的就是obj。最后将obj中的show属性用delete移除。
以此为基础
<script>
var value = 'window'
var obj = {
value:'obj'
}
function show(){
console.log(this.value)
}
Function.prototype.newCall = function(ctx) {
// 这个this指向的就是函数实例对象中的this(此时是show函数,我们通过this可以拿到show函数实例对象)
// 将函数实例对象添加到某个对象上(此时等同于obj.fn = show)
ctx.fn = this
// 执行这个对象上的那个函数(相当与obj.show())
// 此时这个函数里面的this指向的就是这个要改变的对象(show函数实例里面的this指向的是obj对象)
ctx.fn()
// 删除对象的方法属性(删除在前面添加都obj里面的fn方法)
delete ctx.fn
}
show.newCall(obj)
</script>
上述的方法可以实现call中改变this的功能,但是用过call的读者应该发现,call方法不只能接受一个参数。
接着实现完整的call方法
具体实现需要具备arguments和展开运算符相关知识
<script>
var value = 'window'
var obj = {
value:'obj'
}
function show(name,age){
console.log(this.value)
return {
name,
age
}
}
/*****call方法*****/
var result = show.call(obj,'fu',21)
console.log(result)
/*****自定义方法*****/
Function.prototype.newCall = function() {
// 获取arguments中的第一个元素,也就是传入的第一个实参,如果为null的话默认是window
var ctx = arguments[0] || window
// 这个this指向的就是函数实例对象中的this(此时是show函数,我们通过this可以拿到show函数实例对象)
// 将函数实例对象添加到某个对象上(此时等同于obj.fn = show)
ctx.fn = this
// 创建一个数组,将arguments中的值放入数组中
var arr = new Array(...arguments)
// 将数组中第一个元素去掉
arr.splice(0,1)
// 执行这个对象上的那个函数(相当与obj.show('fu',21))
// 此时这个函数里面的this指向的就是这个要改变的对象(show函数实例里面的this指向的是obj对象)
// 此时不能直接return, 否则后续代码不能继续执行
var result = ctx.fn(...arr)
// 删除对象的方法属性(删除在前面添加都obj里面的fn方法)
delete ctx.fn
// 返回方法执行的结果
return result
}
var result2 = show.newCall(obj,'fu',21)
console.log(result2)
</script>
最后实现apply
知道了怎么实现call,实现apply就非常容易了
Function.prototype.newApply = function(ctx,argsArr){
ctx.fn = this || window
if(!argsArr) {
var result = ctx.fn()
} else {
var result = ctx.fn(...argsArr)
}
delete ctx.fn
return result
}
总结:要学会自定义call和apply,最关键的还是熟悉js中this的指向问题
网友评论