this是函数内部的特殊对象之一(其他还有arguments、caller、new.target)。
this的 指向 或 值 是不确定的,取决于函数的调用方式。
在JavaScript中,this的指向有以下几种情况:
此外,this在使用 闭包 和 箭头函数 时的情况我们在后面介绍两者时再谈。
1.作为对象的方法调用
当函数作为对象的方法被调用时,this指向该对象。
const obj = {
name: 'obj',
getName: function () {
console.log(this.name);
}
}
obj.getName(); //obj
2.作为普通函数调用
当函数不作为对象的属性被调用时,this指向全局对象,浏览器中是window对象。
const name = 'window'
const getName = function () {
console.log(this.name);
}
getName(); //window
3.构造器调用
当函数被new调用时,this指向新创建的对象。
const Person = function (name) {
this.name = name;
}
const person = new Person('person');
console.log(person.name); //person
4.Function.prototype.call或Function.prototype.apply调用
当使用call或apply调用时,this指向传入的第一个参数。
const obj = {
name: 'obj'
}
const getName = function () {
console.log(this.name);
}
getName.call(obj); //obj
闭包(closure)是指访问了另一个函数作用域中的变量的函数。
创建闭包的最常见的方式就是在一个函数内部创建另一个函数,即嵌套函数。
const a4=4;
var a5=5;
const func1 = function (a3) {
const a2=2;
function func2() {
const a1=1;
return function func3(){
console.log(a1+a2+a3+a4+a5);
}
};
return func2();
};
const result=func1(3);
result();
外部函数的活动对象位于内部函数作用域链上的第二个,该作用域链直到全局执行上下文才终止。
活动对象是包含函数的所有局部变量的对象(包括arguments
对象),在函数调用时被创建,在函数执行完后被销毁,即只存在于函数执行期间。而在全局上下文中,这叫做变量对象。
[[Scopes]]
保存了函数的作用域链。
闭包读取函数内部的变量,这使得变量始终保存在内存中,不会在函数调用后被自动清除,这会导致内存泄漏,如果闭包的作用域中有大量的变量,会占用大量的内存。
箭头函数是ES6新增的语法,它的this指向是固定的,指向定义时所在的对象,而不是使用时所在的对象。
示例:
window.count=1;
function Counter() {
this.count = 0;
console.log(this);
this.add = function () {
this.count++;
}
}
var counter = new Counter();
setTimeout(counter.add, 1000);
setTimeout(function () {
console.log(counter.count);
console.log(window.count);
}, 2000);
输出结果为
Counter {count: 0}
0
2
奇怪,为什么输出结果是0和2,而不是1和1呢?
这是因为setTimeout中的this指向了window,而不是counter,所以counter.add()中的this.count++实际上是window.count++,而不是counter.count++。
解决方法:
1.使用bind绑定this
setTimeout(counter.add.bind(counter), 1000);
2.使用_this = this
保存this
function Counter() {
var _this = this;
this.count = 0;
console.log(this);
this.add = function () {
_this.count++;
}
}
3.使用箭头函数
function Counter() {
this.count = 0;
console.log(this);
this.add = () => {
this.count++;
}
}