JS核心知识-this的指向

JS中this的指向是谁?为什么在不同场景下this总是不同。这是学习JS中总会不解的难题。理解this是掌握JS核心的关键之一。

this是什么?

除箭头函数中的this外,this是一个运行时确定的。它的指向取决于函数的调用方式,而不是如何声明的。也就是在执行上下文的创建阶段,JS引擎根据当时调用情况确定了this的指向。

打个比方讲执行上下文是一个会议本身 ,this是会议主席,谁是会议主席。取决于谁发起了这次会议。有如下几种情况:

  • 老板发起的会议(老板就是对象),主席(this)就是老板
  • 如果是在公共论坛上任何人发言(独立调用),主席就是论坛主持人(全局对象/undefined)要看论坛的环境(是否是严格模式)
  • 如果是老板委托某人主持会议发言(call/apply),那么委托的这个人(call/apply指定的对象)就是主席(this)。
  • 如果老板委托某人某段时间(应用存在的时间)内主持会议发言(bind),那么在某段时间内委托的人(bind指定的对象)就是主席(this)

this的指向

JS引擎在执行上下文创建阶段,会按照一套规则来分析,this的绑定谁。而这套规则是有一个优先级的判断。现在从高到低一一介绍。

1. new 绑定

new 绑定就是通过new操作符进行调用函数是,JS引擎认为这个函数是一个构造函数。此时有一系列操作:

  • 创建一个空的新对象,对这个空对象的[[Prototype]]会指向函数的prototype对象
  • 这个新对象将绑定到执行上下文AO的属性ThisBinding
  • 如果函数没有返回其他对象,通过new操作符调用的函数会自动返回这个新对象
js 复制代码
function Person(name) {
    this.name = name;
    this.sayName = function() {
        return `My name is ${this.name}`
    }
    // 隐式的返回了这个this
}
var p = new Person('lucy');
p.sayName() // `My name is lucy`

2. 显示绑定

通过函数中callapplybind方法,强制指定函数执行时this的指向。它们都能改变this的指向,但是调用方式或行为上有点略微的差别。

js 复制代码
function calculatePrice(total) {
  return total * this.price;
}

var product1 = {
  price: 2,
};
var product2 = {
  price: 3,
};
var product3 = {
  price: 5,
};
console.log(calculatePrice.call(product1, 5)); // 10
console.log(calculatePrice.apply(product2, [10])); // 30
const newCalculatePrice = calculatePrice.bind(product3);
console.log(newCalculatePrice(15)); // 75
product3 = {
  price: 6,
};
console.log(newCalculatePrice(15)); // 75
const newCalculatePrice2 = calculatePrice.bind(product3);
console.log(newCalculatePrice2(15)); // 90

3. 隐式绑定

当函数作为了对象的一个属性时,通过对象调用属性的方法时,this指向这个对象。

js 复制代码
var name = 'jake'
var girl = {
  name: "lucy",
  age: 18,
  sayHello: function () {
    console.log("Hello, my name is " + this.name);
  },
};
girl.sayHello(); // 'Hello, my name is lucy'
// 将sayHello赋值给了另一个变量的话,this就改变了
// 这是因为sayHello现在是独立调用。
var sayHello = girl.sayHello;
sayHello() // 'Hello, my name is jake'

4. 独立调用

当函数独立调用时,this的指向全局对象 。在严格模式下为undefined

js 复制代码
function showThis() {
    console.log(this);
}
showThis() // 浏览器非严格模式下 window 严格模式下undefined node.js下为global

5. 其他情况

箭头函数

箭头函数没有自己的this。当创建箭头函数的执行上下文时,直接获取外层执行上下文中的this。就是说箭头函数不是在运行时所决定的,而是在定义它时已经确定了this的指向。属于静态绑定。从性能上看的话,箭头函数要略优于普通函数

js 复制代码
var obj = {
  name: "object",
};
var name = "global object";
var sayName = () => {
  console.log(this.name);
};
sayName.call(obj); // 'global object' 无法通过显示绑定修改this的指向

再来看一个例子:

js 复制代码
var a = 0;
function Foo() {
  this.a = 1;
  var bar = () => {
    console.log(this.a);
  };
  bar(); // 1 因为bar的执行上下文的this是直接获取Foo的执行上下文的this,而它的this就是一个对象,并且属性a值为1.
}
const f = new Foo();

DOM事件处理的函数

DOM事件绑定两种:

  1. 在HTML的onclick属性添加处理函数
html 复制代码
<button onclick="click()">点击</button>
<script>
    function click () {
        console.log(this) // window对象
    }
</script>
  1. 使用addEventListener方法注册事件处理函数
js 复制代码
<button id="btn" >点击</button>
<script>
    const btn = document.getElementById('#btn')
    btn.addEventListener('click', function () { // 函数改为箭头函数的话 this指向window
        console.log(this === btn) // true 
    })
</script>

小结

本章主要讲解一下内容:

  • this指向的确定时机和确定规则优先级为: new > 显示绑定 > 隐式绑定 > 独立调用
  • 箭头函数中的this的确定时机以及指向问题
  • DOM事件处理函数this的表现
相关推荐
永日456702 小时前
学习日记-CSS-day53-9.11
前端·css·学习
magnet2 小时前
用img标签渲染的svg VS 直接使用svg标签,有什么区别?
前端·html
ze_juejin2 小时前
createComponent的environmentInjector详解
前端
云舟吖2 小时前
基于 electron-vite 从零到一搭建桌面端应用
前端·架构
ze_juejin2 小时前
CSS backdrop-filter 属性详解
前端
前端人类学2 小时前
现代贪吃蛇游戏的进化:从经典玩法到多人在线体验
javascript·css
不爱编程的小方2 小时前
响应式布局
前端·css3
前端康师傅2 小时前
JavaScript 函数高级用法
前端·javascript