在真正实现这个三个函数的方式其实是用c++来实现的,这边我们只是用js来简单模拟实现一下其中的思路,(还要一些边界情况需要判断)想要弄明白这个三个方法的实现需要先明白几点
- 构造函数的原型,如何往原型上添加方法(面试中常见的面试题:原型、原型链、构造函数实现继承与哪些方法)
- 在我们JavaScript中this的理解(难点)
- ES6中剩余参数
1. call的实现:
Function.prototype.FqCall = function(thisArg, ...argArray) {
// 获取到当前函数
var fn = this
// 这里是处理传递过来需要绑定的this如果是undefined和null的时候需要绑定到window上,但是还有一种传了0的时候不应该绑定到window上
thisArg = (thisArg !== undefined && thisArg !== null ) ? Object(thisArg) : window
// 将这个函数添加到传入需要绑定的参数中
thisArg.fn = fn
// 利用隐式绑定调用这个函数,将this绑定到传入的参数中
const result = thisArg.fn(...argArray)
delete thisArg.fn
// 将最终的结果进行返回
return result
}
function foo(num1, num2, num3) {
console.log('foo被调用了', this, num1, num2)
return num1 + num2
}
const result = foo.FqCall({name: 'fang'}, 10, 20)
console.log(result) // 30
2.apply的实现:
其实逻辑跟call差不多,只是处理参数有一点区别而已
Function.prototype.FqApply = function(thisArg, argArray) {
// 1. 获取到需要执行的函数
const fn = this
// 处理需要绑定的this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
thisArg.fn = fn
//这里是为了处理如果没有传递参数的情况,因为不传的情况argArray的值就是undefined,不能将undefined进行展开运算符
const arr = argArray || []
const result = thisArg.fn(...arr)
delete thisArg.fn
return result
}
function sum(num1, num2) {
console.log('sum函数被调用了', this, num1, num2)
return num1 + num2
}
const result = sum.FqApply({name: 'fang'}, [10, 20])
console.log(result)
function bar() {
console.log('bar被执行了')
}
bar.FqApply({name: 'fang'})
3.bind的实现:
Function.prototype.FqBind = function(thisArg, ...argArray) {
const fn = this
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
return function proxyFn(...arrList) {
thisArg.fn = fn
// 参数合并,因为我们在调用系统的bind的时候参数其实是可以分开传递的
const arr = [...argArray, ...arrList]
const result = thisArg.fn(...arr)
delete thisArg.fn
return result
}
}
function sum(num1, num2, num3, num4){
console.log('sum函数被调用了:' , this, num1, num2, num3, num4)
return num1 + num2 + num3 + num4
}
const result = sum.FqBind({name: 'sum'}, 10, 20)
console.log(result(30, 40))