如何正确判断this指向
首先,我们知道js运行时, 会产生维护一个调用栈。 在js引擎逐行执行代码的时候,会动态的去对这个栈进行维护(进入一个函数,产生一个调用栈, 也就是我们说的产生一个局部作用域, 函数运行完成,退出函数, 这个栈跟着也就弹出, 把控制权回到上一层)。那说this的时候,为什么要扯调用栈呢?
这是因为,this是在运行时绑定的,而不是在编写时绑定的, 它是什么只取决于调用方式, 与函数声明的位置无关.
那问题来了,什么是调用位置?
调用位置指的是代码执行到这个地方的时候, 他的调用上下文是什么?当前环境是什么?让我们来看一个示例:
1 | a(); |
(这也是一个调用栈的关系, 脑补一下栈的结构, 先进后出。global - a -> b -> c -> c(done) -> b(done) -> a(done) -> global)
在我们理解了调用位置后,获取调用位置。在调用过程中如何绑定this对象呢?
四个规则:
规则1: 默认绑定
该规则优先级最低.
在全局环境下, this会被默认的指向全局对象.(浏览器的话就是window)
看一个例子:
1 | var b = 1; |
But, 这里有个问题是, 如果你使用了严格模式,this不会默认绑定到全局对象,而是被绑定到undefind
规则2: 隐式绑定
当我的this, 存在上下文环境, 并且该环境下this有指向的时候, 那么this, 指向该上下文.看个例子:
1 | var student = { |
规则3: 显式绑定
call/apply/bind绑定
啊, 这里是不是要说这三个函数的不同之处?
- call, 绑定第一个参数为this, 后调用, 参数不以数组的形式传入
- apply, 绑定第一个参数为this, 后调用,参数以数组的形式传入
- bind, 绑定第一个参数为this, 后不调用
这里的第二步就是显式绑定, 显示绑定时最常见的情况,也是我们预料中this的合理行为。这个不多说了。
规则4: new关键字绑定
啊, 这里是不是要说new关键字了。我记得有道面试题,问new做了什么事?
- 创建一个object
- 创建object到prototype的链接
- 显示绑定this到object
- 执行函数体
- 返回这个object
判定顺序:
1. 你用new关键字了吗?
->嗯(绑定到new后返回的对象里)
->2
2. 你用显式绑定了吗?
->嗯(...)
->3
3. 有没有存在上下文绑定的情况?
->嗯(...)
-> 4
4. 只有默认绑定给你选了(注意严格模式下)PS: ES6要格外注意箭头函数, 箭头函数的this指向,大家可以看一下这个issues
反正我只记住了一句话: 所有的箭头函数都没有自己的this,都指向外层。然后放一个例子:
1 | var obj = { |