普通函数
普通函数中的this:
1.this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是obj
2.在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window
3.在严格模式下,没有直接调用者的函数中的this是 undefined
4.使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象
是谁调用的,this就指向谁
由运行时的执行环境来决定
var obj = {
name : "zhar",
say : function(){
console.log(this.name);
}
}
obj.say(); //zhar
//对比
//1.
var name = 'tom';
var obj = {
name : "zhar",
say : function(){
console.log(this.name);
}
}
var fun = obj.say;
fun();//输出 tom
//fun定义在全局环境下,即window.fun()
//再次说明了this的指向是由运行时的执行环境来决定的
//2.
var name = 'tom';
var obj = {
name : "zhar",
say : function(){
return function(){
console.log(this.name);
}
}
}
obj.say()();
// tom
构造函数环境
构造函数中的this 会指向创建出来的实例对象。
使用new 调用构造函数时,会先创建出一个空对象,然后用call函数把构造函数中的this指针修改为指向这个空对象。执行完环境后,空对象也就有了相关的属性,然后将对象返回出去。
事件对象
在 DOM 事件中使用 this,this 指向了触发事件的 DOM 元素本身
立即执行函数
立即执行函数的this指向是window(非严格模式下),因为作为一个匿名函数,在被调用的时候,我们往往就是直接调用,因此它的this是非常确定的
var tes = 2;
function a() {
var tes = 1;
(function(){
console.log(tes);
console.log('this:', this);
})()
}
a();
// 1
// window对象
箭头函数
没有自己的this,从自己的作用域链的上一层继承this(跟随上一层的this变而变)。
简单来说:箭头函数的this指向,通过定义箭头函数的地方向上寻找,找到第一个嵌套该箭头函数的普通函数
该普通函数在执行的过程中会形成自己的执行上下文,其中包含三个重要的属性:变量对象,作用域链,this
箭头函数的this就是继承该普通函数的this;如果一直找到全局环境,那么箭头函数的this就是指向全局对象。
由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,所以箭头函数的this一经捕获就不再发生变化,
call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
function Person() {
this.name = '11'
this.age = 23
setTimeout(function (){
console.log(this); // window
console.log(this.name + " + " + this.age); //undefined
}, 2000)
}
let p = new Person();
function Person2() {
this.name = '11'
this.age = 23
setTimeout(() => {
console.log(this); // Person2
console.log(this.name + ' + ' + this.age) // 11 + 23
}, 2000)
}
let p2 = new Person2();
function Person3() {
this.name = '11'
this.age = 23
var _this = this
setTimeout(function () {
console.log(_this); // Person3
console.log(this); // window
console.log(_this.name + " + " + _this.age); // 11 + 23
}, 2000)
}
let p3 = new Person3();
------------------------------------------------------------------------------------------------------------
var obj = {
i: 10,
b: () => console.log(this.i, this), // this捕获的是obj所在的上下文环境 此处为window
c: function () {
console.log(this.i, this);
}
}
// b函数为箭头函数,定义时所在的上层执行上下文为全局环境,所以this执行window
obj.b(); // undefined window
obj.c(); // 10 {i:10,b:f,c:f}
let p = {
a: function () {
var i = 22;
var obj = {
i: 10,
b: () => {
console.log(this.i, this)
},
c: function () {
console.log(this.i, this)
}
};
obj.b();
obj.c();
},
tes: 1111
}
// p.a();
/*
p.a()执行,由于p是a的直接调用者,所以a的this指向p
执行a的函数体,obj.b(), obj.c()
obj.b()
b函数为箭头函数 定义时所在的上层执行上下文为a函数,所以会继承a函数的this
打印 p.i 和 p对象的定义 即undefined 和 { a: [Function: a], tes: 1111 }
obj.c()
c函数为普通函数,所以c函数中的this指向obj,
所以打印10 和 obj对象的定义 { i: 10, b: [Function: b], c: [Function: c] }
*/
let windowCall = p.a;
windowCall();
/*
将windowCall指向p.a,执行windowCall,由于无直接调用者,所以a的this指向window
执行a的函数体,obj.b(), obj.c()
obj.b()
b函数为箭头函数 定义时所在的上层执行上下文为a函数,所以会继承a函数的this
打印 window.i 和 window对象的定义
obj.c()不变
c函数为普通函数,所以c函数中的this指向obj,
所以打印10 和 obj对象的定义 { i: 10, b: [Function: b], c: [Function: c] }
*/