如何正确判断this的指向.md

如何正确判断this指向

首先,我们知道js运行时, 会产生维护一个调用栈。 在js引擎逐行执行代码的时候,会动态的去对这个栈进行维护(进入一个函数,产生一个调用栈, 也就是我们说的产生一个局部作用域, 函数运行完成,退出函数, 这个栈跟着也就弹出, 把控制权回到上一层)。那说this的时候,为什么要扯调用栈呢?

这是因为,this是在运行时绑定的,而不是在编写时绑定的, 它是什么只取决于调用方式, 与函数声明的位置无关.

那问题来了,什么是调用位置?

调用位置指的是代码执行到这个地方的时候, 他的调用上下文是什么?当前环境是什么?让我们来看一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
a();

function a () {
console.log('a');
// 在window下调用
// 当前在a的执行环境

b();
}

function b () {
console.log('b');
// 在a下调用
// 当前在b的执行环境
c();
}

function c () {
// 在b下调用
// 当前在c的执行环境
console.log('c')
}

(这也是一个调用栈的关系, 脑补一下栈的结构, 先进后出。global - a -> b -> c -> c(done) -> b(done) -> a(done) -> global)

在我们理解了调用位置后,获取调用位置。在调用过程中如何绑定this对象呢?

四个规则:

规则1: 默认绑定

该规则优先级最低.

在全局环境下, this会被默认的指向全局对象.(浏览器的话就是window)
看一个例子:

1
2
3
4
var b = 1;
function a () {
console.log(this.b); // 此时, this 指向了window, 那么相当于直接访问全局变量b, 所以该行等价于-》 console.log(b)的效果, 然后这就变成了作用域的问题.....
}

But, 这里有个问题是, 如果你使用了严格模式,this不会默认绑定到全局对象,而是被绑定到undefind

规则2: 隐式绑定

当我的this, 存在上下文环境, 并且该环境下this有指向的时候, 那么this, 指向该上下文.看个例子:

1
2
3
4
5
6
7
8
9
10
var student = {
name: 'Nancy',
getName
}

function getName () {
console.log(this.name)
}

student.getName() // Nancy

规则3: 显式绑定

call/apply/bind绑定

啊, 这里是不是要说这三个函数的不同之处?

  1. call, 绑定第一个参数为this, 后调用, 参数不以数组的形式传入
  2. apply, 绑定第一个参数为this, 后调用,参数以数组的形式传入
  3. bind, 绑定第一个参数为this, 后不调用

这里的第二步就是显式绑定, 显示绑定时最常见的情况,也是我们预料中this的合理行为。这个不多说了。

规则4: new关键字绑定

啊, 这里是不是要说new关键字了。我记得有道面试题,问new做了什么事?

  1. 创建一个object
  2. 创建object到prototype的链接
  3. 显示绑定this到object
  4. 执行函数体
  5. 返回这个object

判定顺序:

1. 你用new关键字了吗?
    ->嗯(绑定到new后返回的对象里)
    ->2
2. 你用显式绑定了吗?
    ->嗯(...)
    ->3
3. 有没有存在上下文绑定的情况?
    ->嗯(...)
    -> 4
4. 只有默认绑定给你选了(注意严格模式下)

PS: ES6要格外注意箭头函数, 箭头函数的this指向,大家可以看一下这个issues

反正我只记住了一句话: 所有的箭头函数都没有自己的this,都指向外层。然后放一个例子:

1
2
3
4
5
var obj = {
fn: x => console.log(this)
}

obj.fn() // 浏览器环境下: window