this
在讲这些this家族成员之前,我们有必要先了解一下this指针,如果还有小伙伴不清楚的,可以去看看这篇文章浅谈this,里面有我们平常遇到的this使用情况。
大同小异
bind、call、apply可以说大同小异,首先,他们都是用来指定一个函数内部的this的值,只是在用法上面略微有些差异。
首先call() 方法接收的语法和作用与apply()方法相似,区别就在于,call()接收的是一个参数列表,而apply()方法接收的是一个包含多个参数的数组
let obj = {
a: 1,
get: function() {
return 2
}
let o = obj.get
o.call({}, 1, 2)
o.apply({}, [ 1, 2 ])
bind的第二个之后的参数为调用它的函数的参数列表,而bind()函数会返回一个新的方法,并且该方法满足柯里化,仍可以传递参数,但这个方法的this不可被call、apply、bind改变,如果使用new实例化,那么原本通过bind绑定的this指向的对象会失效,this将指向到新实例化的对象上,且可以使用原方法原型链上的属性或方法。
手写思路
记住精髓,函数干的事情就是改变this指针的指向,这些函数被调用的时候必须是this,那么此时手写函数的时候,我们只需要将其挂载在该this上,并且执行掉,之后再将这个属性删除,那么就可以悄然的改变this指向,废话不多说我们上代码!
call
Function.prototype.mycall = function(context){
//调用call的是this mycall需要被a调用,mycall的this将会指向a函数
if(typeof this !== 'function'){
//如果调用的不是一个函数,报错
throw new TypeError('Error')
}
context = context || window
//把调用的那个函数获取到,复制到context对象中去
context.fn = this //获取a函数作为fn属性
context.fn() //调用fn属性,执行函数a
delete context.fn //删除fn
}
a.mycall(b)
apply
var b = {
name:'aa'
}
function a(e,ee) {
console.log(this.name);
console.log(e + ee);
}
// a.call(b) //b.a()
//a.call() 不传参数指向window
//函数才能调用,函数原型链
Function.prototype.myapply = function(context){
//调用call的是this mycall需要被a调用,mycall的this将会指向a函数
if(typeof this !== 'function'){
//如果调用的不是一个函数,报错
throw new TypeError('Error')
}
context = context || window
//把调用的那个函数获取到,复制到context对象中去
context.fn = this //获取a函数作为fn属性
let result = context.fn(...arguments[1]) //调用fn属性 //防止a函数有返回值
delete context.fn //删除fn
return result
}
a.myapply(b,[1 ,2])
bind
Function.prototype.mybind = function(context){
//调用call的是this mycall需要被a调用,mycall的this将会指向a函数
if(typeof this !== 'function'){
//如果调用的不是一个函数,报错
throw new TypeError('Error')
}
let _this = this
context = context || window
let args = [...arguments].slice(1) //除了第一个参数之后的
return function F(){ //即c的函数
//this代表的函数执行
_this.apply(context,args.concat(Array.from(arguments))) //concat() 字符串拼接
//调用a b.a()
// _this.apply(context,args.concat(...arguments))
}
}
let c = a.mybind(b,1)
总结
总之,掌握原理还是很重要的,我是小白,我们一起学习js 文章如有错误,请在下方指出,谢谢!