介绍
简单点,说法的方式需要尽量简单!在JS中,bind、call、apply函数都是用来修改函数运行时的this指向。
语法示例: 更加详细用法可以看一下 MDN文档
function greet(name) {
console.log(`Hello, ${name}! My name is ${this.name}.`);
}
const person = { name: "John" };
greet.call(person, "Alice"); // 输出:Hello, Alice! My name is John.
区别
参数
bind在设置this绑定值后,传入的参数为参数列表,并且可以多次传参。call在设置this绑定值后,传入的参数为参数列表。apply在设置this绑定值后,传入的参数为数组。
执行时机
call、apply立即执行bind没有立即执行,而是返回一个this固定指向目标的函数
this指向状态
apply、call临时指向bind永久指向
手写bind函数
不是很完整但基本够用(mian试)
Function.prototype.bindMin = function(obj) {
const fn = this
if (typeof fn !== "function") return new TypeError("Error")
const args = [...arguments].slice(1)
return function Fbind() {
return fn.apply(this instanceof Fbind ? new fn(...arguments) : obj, args.concat([...arguments]))
}
}
分步解析
- 首先bind作为函数原型方法,它被实现在
Function对象的原型上。所以我们手动实现也需要在Function对象的原型上定义。 bindMin函数中的this指向谁?我们知道函数的指向是函数调用时才被确定的。bind是一个函数 方法,它是通过函数对象调用的,所以this指向调用它的函数对象。so,bindMin函数中的this将指向调用它的函数对象。- 判断调用
bindMin函数的调用者是否为函数!若不为函数者抛出一个错误。 - 由于
bind函数第一个参数为this指向的目标,往后才是我们需要的参数,所以需要剪掉第一个参数。[...arguments].slice(1) - 调用bind函数,返回一个已经改变this指向的函数。
- 当外部调用
Fbind的时候会返回fn.apply(括号中的内容暂时省略),这个立即调用函数。调用时进行判断,若外界是通过new Fbind()的方式调用的话,内部就new一个新的实例绑定this,否则就绑定到原来传入的obj。
手写call函数
Function.prototype.callMin = function (obj = window) { // 函数默认参数解决调用不传参的问题
// 判断调用者是否为函数
if (typeof this !== "function") return new TypeError("Error")
// 将函数(callMin的调用者)赋值给给obj对象的一个fn属性
obj.fn = this
// 获取参数列表
const args = [...arguments].slice(1)
// 将调用obj对象上的fn属性(调用这个fn函数)并传入参数
const res = obj.fn(...args)
delete obj.fn
return res
}
由于call和apply函数的this指向是临时的,所以在调用后需要删除掉obj对象上的fn属性。
为什么要把this赋值给传入的obj对象? 因为函数的this指向是在调用时被确定的,将this赋值给obj,调用fn属性时就是调用定义在对象中的函数。这个函数是通过对象调用的,所以this需要指向对象本身。so,need obj.fn = this。
同理可实现apply!
手写apply函数
Function.prototype.callMin = function (obj = window) {
if (typeof this !== "function") return new TypeError("Error")
obj.fn = this
const args = arguments[1] || []
const res = obj.fn(...args)
delete obj.fn
return res
}