欢迎光临
我们一直在努力

【前端手撕】call

call是改变this指向的方法,传入的参数是要指向的对象和函数需要的参数序列。

改变this指向还可以用apply和bind,区别如下:

方法传参方式执行时机返回值
call 参数序列(逐个传入) 立即执行 函数执行的结果
apply 参数数组(或类数组) 立即执行 函数执行的结果
bind 参数序列(逐个传入) 返回新函数,稍后执行 绑定了 this 的新函数

代码

简易版

Function.prototype.callSimple = function (context, …args) {
context = context || window // 确认上下文,如果没有上下文就默认window
context.fn = this // 把当前函数赋值给上下文的fn属性(临时属性)
const res = context.fn(…args) // 调用函数,传参
delete context.fn // 删除临时属性
return res
}

健壮版

Function.prototype.call = function (context, …args) {
// 如果上下文是null或undefined,就默认window;否则用Object()转换为对象
// Object()包对象返回原对象,包原始类型返回对象包装类型。这是因为简单数据类型不能挂载属性,对象才可以
context = context !== null && context !== undefined ? Object(context) : window
let tag = Symbol('call') // Symbol()创建一个唯一的符号值,避免与其他属性冲突/覆盖
context[tag] = this // 把当前函数赋值给上下文的tag属性(临时属性)
const res = context[tag](…args) // 调用函数,传参。这里使用方括号是因为tag是一个符号值,不能用点号
return res
}

Tips

1. bind传参数可以先传一部分参数,返回新函数,下次再传剩下的。这种特性叫函数柯里化(Currying)

2. 如果bind返回的新函数被new构造调用了,this会失效。因为new的优先级高于bind(但也只有new比bind高)

function Person(name) {
this.name = name;
}
const BoundPerson = Person.bind({ name: '默认' }); // 试图绑定 this

const p = new BoundPerson('李四');
console.log(p.name); // 输出:李四

因为new强行创建了一个新对象作为this,bind绑定的this被覆盖了。

赞(0)
未经允许不得转载:171主机测评 » 【前端手撕】call
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址