我们知道在JavaScript里面有关于this的指向的问题,原生JavaScript里面也有四种绑定方式,
(1)默认绑定
(2)隐式绑定
(3)显示绑定(通过call,apply,bind等实现)
(4)new关键字绑定
下面我们主要对显示绑定来进行实现以及说明
一.call方法的实现
我们知道call可以改变this的指向
function foo(a){
console.log('foo函数',a)
}
foo.call('zb',10)
原本在执行的时候,foo默认被全局对象执行,在浏览器里面是window对象,在node里面是global对象,现在我们通过call方法将this指向改变为zb这个对象。
所以我们想通过原生js实现这个call方法具体实现如下,我们将我们模拟的这个函数挂载到Function这个对象上,方便我们调用。
Function.prototype.zbCall = function(){
//这里的this指向是被执行的函数
let fn = this
fn()
}
function foo(a){
console.log('foo函数',a)
}
foo.zbCall()
可以看到foo函数被执行了
我们接着进行实现,现在我们需要考虑zbCall函数的第一个参数,第一个参数是this的指向,第二个参数是被执行函数的参数所以我们加入形参thisArg和args
Function.prototype.zbCall = function(thisArg,...args){
//这里的this指向是被执行的函数
let fn = this
//如果zbCall函数的第一个参数为空或者未定义,我们需要进行处理,将它默认指向全局对象
thisArg = (thisArg !== undefined && thisArg !== null) ?Object(thisArg) :window
thisArg.fn = fn
//执行函数,
const result = thisArg.fn(...args)
delete thisArg.fn
//将执行结果返回
return result
}
function foo(a){
console.log('foo函数',a,this)
}
foo.zbCall(null,10)
说明没有问题
二.apply的实现
apply的实现和call基本一样,唯一不同的是apply函数的第二个参数是一个数组,只需要将上面的代码稍微修改就行
Function.prototype.zbApply = function(thisArg,args){
//这里的this指向是被执行的函数
let fn = this
//如果zbCall函数的第一个参数为空或者未定义,我们需要进行处理,将它默认指向全局对象
thisArg = (thisArg !== undefined && thisArg !== null) ?Object(thisArg) :window
thisArg.fn = fn
//执行函数,
const result = thisArg.fn(args)
delete thisArg.fn
//将执行结果返回
return result
}
function foo(a){
console.log('foo函数',a,this)
}
foo.zbApply(null,10)
三.bind函数的实现
bind函数只是改变了this指向,在函数调用bind函数之后,会生成一个新的函数,
Function.prototype.zbind = function(thisArg,...args){
let fn = this
thisArg = (thisArg !== undefined && thisArg !== null) ?Object(thisArg) : window
return function Fbind(...args2){
thisArg.fn = fn
let final = [...args,...args2]
let result = thisArg.fn(...final)
delete thisArg.fn
return result
}
}
function foo() {
console.log('foo函数', this);
}
function sum(a, b, c, d) {
console.log(a, b, c, d);
}
let newsum = sum.zbBind('zb', 10, 20)
let res = newsum(30, 40) //10 20 30 40
//改变了this的指向,并且生成了新的函数
let s = foo.bind('1111')
s() // foo函数 [String: '1111']