影响this绑定的四种情况
1、默认情况的绑定
function testC(){
debugger;
// 查看调用栈
let c = 10
console.log(this.testA)
}
testC()
2、当函数被一个对象拥有或者包含的时候,this默认指向这个对象(隐性绑定)
//如果调用位置被对象拥有或者是被对象包围,需要考虑上下文对象
function testD(){
debugger
console.log(this.a)
}
let obj = {
a:12,
test:function(){debugger; console.log(this.a)},
testTwo:testD
}
//注意这里的要求是完全的拥有或者是包含,但是以下情况也是可以的
// obj.test()
obj.testTwo()
注意:这里需要注意一个隐性绑定丢失的问题
function foo(a){
debugger;
this.a = a
}
let objA = {
a:1,
foo:foo
}
objA.foo(3)
这里通过objA调用foo是没有问题的,但是当把objA.foo当作参数传递的时候会出现this绑定丢失的情况
function foo(a){
debugger;
this.a = a
}
let objA = {
a:1,
foo:foo
}
// objA.foo(3)
let fooTwo = objA.foo
fooTwo(5)
回掉函数中也是如此
function foo(a){
debugger;
this.a = a
}
let objA = {
a:1,
foo:foo
}
setTimeout(objA.foo,5000)
3、显式绑定
通过apply和call显式的将this绑定到一个对象上
let obj = {
a:'a',
b:'b',
c:'c'
}
function testA(){
debugger;
console.log(this.a)
console.log(this.b)
console.log(this.c)
}
testA.call(obj)
通过硬绑定绑定解决this绑定丢失的问题
function foo(a){
// debugger;
this.a = a
}
let objA = {
a:1,
foo:foo
}
function testBind(func,obj){
return function(){
return obj.call(func)
}
}
let fooTwo = testBind(objA,foo)
setTimeout(fooTwo,5000)
我个人的理解是当函数被当作值进行传递的时候this的绑定关系会丢失,硬绑定通过闭包函数重新的将this关系进行绑定
可以使用js的内置方法bind方法来实现硬绑定
function foo(a){
this.a = a
debugger;
}
let objA = {
a:1,
foo:foo
}
let fooTwo = foo.bind(objA,3)
setTimeout(fooTwo,5000)
4、new 绑定 JavaScript中的new与其他面向对象中的new的方式有一些区别,其他面向对象中的new函数一般是类中的构造函数方法,而JavaScript中的new函数的调用则不同,它包括了以下的四步:
- 1、创建一个空的对象
- 2、创建原型链
- 3、将this绑定到这个空对象
- 4、如果没有返回则返回这个空的对象
5、特殊情况:箭头函数 JavaScript中的箭头函数并不是通过函数声明定义的,它的this是基于外层的作用域,及类似let that = this,这样的用法:
function foo(){
return (a)=> {
console.log(this.a)
}
}
let objB = {
a:8
}
var a = 2
let fooTwo = foo.call(objB)
fooTwo()
这里如果是普通函数的话应该是应用默认规则一,但是箭头函数的行为却不一样,它会根据外层的词法作用域去寻找,这里外层的foo绑定了objB:
箭头函数的this被绑定之后就不会在发生变化,类似词法作用域
function foo(){
return (a)=> {
console.log(this.a)
}
}
let objB = {
a:8
}
let fooTwo = foo.call(objB)
let objC = {
a:10
}
fooTwo.call(objC)
在回掉函数中也是如此
function foo(){
return (a)=> {
console.log(this.a)
}
}
let objB = {
a:8
}
let fooTwo = foo.call(objB)
let objC = {
a:10
}
setTimeout(fooTwo,5000)