关于 this
当 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 不能使用其他三个规则的则使用默认绑定。默认绑定就是函数独立运行所在的位置,通常都是指全局对象或者 undefined,这取决函数是否在严格模式下执行。
关于箭头函数的 this
箭头函数本身是没有 this 这个概念的,内部的 this 取决于包裹箭头函数的第一个普通函数 this。
总结
- 是否是使用 new 的方式生成?如果是则 this 绑定到该对象
- 是否使用 call、apply 以及 bind 等显示绑定方式?
- 是否使用隐式绑定?则 this 绑定到引用上下文对象
- 都不是则使用默认规则
箭头函数是根据当前此法作用域来决定 this,具体来说就是继承外层函数绑定的 this。
以上就是【js 关于 this指向问题】的全部内容了,欢迎留言评论进行交流!