极简实现系列——是用最简单的代码实现一些常见的方法,目的是为了帮助理解原理,所以并没有考虑太多限制条件
之前写过call和apply的原理实现,bind的实现原理也类似。先来看看MDN上关于bind的介绍:
bind()
方法创建一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
看个简单的例子:
let obj = {
value: 1
}
function fn(a,b){
console.log(this.value)
}
let fn2 = fn.bind(obj)
fn2() // 1
可以看出跟call/apply的区别就是bind是返回一个函数。我们根据之前在《自己简易实现系列——手写call和apply》中的思路,可以简易的写出第一版的代码
第一版
Function.prototype.myBind = function(context) {
let that = this
return function(){
return that.apply(context)
}
}
let obj = {
value: 1
}
function fn(){
console.log(this.value)
}
let fn2 = fn.myBind(obj)
fn2() // 1 输出1,说明改变指向成功
看到结果是可以了,粗糙的第一版已经完成了
第二版
bind是可以传参数的,而且通过bind创建的新函数也可以带参数。我们看一个例子:
let obj = {
value: 1
}
function fn(a,b){
console.log(this.value)
console.log(a)
console.log(b)
}
let fn2 = fn.bind(obj, 'a')
fn2('b') // 1 a b
可以看到bind很神奇,可以在创建的时候传一个参数,创建后的新函数调用时再传另一个~。 我们根据这个特性再来改造下
Function.prototype.myBind = function(context) {
let that = this
let arg =[].slice.call(arguments, 1)
return function(){
let arg2 = [].slice.call(arguments) // 此时的argument表示bind创建后的函数的参数
return that.apply(context, arg.concat(arg2))
}
}
let obj = {
value: 1
}
function fn(a, b){
console.log(this.value)
console.log(a)
console.log(b)
}
let fn2 = fn.myBind(obj, 'a')
fn2('b') // 1 a b
当然也可以用es6的rest参数来简化一下
Function.prototype.myBind = function(context, ...arg) {
let that = this
return function(...arg2){
return that.apply(context, [...arg, ...arg2])
}
}
let obj = {
value: 1
}
function fn(a, b){
console.log(this.value)
console.log(a)
console.log(b)
}
let fn2 = fn.myBind(obj, 'a')
fn2('b') // 1 a b
over~
当然bind还有一个比较复杂的特性就是当 bind 返回的函数作为构造函数的时候,bind绑定的this会失效,但是其他的参数依然有效 ,这部分内容等下次有时间再来完善~