Appearance
this 指针
前言
- 在 JavaScript this 是一个绕不开的话题,随着 ES6 的出现给 this 又增加的一定的难度,今天一步步分析的下 this 的指向问题
全局环境
- 在浏览器全局环境下的 this 始终指向 (window===self) 对象,并且用 var 声明的全局变量会挂载到 window 属性上,let、const 不会
js
var a = 10;
let b = 20;
console.log(this === window); // true
console.log(window === self); // true
console.log(window.a); // 10
console.log(window.b); // undefined
函数直接调用中的 this
严格模式
- 在严格模式下函数直接调用,this 会指向 undefined
js
function f() {
"use strict"; // 这里是严格模式
console.log(this === undefined); // true
}
f();
非严格模式
js
function f() {
console.log(this === window); // true
}
f();
对象中的 this
- 对象中的 this,
除箭头函数
,this 不是在当前定义的地方,而是在被调用时离函数最近的地方,谁调用我 this 就指向谁
js
let obj = {
name: "hulei",
age: 18,
getName() {
return this.name;
},
getAge() {
return this.age;
},
};
// 因为是obj调用的所有this指向obj
console.log(obj.getName()); // hulei
let getAge = obj.getAge;
// getAge在全局的window对象上,其实最终通过window.getAge(),因为this上没有age,所以undefined
console.log(getAge()); // undefined
构造函数中 this
- 构造函数函数返回的不是对象,则 this 是当前的实例对象
- 如果返回的是一个对象,则 this 指向返回的对象
js
function F1() {
this.age = 18;
}
var f1 = new F1();
console.log(f1.age); // 18
function F2() {
this.age = 19;
return { age: 20 };
}
var f2 = new F2();
console.log(f2.age); // 20
call & apply 可以改变 this 的指向注意:箭头函数是无法通过call & apply改变,下面会介绍到
js
function fn() {
console.log(this.name); // hulei
}
var user = { name: "hulei" };
fn.call(user); // hulei
箭头函数的 this
- 箭头函数的 this 一般情况下在定义的时候指向上层函数或者对象的 this
js
var age = 20;
let obj = {
age: 21,
getAge1() {
// 普通函数谁调用有this就指向谁
console.log(this.age); // 21
},
getAge2: () => {
// 箭头函this在定义的时候指向上层对象的 this,obj的this是window
console.log(this.age); // 20
},
getAge3: () => {
const getAge = () => {
// 箭头函指向上层函数的的 this
// 此时getAge3也是一个箭头函数,他的上层对象的this是window
console.log(this.age); // 20
};
getAge();
},
};
obj.getAge1(); // 21
obj.getAge2(); // 20
obj.getAge3(); // 20
普通函数、构造函数的中箭头函数 this 指向
普通函数调用箭头函数 this 指向 window
js
function fn() {
let fn1 = function () {
console.log(this); // window
};
// 在函数中箭头函数的this,分2种情况,普通调用,和实例化调用
let fn2 = () => {
console.log(this); // window
};
fn1();
fn2();
}
fn();
构造函数调用箭头函数 this 指向构造函数的实例
js
function fn() {
let fn1 = function () {
console.log(this); // window
};
let fn2 = () => {
console.log(this); // 指向构造函数的实例 fn
};
fn1();
fn2();
}
let f = new fn();
总结:
在浏览器环境下,全局的 this 指向 window===self,用 var 声明的全局变量会挂载到 window 属性上,let、const 不会
this 的指向在定义的时候确认不了,只有在被调用的时候才能确定,this 一般情况下,被谁调用 this 就指向谁
箭头函数的 this 一般情况下在定义的时候指向上层函数或者对象的 this
在函数中分为 2 种情况,普通调用和实例化调用
call 无法改变箭头函数的 this
this 案例 1
js
let point = {
x: 20,
moveTo: function (x) {
var moveX = function (x) {
// 此时函数this是指向window
// window.x = x
this.x = x;
};
moveX(x);
},
getX: function () {
// 谁调用就指向谁,此时指向point
return this.x;
},
getXx: () => {
// 在定义的时候this指向上层对象的this,此时point的this是window
return this.x;
},
};
point.moveTo(1);
console.log(point.getX()); // 20
console.log(point.getXx()); // 1
// let const 不会挂载到全局属性上
let a = 100;
let o = {
a: 10,
f1: function () {
// 普通函数谁调用我,this指向谁
console.log(this.a);
},
f2: () => {
// 在定义的时候this指向上层对象的this,此时o的this是window
// 因为let const 不会挂载到window上所以(a)是undefined
console.log(this.a);
},
f3: function () {
// 因为f3谁调用就指向谁,this已经指向o
// 箭头this指向上层函数的this
setTimeout(() => {
console.log(this.a);
}, 0);
},
};
o.f1(); // 10
o.f2(); // undefined
o.f3(); // 10
this 案例 2
js
const obj = {
f1() {
// f1的this在定义的的时候无法确定,所以这个只有在被调用的时候才能确定箭头函数的this
// f1被obj所调用,所以this是obj
// 箭头函数在定义的时候指向上层函数的this,所以是obj
const fn = () => {
console.log("this1", this);
};
fn();
// call 无法改变箭头函数的 this
fn.call(window);
},
f2: () => {
const fn = function () {
console.log("this2", this); // window
};
fn();
fn.call(this); // window 无法改变箭头函数的this
},
};
obj.f1(); // obj
obj.f2(); // window
let {f1} = obj;
f1() // window => 等价window.f1()
this 案例 3
js
class Foo {
// 原型方法
fn1() {
console.log("this1", this);
}
// 实例方法
fn2 = () => {
console.log("this2", this);
};
// 函数方法
static fn3() {
console.log("this3", this);
}
}
// es5 --------------------------------
function Foo() {
this.fn2 = () => {
console.log("this2", this);
};
}
Foo.prototype.fn1 = function () {
console.log("this1", this);
};
Foo.fn3 = function () {
console.log("this3", this);
};
const f = new Foo();
f.fn1(); // 当前实例
f.fn2(); // 当前实例
Foo.fn3(); // 当前类
箭头函数
- 箭头函数没有自己的 this
- 也没有 prototype
- 也没有 arguments
- 无法创建箭头函数的实例