在刚开始学习js时,this指向问题就是一个大难题,啥时候指向实例对象,啥时候指向全局对象(一般是window 对象)。下面让我们通过几个例子来搞懂this指向问题。
说明一下,这篇文章是基于es5语法的,不包括es6中的箭头函数。后面会有一章专门讲箭头函数。
同时是在非严格模式环境下的结果。后面会有一章专门将严格模式和非严格模式的区别。
开头先说一下结论,this指向的对象在函数定义时是确认不了的,只有在函数被调用时才能确定。而实际上this指向的也就是函数的调用对象。
例子1
function example1() {
var age = 18;
console.log(this.age); //undefined
console.log(this); //Window
}
example1();
- 这个函数在全局作用域中直接调用,可以看到函数中的this指向的是全局对象window。this.age也没有指向函数内部属性age,输出的值是undefined。
- 上面这个例子其实可以等效的改写成下面这样,更加直观一点。
function example1() {
var age = 18;
console.log(this.age); //undefined
console.log(this); //Window
}
window.example1();
- 这里就可以很清楚的看到调用example1函数的对象是window,这确认符合我们最开始说的结果this指向的就是函数调用的对象。
- 在非严格模式下,全局定义的函数,变量都属于window对象。
例子2
var example2 = {
age: 18,
printAge: function() {
console.log(this.age);
}
}
example2.printAge(); // 18
- 在这个例子中我们通过对象字面量定义了一个对象example2。我们通过example2.printAge()的方式来调用它。
- 可以看到最后this.age输出的是对象体内变量age的值。此时this指向的就是example2这个实例对象。
例子3
var example3 = {
age: 18,
printAge: function() {
console.log(this.age);
}
}
window.example3.printAge(); // 18
- 这个例子跟例子2相比就是在调用栈上多了window这个对象。但是结果跟例子2还是一致的。
- 这个例子要说明的就是不管函数有多少个上级调用对象,影响this指向的只是直接调用函数的对象。
例子4
var example4 = {
age: 18,
printAge: function() {
console.log(this.age);
}
}
var temp = example4.printAge;
temp(); // undefined
- 在这个例子中我们把example4.printAge赋值给了变量temp。其中exmplae.printAge的值是printAge这整个函数。可以理解为temp变量指代的就是printAge函数。此时temp的直接调用对象就是window。所以结果就是undefined了。
- 通过这个例子更加说明了一点,this 的指向是动态的,只有在调用时才能被确定,只跟调用函数的对象有关。
例子5
function example5() {
this.age = 18
}
var temp = new example5();
console.log(temp.age); // 18
- 这个例子涉及构造函数中this的指向问题。我们先说一下通过new调用构造函数时的过程。
- 创建一个对象。
- 把构造函数的作用域赋给这个对象。
- 执行构造函数中的代码。
- 返回新对象。
- 其中就是绑定作用域这么一个过程。说白点就是this指向的就是构造函数。(ECMAScript中可以改变this指向的还有call,apply和bind,后面我会写一篇文章讲讲它们的区别。)
- 还是那句话看调用者就谁,谁就是this指向的对象。
这篇文章大家如果有不理解的地方,认为有错误的地方或者有其他补充的地方,欢迎大家在下面多多评论,多多探讨。我会第一时间回复~与君共勉。