js基础:this

谈谈 js 中的 this

js 中的this是面试官经常考的问题,相信每一个开发者都对 this 有或多或少的迷惑,那么什么是 this?又如何找到 this 的指向?

this 是什么?

我们先来看看 js 规范是如何解释它的

image.png

image.png

image.png

摘自《ECMAScrip (ECMA-262)

第一处 10.1.7 对 this 的解释(译):存在与每个活动执行上下文关联的 this 值。 this 值取决于调用方和正在执行的代码类型,并由控件进入执行上下文时确定。与执行上下文关联的 this 值是不可变的。
第二处 11.1.1 译:this 关键字计算为执行上下文的这个值。
第三处 12.2.1 描述 this 也是正在运行时的上下文环境。

this 的指向

ok,以上三处,都围绕一个词:上下文环境。也就是说要看 this 的指向就是通过上下文来决定的。
下面通过几个场景来观察 this。

全局环境下的 this

  • nodejs 环境
1
console.log(this); // {}
  • 浏览器环境

image.png
全局环境下的 this,在 nodejs 中是{},实际指向的是 module.exports 这个模块作用域,,浏览器指向的是 Window。

函数内(function)中的 this

  • nodejs 非严格模式下
1
2
3
4
5
6
function fn() {
return this;
}
const result = fn();
console.log(result); // Object [global] {...}
console.log(result === global); // true
  • 浏览器环境 非严格模式下

image.png

  • nodejs 严格模式下
1
2
3
4
5
6
7
function fn() {
"use strict";
return this;
}
const result = fn();
console.log(result); // undefined
console.log(result === undefined); // true
  • 浏览器环境下

image.png
非严格模式下,函数内 this 的指向
nodejs:global
浏览器:window
严格模式下,函数内 this 的指向
nodejs:undefined
浏览器:undefined

构造函数内的 this

这个也属于函数内的 this,因为内容较大,这里单独拿出来讲:

1
2
3
4
5
function Person(name) {
this.name = name;
}
const p = new Person("zhangsan");
console.log(p.name); // zhangsan

例子可以看出,当经过 new 关键字来声明一个对象时,这里的 this 实际指向的是他的实例。

改变 this 的指向(call,apply,bind)


  • call

语法:function.call(thisArgs,arg1,arg2, …)
第一个参数代表 function 函数内 this 值,可选。
arg1,arg2, … 指定参数列表

1
2
3
4
5
6
7
8
9
10
11
12
function Person() {
this.name = "ipenman";
this.sayHi = function () {
console.log(`My name is ${this.name}`);
};
}
function Man(age, gender) {
this.name = "zhangsan";
}
const man = new Man();
const p = new Person();
p.sayHi.call(man); // zhangsan
  • apply

语法:function.apply(thisArgs,[arg1,arg2, …])
第一个参数代表 function 函数内的 this 值,可选。
[arg1,arg2, …] 指定参数列表

1
2
3
4
5
6
7
8
9
10
11
12
function Person() {
this.name = "ipenman";
this.sayHi = function () {
console.log(`My name is ${this.name}`);
};
}
function Man() {
this.name = "zhangsan";
}
const man = new Man();
const p = new Person();
p.sayHi.apply(man); // zhangsan
  • bind

语法:与 apply 语法相同
区别:bind 函数会创建一个新的函数,不会立即执行

1
2
3
4
5
6
7
8
9
10
11
12
function Person() {
this.name = "ipenman";
this.sayHi = function () {
console.log(`My name is ${this.name}`);
};
}
function Man() {
this.name = "zhangsan";
}
const man = new Man();
const p = new Person();
p.sayHi.bind(man)(); // zhangsan

call、apply、bind 均以改变 this 的指向,p 的 this 指向了 man。

####

作为对象的方法

1
2
3
4
5
6
7
8
const Person = {
name: "ipenman",
age: 24,
show: function () {
console.log(this);
},
};
Person.show(); // { name: 'ipenman', age: 24, sayHi: [Function: sayHi] }

当函数作为对象里的方法被调用时,它们的 this 指向的是调用该函数的对象。
**

箭头函数

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this
–《es6 标准入门 阮一峰》

function 函数:

1
2
3
4
const fn = function () {
return this;
};
console.log(fn()); // Object [global] {...}

箭头函数:

1
2
3
4
const fn = () => {
return this;
};
console.log(this); // {}

箭头函数没有自己的 this,它的 this 就是上层代码块的 this。

总结:

  1. 全局环境下的 this,在 nodejs 中是{},实际指向的是 module.exports 这个模块作用域,,浏览器指向的是 Window。

  2. 函数内的 this

非严格模式下,函数内 this 的指向
nodejs:global
浏览器:window
严格模式下,函数内 this 的指向
nodejs:undefined
浏览器:undefined
**

  1. 构造函数的 this,**new 关键字来声明的对象 this 指向的是它的实例。**
  2. call,apply,bind 函数改变的 this,指向的是其函数内的指定参数。
  3. 作为对象的方法,**它们的 this 指向的是调用该函数的对象。**
  4. 箭头函数的 this,箭头函数的 this 指向的是外层代码块的 this。

习题

通过几道题,看你是否真的掌握了 this。

  1. 运行 test2.js,说出打印结果。


① 创建 test1.js

1
module.exports = this;

② 创建 test2.js

1
2
const t1 = require("./test1");
console.log(this === t1);
  1. 运行 test2.js,说出打印结果


① 创建 test1.js

1
2
3
module.exports = function () {
return this;
};

① 创建 test2.js

1
2
3
4
5
const t1 = require("./test1");
function fn() {
return this;
}
console.log(fn() === this);
  1. 运行以下代码,并说出打印结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const Person = {
name: "ipenman",
show: function () {
return this;
},
show1: () => {
return this;
},
};
console.log(Person.show());
console.log(Person.show1());
console.log(Person.show() === Person.show1());
console.log(Person.show1() === this);
console.log(Person.show() === this);
  1. 运行一下代码,说出打印结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Person() {
this.name = "ipenman";
return () => {
return () => {
console.log(this);
return () => {
console.log(this);
return () => {
console.log(this);
};
};
};
};
}
const p = new Person();
p()()()();
  1. 说出打印结果。
1
2
3
4
5
6
7
8
9
function Person() {
this.name = name;
this.age = 23;
}
function Man(name) {
Person.call(this, name);
}
const man = new Man("ipenman");
console.log(man);
原创技术分享,您的支持将鼓励我继续创作