相信不少小伙伴在面试中,都会被问到怎么改变this的指向呢,然后你说:call、apply、bind
。
面试官:介绍一下这三者的区别
UP: 来来来,我给你手写一个
定义一个function
function fn(arg1, arg2, arg3) {
console.log('fn被执行', this, arg1, arg2, arg3)
return arg1 + arg2 + arg3
}
call() 接收多个参数
//调用fn.Mycall() 隐式调用 this指向Mycall函数调用者
// 接收 this 传参 剩余参数 rest parameters
// 展开运算符 arr = ['1','2','3'] ...arr
Function.prototype.Mycall = function(thisArg, ...args) {
//获取被执行的函数
var fn = this
//thisArg为传参进来的指定this
//这里考虑thisArg类型不确定问题以及thisArg为空或不传值的情况 使用Object()方法
var thisArg = thisArg ? Object(thisArg) : window
// 将需要被执行的函数绑定在指定的this上
thisArg.a = fn
// 执行函数 并返回结果
var result = thisArg.a(...args)
console.log(thisArg, result) // Number {123, a: ƒ}
//因为给a等于一个函数 所以这里会多一个f 可以执行完删除 也可以不必理会
// delete thisArg.a
return result
}
//fn 调用 Mycall()
// var ccc = fn.Mycall(123, 3, 5, 7)
// console.log(ccc) // 15
apply() 接收一个数组
//数组入参
Function.prototype.Myapply = function(thisArg, argArray) {
var fn = this
// 考虑 thisArg 没有传参或者为空的情况
var thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
thisArg.a = fn
// 考虑 argArray 没有传参的情况
argArray = argArray || []
var result = thisArg.a(...argArray)
return result
}
// var ccc = fn.Myapply('abc', [3, 5, 7])
// console.log(ccc) // 15
bind() 接收多个参数并返回一个新的函数
Function.prototype.Mybind = function(thisArg, ...argArray) {
var fn = this // 要执行的函数
var thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
//bind 生产一个新函数
function proxyFn(...args) {
thisArg.a = fn
var bindargs = [...argArray, ...args] // 或者concat
console.log(bindargs) // [3, 5, 7, 1, 2]
var result = thisArg.a(...bindargs)
return result
}
return proxyFn //bind方法返回一个函数
}
// var ccc = fn.Mybind('bind', 3, 5, 7)
// ccc(1, 2)