为什么要使用bind,apply,call
简单的来说就是改变this指向,他们都属于函数的方法,所以只有函数才可以调用bind,call,apply
apply
apply接受两个参数,第一个参数是要指向的this对象,第二个参数是函数接收的参数,以数组的方式传入(可以把a想成Array)。 改变this指向后原函数立即执行,且只是临时改变一次this指向
let a = {name: 'xl'}
let b = {
name: 'xw',
sayName: function () {
console.log(this.name)
}
}
b.sayName.apply(a) // 'xl'
注意: 当传第一个参数是null或者undefined的时候,默认指向window 浏览器下
fn.apply(null,[1,2]); // this指向window
fn.apply(undefined,[1,2]); // this指向window
实现apply
Function.prototype.myApply = function (context, args) {
context = context || window
const fn = Symbol() // 用Symbol来避免fn覆盖context上的属性
context[fn] = this // this指向调用myApply的函数
const result = context[fn](...args) // 通过上下文调用函数
delete context[fn]
return result
}
call
call接收多个参数,第一个参数是要指向的this对象,函数接收多个参数,以分隔的字符串形式传入。和apply一样改变this指向后原函数立即执行,且只是临时改变一次this指向
function fn(...args){
console.log(this,args);
}
let obj = {
myname:"张三"
}
fn.call(obj,1,2); // this会变成传入的obj
fn(1,2) // this指向window
注意: 当传第一个参数是null或者undefined的时候,默认指向window 浏览器下
fn.apply(null,[1,2]); // this指向window
fn.apply(undefined,[1,2]); // this指向window
实现call
Function.prototype.myCall = function (context, ...args) {
context = context || window
const fn = Symbol()
context[fn] = this
const result = context[fn](...args)
delete context[fn]
return result
}
bind
bind和call相似,第一个参数是this指向,传入的也是一个参数列表 bind不会立即执行,而是返回一个改变this指向后的函数的拷贝,参数可以分多次传入
function fn(...args){
console.log(this,args);
}
let obj = {
myname:"张三"
}
fn.bind(obj,'z')('w') // {myname: "张三"} ["z", "w"]
实现一个bind
Function.prototype.myBind = function (context, ...args) {
context = context || window
const fn = this // this指向调用myBind的函数
// 返回当前函数的引用
return function (...newArgs) {
return fn.myApply(context, args.concat(newArgs))
}
}
面试题
let obj = {
a: 1,
func() {
console.log(this.a);
},
};
let obj2 = { a: 2 };
obj.func.bind(obj2).bind(obj)() // 2
ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数。
但是在这个新函数中,this
将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
也就是说多次调用bind,this指向最终的结果都是第一次调用bind时传入的参数。这就是为什么会输出2的原因。
使用
我们经常会看到在第三方库中大量使用,在日常搬砖的过程中可能并不常用,但还是有一些使用的地方可以注意
- 数组合并
let arr1 = [1,2,3]
let arr3 = [4,5,6]
[].push.apply(arr1, arr3) // [1,2,3,4,5,6]
- 防抖
function debounce (fn, delay = 500) {
// timer 写在闭包中,因此防抖也是闭包的一个应用
let timer = null
function f () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
return f
}
- 继承
function Person (name) {
this.name = name
}
function Man (name) {
this.age = 18
Person.call(this,name)
}
let boy = new Man('柯南')
conosle.log(boy.name, boy.age) // '柯南', 18
结尾
写的不好,还望各位大佬多多指教,感恩家人🙏