在JavaScript中,this它指的是函数调用的上下文(context)即调用的函数的执行环境。
在函数执行时,this 总是指向调用该函数的环境。要判断 this 的指向,其实就是判断 this 所在的函数是在哪个环境中。
this 出现的场景分为四类,简单的说就是:
- 有对象就指向调用对象
- 没调用对象就指向全局对象
- 用new构造就指向新对象
- 通过 apply 或 call 或 bind 来改变 this 的所指。
- 如果是函数,就看这个函数在哪个对象中。
function test() {
let a = 4;
console.log('第一层test:', this.a); // undefined
console.log('第一层this:', this); // 全局对象
// 闭包
function c() {
console.log('第二层c:', this.a) // undefined
console.log('第二层this:', this) // 全局对象
};
c();
};
test();
如上代码:因为不管 c
函数 或者 test
函数都是在全局对象中调用, 所以this 指向的都是 全局对象。即如果函数中,使用this, 那么这个this一定指的是包含这个函数的 对象。如下图:
test 函数 是存在 A对象中,所以,这个 this 指的就是 A 对象。
总结就是:如果是函数使用this,那就往出跳一层,跳出这个函数。看这个函数是属于哪个对象的,即这个函数是在哪个对象里面申明的。
函数调用的四种形式:
- 普通的函数调用
- 作为对象的方法调用
- 作为构造函数调用
- 通过它们的call()和apply()间接调用
1)作为函数
这是最通常的函数用法,属于全局性调用,因此this等于全局对象。
function f(){
window.x = 1;
console.log(this.x);
}
f(); // 1
对代码做些改变再看
var x = 1;
function f(){
console.log(this.x);
}
f(); // 1
console.log(window.x); // 1
window.x与this.x值相等。再变一下
var x = 1;
function f(){
this.x = -1;
console.log(this.x);
}
f(); // -1
console.log(x); // -1
在f()中给this.x赋值为-1,结果x的值跟着改变为-1,所以this等于全局对象。
2)作为方法
当函数作为某个对象的方法调用时,这时this的值就是这个对象。
function f(){
console.log(this.x);
}
var o = {
x: -1,
m: f
};
o.m(); // -1
o.x = 1;
o.m(); // 1
对象的属性值改变,f()里面this.x跟着改变。可以在f()里面打印一下this,看看结果呢!
3)作为构造函数
作为构造函数调用时,使用new关键字初始化一个实例对象,这时this等于这个实例对象。
function f(){
this.name = "zrn";
}
var o = new f();
console.log(o.name); // "zrn"
运行结果为”zrn”,表示这并非全局对象。变一下代码
var name = "window";
function f(){
this.name = "zrn";
}
var o = new f();
console.log(o.name); // "zrn"
console.log(name); // "window"
name的值互不干涉。
4)通过call()或者apply()调用
call()和apply()的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this的值。第一个参数(context)是函数运行的作用域,第二个参数是参数数组(argArr),不过使用call()时,要将这些参数逐个列举出来。如果未传递context,则context是全局对象(啊,说的有点多了)
var name = "window";
function f(){
console.log(this.name);
}
var o = {name: "zrn"};
f.call(); // "window", this指的是window
f.apply(o); // "zrn", this指的是对象o