答应我,搞懂call、apply好嘛

总结一句话:改变函数内部的 this 指向,并执行函数。

call、apply 是 Function 构造函数原型对象上的方法,所有的函数(包括call)都可以调用 call 和 apply。

call

先看一下原生call的效果(运行在浏览器环境)

let context = {
    name: 'z'
}
// 全局环境, 用let变量不会挂在window上
var name = 'j'
function say(age,sex){
    console.log(this.name+age+sex)
}
say.call(context,12,1)	// z121
say.call(null,18,0)	// j180

我们稍加分析,将成call做的事情拆解为三步:

  1. 先把方法say挂在call的第一个参数,context的属性下(context指上下文,this所指向的新执行环境)
  2. 执行 context.say(age, sex),并传入参数
  3. 删除 context.say,不能侵入性修改原数据

按照这三步我们复现一下 写一个myCall

Function.prototype.myCall = function(context) {
    // 设置一个参数默认值,浏览器环境默认window,node环境是global
    context = context ? context : window;
    // 原函数调用call函数,所以this指向原函数本身,即 say
    context.fn = this
    // 获取除掉第一个context外的参数
    let args = []
    for(let i=1;i<arguments.length;i++){
        args.push('arguments['+i+']')
    }
    // 调用函数
    var result = eval('context.fn('+ args +')')
    // 删除增加的属性
    delete context.fn
    // 返回执行结果
    return result
}

执行一下

let context = {
    name: 'z'
}
// 全局环境, 用let变量不会挂在window上
var name = 'j'
function say(age,sex){
    console.log(this.name+age+sex)
}
say.myCall(context,12,1)	// z121
say.myCall(null,18,0)	// j180

完美复现,okkkk~~~

解释一下eval问题,之所以这样写,是因为之前还没有结构啊,Array.from类数组转数组语法什么的。eval遇到数组会调用 args.toString(),解析后是这样的

 context.fn(arguments[1], arguments[2], ...)

apply

apply与call基本相同,只是额外参数是数组形式

Function.prototype.myApply = function (context,args){
	context = context ? context : window
	context.fn = this
	
	// 判断是否传递额外参数,如果没有直接执行函数即可
	if(!args) return context.fn()
	var result = eval('context.fn('+ args +')')
	delete context.fn
	return result
}

bind

bind下篇文章讲,关注一下哈哈~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值