Fork me on GitHub

JS-this指向

确定 this 指向

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。

全局上下文

  • 浏览器环境,严格模式或非严格模式this指向Window对象。
1
2
3
4
5
6
7
<script>
console.log('非严格模式')
console.log('this === window', this === window)
console.log('this.document === document', this.document === document)
this.a = 'test';
console.log('this.a === window.a', this.a === window.a)
</script>
  • node 环境,指定空对象{}
1
console.log("this", this);//window

全局作用域

函数上下文

普通函数

  • 浏览器环境,非严格模式,this指向window;
1
2
3
4
5
6
7
8
9
10
<script>
function a() {
console.log('非严格模式-函数')
console.log('this === window', this === window)
console.log('this.document === document', this.document === document)
this.a = 'test';
console.log('this.a === window.a', this.a === window.a)
}
a()
</script>

非严格模式-函数

  • 浏览器环境,严格模式,this指向undefined
1
2
3
4
5
function a() {
'use strict';
console.log('严格模式-函数',this)
}
a()

严格模式-函数

  • node 环境,this指向global
1
2
3
4
function foo() {
console.log("foo", this);//global
}
foo();

箭头函数

  • 浏览器环境
    箭头函数中没有this绑定,必须通过查找作用域链来决定其值。 如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象。
1
2
3
4
5
6
7
8
9
10
11
12
<script>
function b() {
this.c = 'test';
let that = this;
const a = () => {
console.log('箭头函数')
console.log('this.c === that.c', this.c === that.c)//true
}
a()
}
b()
</script>

箭头函数

  • node环境
    与浏览器环境一样
1
2
3
4
5
6
7
8
function a() {
this.a = "a";
let foo = () => {
console.log("foo", this.a);
};
foo();
}
a();

对象的方法

如果函数作为对象的方法调用,this 指向的是这个上级对象,即调用方法的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let name = 'window';
let doSth = function () {
console.log(this.name)
}
let student = {
name: 'student_name',
doSth: doSth,
other: {
name: 'other_name',
doSth: doSth
}
}
student.doSth(); //student_name
student.other.doSth(); //other_name
student.other.doSth.call(student); //student_name

call 方法执行函数,传入的第一个参数就是 this 的指向
如果将对象方法赋值给变量就变成了普通函数

1
2
3
4
5
6
7
8
let student = {
name: 'student_name',
doSth: function () {
console.log(this)
}
}
let stu_doSth = student.doSth;
stu_doSth(); //window

构造函数中的 this

构造函数使用 new 调用的时候,如果没有返回 function 或者是 object,this 指向当前的实例。

1
2
3
4
5
6
7
function showName(name) {
this.name = name
}
let obj = new showName('obj');
let obj1 = new showName('obj1');
console.log(obj.name);//obj
console.log(obj1.name);//obj1

call、apply 和 bind

this 是第一个参数,bind 不会执行,返回绑定好的函数。apply 的第二个参数是数组。

  • 如果第一个参数值是undefinednull,严格模式下 this 的值为传入的值nullundefined,非严格模式下,this 指向全局对象(node 环境为 global,浏览器环境为 window)。
  • 如果第一个参数没有传入,非严格模式,指向 window/global,严格模式指向undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {
a: 1,
b: 3
}
console.log(add.call(o, 5, 7)) //16
console.log(add.bind(o, 1, 2))
//ƒ add(c, d) {
//return this.a + this.b + c + d;
//}
console.log(add.apply(o, [10, 20])) //34
  • 如果第一个参数值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
1
2
3
4
5
var doSth = function (name) {
console.log(this);
console.log(name);
};
doSth.call(2, "name"); // Number{2}, 'name'

事件处理函数

在严格模式下,在事件处理函数中,this 指向触发事件的目标对象。

1
2
3
4
5
"use strict";
let btn = document.getElementById('loginBtn');
btn.onclick = function (e) {
console.log(e.target === this)//true
}

总结

如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。 找到之后
就可以顺序应用下面这四条规则来判断 this 的绑定对象。

  • new 调用:绑定到新创建的对象,注意:显示 return 函数或对象,返回值不是新创建的对象,而是显式返回的函数或对象。
  • call 或者 apply( 或者 bind) 调用:严格模式下,绑定到指定的第一个参数。非严格模式下,null 和 undefined,指向全局对象(浏览器中是 window),其余值指向被 new Object()包装的对象。
  • 对象上的函数调用:绑定到那个对象。
  • 普通函数调用: 在严格模式下绑定到 undefined,否则绑定到全局对象。
-------------本文结束感谢阅读-------------