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的表现
相关推荐
用户908324602731 小时前
Spring AI + RAG + SSE 实现带搜索来源的智能问答完整方案
前端·后端
GISer_Jing1 小时前
阿里开源纯前端浏览器自动化 PageAgent,[特殊字符] 浏览器自动化变天啦?
前端·人工智能·自动化·aigc·交互
清风徐来QCQ1 小时前
js中的模板字符串
开发语言·前端·javascript
成都渲染101云渲染66661 小时前
Houdini+Blender高效渲染方案(高配算力+全渲染器兼容)
前端·系统架构
SuperEugene2 小时前
Vue3 + Element Plus 表格实战:批量操作、行内编辑、跨页选中逻辑统一|表单与表格规范篇
开发语言·前端·javascript
极梦网络无忧2 小时前
基于 Vite + Vue3 的组件自动注册功能
前端·javascript·vue.js
Predestination王瀞潞2 小时前
5.4.3 通信->WWW万维网内容访问标准(W3C):WWW(World Wide Web) 协议架构(分层)
前端·网络·网络协议·架构·www
爱学习的程序媛2 小时前
【Web前端】优化Core Web Vitals提升用户体验
前端·ui·web·ux·用户体验
zabr3 小时前
花了 100+ 篇笔记,我整理出 了一套 AI Agent 工程完全指南
前端·后端·agent
软弹3 小时前
深入理解 React Ref 机制:useRef 与 forwardRef 的协作原理
前端·javascript·react.js