this全面解析


this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在 所有函数的作用域中。但是即使是非常有经验的 JavaScript 开发者也很难说清它到底指向 什么。

实际上,JavaScript 中 this 的机制并没有那么先进,但是开发者往往会把理解过程复杂化, 毫无疑问,在缺乏清晰认识的情况下,this 对你来说完全就是一种魔法

为什么要用this

使用this可以在不同的上下文对象中重复使用函数,不用针对每个对象编写不同版本的函数;

如果不使用this那就得给函数显示的传入一个上下文对象,随着你使用的模式越来越复杂,显示传递上下文对象会让代码越来越混乱;

而this提供了一种更优雅的方式来隐式传递一个对象引用,可以是API设计得更加简洁并且易于复用。

解开this的误解

  1. this并不指向函数自身
  2. this也不一定总指向函数的作用域

this到底是什么

this实际上是在函数调用时发生绑定的,它指向什么完全取决于函数在哪里被调用。

调用位置有时候会被隐藏,可以分析调用栈也就是为了到达当前执行位置所调用的所有函数,要注意的是调用位置就在正在执行的函数的前一个调用中。

可以在工具中给 foo() 函数的 第一行代码设置一个断点,或者直接在第一行代码之前插入一条 debugger; 语句。运行代码时,调试器会在那个位置暂停,同时会展示当前位置的函数 调用列表,这就是你的调用栈。因此,如果你想要分析 this 的绑定,使用开 发者工具得到调用栈,然后找到栈中第二个元素,这就是真正的调用位置。

this的绑定规则以及优先级

默认绑定

最常用的函数调用类型:独立函数调用(函数的调用在全局不加任何修饰)。可以把这条规则看作是无法应用 其他规则时的默认规则,this指向全局对象window,但是如果时严格模式下this的绑定是undefined。

var bar = foo()

隐式绑定

需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,绑定在那个上下文对象。

obj1.foo()

当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的

注意:对象属性引用链中只有最顶层或者说最后一层会影响调用位置obj1.obj2.foo()时this指向obj2

隐式丢失

  • 上下文对象引用之后赋值在全局调用
  • 把函数作为参数进行值传递在全局调用
  • 把函数传入语言内置函数中调用

显示绑定

由call、apply、bind调用,绑定到指定对象上

var bar = foo.call(obj2)

new绑定

是否由new调用,绑定到新创建的对象上

var bar = new foo()

new调用函数自动执行的操作

  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行 [[ 原型 ]] 连接。
  3. 这个新对象会绑定到函数调用的 this。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。

优先级

new绑定>显示绑定>隐式绑定>默认绑定

绑定例外

  • 如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值 在调用时会被忽略,实际应用的是默认绑定规则

​ 安全的做法:在忽略 this 绑定时总是传入一个 DMZ 对象

var ø = Object.create( null ); 
 foo.apply( ø, [2, 3] );
  • 创建一个函数的“间接引用(间接引用最容易在赋值时发生)”,在这 种情况下,调用这个函数会应用默认绑定规则。

this词法

ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定 this,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这 其实和 ES6 之前代码中的 self = this 机制一样。


文章作者: XiaoQi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 XiaoQi !
 上一篇
作用域 作用域
1.作用域 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。 如果查找的目的是对 变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。 赋值操作符会导致 LHS 查询。=操作符或调用函数时
2020-08-01
下一篇 
原型和原型链 原型和原型链
构造函数创建对象function Person(){ } var person = new Person(); person.name = 'Kevin'; console.log(person.name);//Kevin
2020-07-30
  目录