javascript-this

1 前言:

this 是javascript中一个重要的关键词 根据函数执行时候上下文的不同this代表的含义也不同

2 为什么使用this

this提供了优雅的方式来隐式的传递一个对象的引用

this是在运行时候绑定的,并不是在编写的时候绑定的,它的上下文取决于函数调用时的条件。

this绑定规则有4种

3 绑定机制

3.1 不带任何修饰的函数调用 -默认绑定

没有任何修饰,即没有使用apply/call,也没有显式的对象包含 比如 object.somefunction()

1
2
3
4
5
6
7
8
a = 1
function fun(){
console.log(this.a)
}

fun()
//使用默认绑定,非严格模式下是全局对象 window,
//调用window的a属性,即1;严格模式下为undefined,发生错误

3.2 隐式绑定

被对象拥有或者包含时候使用隐式绑定,this指向调用对象

1
2
3
4
5
6
7
8
9
10
let a = 2
function fun(){
console.log(this.a)
}
const obj = {
a:1,
fun:fun
}

obj.fun()//1

但此时需要注意一种隐式丢失的情况

1
2
3
4
5
6
7
8
9
10
11
let a = 2
function fun(){
console.log(this.a)
}
const obj = {
a:1,
fun:fun
}

let anotherfun = obj.fun
anotherfun()//2,anotherfun是fun的别名或者说引用,此时没有任何修饰,使用默认绑定

对象属性引用链中只有最后一条会影响调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

function foo(){
console.log(this.a)
}

let obj2 = {
a:42,
foo:foo
}

let obj1 = {
a:2,
obj2:obj2
}

obj1.obj2.foo()//42

3.3 显示绑定

使用call/apply/bind进行硬绑定

1
2
3
4
5
6
7
8
9
10
11
12
function foo(){
console.log(this.a)
}

obj={
a:1
}

foo.call(obj) // 1
foo.apply(obj) // 1
let foo_with_obj = foo.bind(obj)
foo_with_obj()//1

3.4 new关键词绑定

new的执行过程
1 创建一个全新的对象
2 绑定原型链
3 新对象绑定到函数调用的this
4 函数没有返回其他对象,那么返回新对象

可以看到第3步中,new关键词,会将新对象绑定到调用函数的this上

4 绑定的优先级

new > 显示 > 隐式 > 默认

证明 显式 > 隐式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function foo(){
console.log(this.a)
}

obj1= {
a:1,
foo:foo
}

obj2={
a:2,
foo:foo
}

obj1.foo()//1
obj2.foo()//2
obj1.foo.call(obj2)//2
obj2.foo.call(obj1)//1

证明 new优先级高于显示绑定

1
2
3
4
5
6
7
8
9
10
11
12
function foo(something){
this.a= something
}

let obj = {}
let bar = foo.bind(obj)
bar(2)
console.log(obj.a)//2

let baz = new bar(3)
console.log(obj.a)//2
console.log(baz.a)//3

5 apply/call/bind 使用 null作为绑定对象

此时为默认绑定
如果你的函数不会修改this,那么可以放心传入
否则,你的函数会在全局对象上产生可怕的修改

1
2
3
4
5
6
7
8
9
10
function foo(x){
this.x = x
}

let obj = {}
foo.apply(obj, [2])
console.log(obj.x)//2

foo.apply(null, [3])
console.log(global.x)// 2 3

5.1 避免不必要的默认绑定

可以使用一个空的DMZ对象进行绑定

1
2
3
4
5
function foo(){
this.a = 1
}
valet SPECIAL_OBJ = Object.create(null)//空对象{}
foo.call(SPECIAL_OBJ)