当 JavaScript 执行到一段可执行代码时,会创建一个可执行上下文。执行上下文可以理解为当前代码的执行环境。 执行上下文的周期可以分为两个阶段。
- 创建阶段
在这个阶段,可执行上下文会创建变量对象、建立作用域链以及确定 this 指向问题。
- 代码执行阶段
创建完成后,就开始执行代码,完成变量赋值、函数引用以及执行其他代码。
如何判断 this 的指向
this 对象是基于当前运行环境执行时所绑定的。
- 隐式绑定
通过某个对象的属性指向函数,再通过这个对象属性调用函数。这就是函数在调用的时候给绑定了上下文对象,或者说被这个对象拥有。
function getName() { console.log('this:%s,name:%s', this, this.name); } var name = 'globalName'; var bar = { name: 'barName', getName: getName, }; bar.getName();
getName
是一个单独函数,严格来说它不属于 bar,只不过在调用的时候使用bar.getName
引用函数,也就是说 getName 函数被调用的时候添加了对 bar 的引用,当函数有引用文对象的时候,函数内部的 this 就会被绑定到 bar。所以上述代码执行的结果如下图所示:
现在代码稍微修改一下
var name = 'globalName'; function getName() { console.log('this:%s,name:%s', this, this.name); } var bar = { name: 'barName', getName: getName, }; //将引用地址赋值给一个新的变量 const fn = bar.getName; fn();
运行结果如下:
函数
getName
丢失了绑定对象,变成了 全局对象(或者 undefined,这取决于是否函数是否在严格模式下执行)。 - 显示绑定
通过 call 或者 apply 方法强制把 this 绑定到指定的对象。var name = 'globalName'; function getName(...params) { console.log('this:%s,name:%s,params:%s', this, this.name, params); } var bar = { name: 'barName', }; getName.apply(bar, [10, 11]); getName.call(bar, 10, 12); const fn = getName.bind(bar, 10, 13); fn();
温馨提示
apply
和call
区别仅是其他参数传递方式不同。apply
和call
第一个参数如果传递的值为基本类型,JavaScript 会有一个装箱的操作,也就是把基本类型包装成它对应的对象形式。
为了解决隐式绑定出现 this 丢失的问题,我们可以增加一个中间函数解决这个问题。var name = 'globalName'; function getName() { console.log('this:%s,name:%s', this, this.name); } var bar = { name: 'barName', }; function foo() { //强制将getName函数的this绑定到bar return getName.apply(bar); } foo();
3.new 绑定
使用 new 的方式创建的实例,this 指向这个实例(新创建的对象)。 使用 new 操作符创建的实例,经历 4 个步骤。
- 创建一个新对象
- 新对象的 proto 属性指向函数的原型
- 将构造函数的作用域赋给新对象(所以 this 是指向这个新对象)。执行构造函数中的代码,为这个新对象添加属性
- 如果函数没有返回其他对象,则返回这个新对象
function Person(name, age) { this.name = name; this.age = age; } // 在这里可以把Person当作一个构造函数 // 所以在new Person的时候就相当于把它的作用域指向了p // 所以Person中的this是指向p的 const p = new Person();
4.默认绑定
箭头函数本身不具备独立的
this
概念,其内部的this
是由箭头函数所处的词法作用域来决定的。具体而言,箭头函数会继承外层函数的this
绑定。要概括箭头函数中
this
的行为,可以考虑以下情况:- 使用
new
生成对象: 如果箭头函数被new
方式调用,它不会创建一个新的对象,也不会改变this
的指向,而是继承外层函数的this
。 - 显式绑定(
call
、apply
、bind
等): 在箭头函数中,无论如何都无法改变其this
的指向,因为箭头函数没有自己的this
,它会继承外层函数的this
。 - 隐式绑定: 如果箭头函数在某个对象的方法中被调用,它会继承该方法调用时的上下文对象作为
this
。 - 默认规则: 如果箭头函数不符合以上情况,它会继承外层函数的
this
,或者如果外层函数没有绑定this
,则会继承其所处的最近一层词法作用域的this
。
箭头函数的
this
绑定机制是静态的,它在定义时就确定了,不会随着调用方式的改变而改变。
Comments | NOTHING