this(执行上下文)

🚩 这个专栏是一个 JS 进阶系列,当前内容为 JS 执行机制,建议按顺序阅读

执行上下文&作用域

词法环境&变量环境

this(上下文对象) 🔹

概述

🌍 前提概要:

在上文 执行上下文&作用域 中,我们已经知道

  • 执行上下文的 thisValuethis 等价
  • 全局执行上下文的 this 指向全局对象

而函数执行上下文中的 thisValue 指向 ,我却一笔带过 ,现在打算放在这篇文章帮它整明白!

💡 我们每次调用函数时,解析器都会将一个 上下文对象 作为 隐含参数 传递进函数。 使用 this 来引用上下文对象,根据函数的 调用方式 不同,this 的值也不同。

函数中的 this

普通函数调用

在普通函数调用中,this 指向全局对象(非严格模式)或 undefined(严格模式)。

🌰举个栗子

let a = {b: function () {let func = function () {console.log(this); //Window}func(); //普通函数调用},}
a.b(); //打印 Window

方法调用

当函数作为对象的方法调用时,this 指向调用该方法的对象。

🌰举个栗子

const obj = {name: 'Alice',greet: function() {console.log(this.name);}
};obj.greet(); // 输出: Alice

构造函数调用

当函数作为构造函数调用(使用 new 关键字)时,this 指向新创建的对象。

🌰举个栗子

function Person(name) {this.name = name;
}const alice = new Person('Alice');
console.log(alice.name); // 输出: Alice

箭头函数中的 this

箭头函数没有自己的 this,它会捕获其所在上下文的 this 值。这意味着箭头函数中的 this 在定义时就已经确定,不会因为调用方式而改变。

🌰举个栗子

const obj = {name: 'Alice',greet: function() {setTimeout(() => {console.log(this.name);}, 100);}
};obj.greet(); // 输出: Alice

类中的 this

类本质上是基于构造函数原型继承的语法糖 , 在类的方法中,this 指向类的实例。

🌰举个栗子

class Person {constructor(name) {this.name = name;}greet() {console.log(this.name);}
}const alice = new Person('Alice');
alice.greet(); // 输出: Alice

使用 callapplybind

call、apply、bind 方法:这三种方法可以明确指定 this 的值 , 即显式设置this

call、apply、bind 原理

call

作用:

call 方法用于调用一个函数,并设置函数执行时的 this 值,同时可以传递参数列表。

语法:

func.call(thisArg, arg1, arg2, ...)

  • thisArg:函数执行时的 this 值。
  • arg1, arg2, ...:传递给函数的参数列表。

原理:

  1. 将函数的 this 绑定到 thisArg
  2. 立即执行函数,并传入参数。

🌰举个例子:

const person1 = {name: '张三',introduce: function (city, country) {console.log(`${this.name} is from ${city}, ${country}`);},
};
const person2 = {name: '李四',
};
person1.introduce.call(person2, '上海', '中国')

打印:李四 is from 上海, 中国

apply

作用:

apply 方法与 call 类似,用于调用一个函数并设置 this 值,但它的参数是以数组(或类数组对象)的形式传递的。

语法:

func.apply(thisArg, [argsArray])

  • thisArg:函数执行时的 this 值。
  • argsArray:传递给函数的参数数组。

原理:

apply 的原理与 call 几乎相同,唯一的区别是参数传递方式。

🌰仍然是上面那个例子:

参数传递 必须是参数数组

person1.introduce.apply(person2, ['上海', '中国']);

bind

作用:

bind 方法用于创建一个新函数,并将原函数的 this 值绑定到指定的 thisArg。与 callapply 不同,bind 不会立即执行函数,而是返回一个绑定了 this 的新函数。

语法:

func.bind(thisArg, arg1, arg2, ...): newFunc

  • thisArg:新函数执行时的 this 值。
  • arg1, arg2, ...:预先传递给新函数的参数(可选)。
  • return newFunc: 返回一个绑定了 this 的新函数。

原理:

bind 的原理可以理解为:

  1. 返回一个新函数。
    • bind 不会改变原函数,而是返回一个新的函数。
  2. 新函数执行时,this 被绑定到 thisArg
    • 新函数的 this 值会被固定为传入的 第一个参数。例如 f.bind(obj) ,实际上可以理解为 obj.f(),这时,f 函数体内的 this 自然指向的是 obj
  3. 可以预先传递部分参数(柯里化)。
    • 可以在调用新函数时,传入额外的参数,这些参数会在调用时被传递给原函数。
预设参数
案例1:
function multiply(a, b) {return a * b;
}
const double = multiply.bind(null, 2); // 固定第一个参数为2
console.log(double(5)); // 输出: 10

在这个例子中:

  • null 是固定的 this 值,因为我们不需要设置 this
  • 2 是预设的第一个参数(对应原函数的 a),而在调用 double(5) 时,5 会作为第二个参数(对应原函数的 b)传递。
  • double 函数实际上是 multiply 函数的一个“封装”,它将第一个参数固定为 2,而 this 的值被设置为 null,这在这里并不重要,因为 multiply 函数并没有使用 this
案例 2
function f(y, z){return this.x + y + z;
}
let m = f.bind({x : 1}, 2);
console.log(m(3));
//6

在这个例子中:

  1. 参数{x : 1}
    • 这里bind方法会把它的第一个实参绑定给f函数体内的 this,所以这里的 this即指向{x : 1}对象
  2. **参数 **2
    • 从第二个参数起,会依次传递给原始函数,这里的第二个参数 2,即是 f 函数的 y参数,
  3. **参数 **3
    • 最后调用 m(3)的时候,这里的 3 便是最后一个参数 z 了,所以执行结果为 1 + 2 + 3 = 6

分步处理参数的过程其实是一个典型的 函数柯里化 的过程(Curry)

案例

分析代码:

let a = {b: function () {let func = function () {console.log(this.c);//undefined}func(); //普通函数调用},c : 'Hello!'}
a.b(); // undefined

undefined的 原因:

😃func 函数是在 a.b() 方法内定义的,调用时是作为一个普通函数调用,而不是作为对象的方法调用。这导致 this 的指向变成了全局对象(在浏览器中是 window),而不是对象 a

🤔在学习完所有this指向的场景后,你能想出不同的方法去使得this.c能正常访问吗?

解决方法

赋值

可以通过赋值的方式将 this 赋值给 that

let a = {b: function () {let self = this //将 this 赋值给 thatlet func = function () {console.log(self.c);//修改成self}func();},c: 'Hello!'}
a.b(); //输出: Hello!
使用箭头函数
let a = {b: function () {let func = () => {console.log(this.c);}func();},c: 'Hello!'
}
a.b(); // 输出: Hello!
使用call / apply
let a = {b: function () {let func = function () {console.log(this.c);}func.call(this); //call},c: 'Hello!'
}
a.b(); // 输出: Hello!
使用 bind方法
//写法一
let a = {b: function() {let func = function() {console.log(this.c);}.bind(this); //返回新函数 覆盖 func();},c: 'Hello!'
}
a.b(); // 输出: Hello!//写法二
let a = {b : function(){let func = function(){console.log(this.c);}func.bind(this)(); //立即执行},c : 'Hello!'
}a.b(); // 输出: Hello!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/899197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——数据链路层的功能

目录 物理链路 逻辑链路 封装成帧(组帧) 帧定界 透明传输 SDU 差错控制 可靠传输 流量控制 介质访问控制 主机需要实现第一层到第五层的功能,而路由器这种节点只需要实现第一层到第三层的这些功能 假设左边用户需要给右边用户发送…

计算机网络 --应用层

计算机网络 --应用层 一、应用层概述 1. 功能 应用层为应用程序通信提供直接服务,这种服务是用户能够直接感知到的数据通信服务。核心功能包括: 文件传输:实现不同设备间文件的传输操作。访问管理:对用户访问资源等进行管理。电…

企业级Linux服务器初始化优化全流程

实战指南:企业级Linux服务器初始化优化全流程 本文基于某电商平台百万级并发服务器的真实调优案例整理,所有操作均在Rocky Linux8.5验证通过,不同发行版请注意命令差异 一、服务器安全加固(Situation-Task-Action-Result&#xff…

OpenAI流式解析

OpenAI 流式的代码: 首选一般请使用os.getenv 去读环境变量的内容 注意使用pip install python-dotenv 的安装方法 load_dotenv 是这个库提供的一个函数,用于读取 .env 文件并将其中定义的键值对设置为系统的环境变量。 默认情况下,load_…

数据抓取的缓存策略:减少重复请求与资源消耗

在数据采集领域,爬虫效率是决定项目成败的关键因素之一。传统的爬虫架构往往因请求频繁、资源消耗较大以及重复抓取等问题,导致效率低下。这些问题不仅拖慢了数据获取的速度,还可能引发目标服务器的过载风险,甚至导致爬虫被限制。…

k8s部署argocd

前言 ArgoCD是一个基于Kubernetes的GitOps持续交付工具,应用的部署和更新都可以在Git仓库上同步实现,并自带一个可视化界面。本文介绍如何使用GitHelmArgocd方式来实现在k8s中部署和更新应用服务; 安装Argocd 准备一个k8s集群,然…

【Linux】MAC帧

目录 一、MAC帧 (一)IP地址和MAC地址 (二)MAC帧格式 (三)MTU对IP协议的影响、 (四)MTU对UDP协议的影响 (五)MTU对TCP协议的影响 二、以太网协议 &…

MySQL - 数据库基础操作

SQL语句 结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。 分类 DDL 数据定义语言(Data Definition Language),定义对数据库对象(库、表、列、索引)的操作。 DML 数据操作语言(Data Manip…

GraalVM原生镜像支持:Spring Cloud应用启动速度提升90%

引言:当Spring Cloud遇见GraalVM,启动时间进入秒级时代 传统Spring Cloud应用因动态类加载、反射等机制导致启动缓慢(通常超过30秒),在Serverless和Kubernetes滚动更新场景下成为性能瓶颈。Spring Cloud 2023.x通过**G…

【Unity3D】摄像机适配场景以及Canvas适配

目录 宽度不变策略 高度不变策略 宽度不变策略 开发分辨率 750*1334 (宽高比:0.56) 真机分辨率 1170*2532 (宽高比:0.46) 真机宽高比<开发宽高比&#xff0c;采用宽度不变策略 理由&#xff1a;小于代表真机高度比开发高度更大&#xff0c;因此不需要担心高度上…

HarmonyOS:基于axios实现文件的下载以及下载进度的监听

#前言&#xff1a;项目开发中&#xff0c;避免不了实现文件下载功能&#xff0c;其他平台的下载都很成熟&#xff0c;网上的例子也比较多&#xff0c;我就自己项目中实现的下载功能做个总结&#xff0c;你可以参考我的写法实现功能。 下载封装基于axios实现的下载功能。 1.下载…

简单一周日期展示及选择切换

医院挂号&#xff0c;可能需要切换日期&#xff0c;选择一周内的某一天。 提供一周内的日期段&#xff0c;通过点击&#xff0c;切换到不同天。 简单的js&#xff0c;html实例。切换玩调用后台接口&#xff0c;实现后续逻辑。 使用Vue,插值语法&#xff0c;更简单。 一周日历…

二叉树的前,中,后序遍历

我们来了解一下二叉树的遍历&#xff0c;话不多说 二叉树的遍历的概念&#xff1a; 二叉树有四种遍历方式&#xff0c;分别为前序遍历&#xff0c;中序遍历&#xff0c;后序遍历和层序遍历&#xff0c;但我们今天谈谈前三种&#xff0c;并实现它 前序遍历&#xff1a; 按照根…

golang Error的一些坑

golang Error的一些坑 golang error的设计可能是被人吐槽最多的golang设计了。 最经典的err!nil只影响代码风格设计&#xff0c;而有一些坑会导致我们的程序发生一些与我们预期不符的问题&#xff0c;开发过程中需要注意。 ​​ errors.Is​判断error是否Wrap不符合预期 ​…

逼用户升级Win11,微软开始给Win10限速

随着Windows10的支持时间越来越短&#xff0c;微软也加大了对Win10用户的驱赶力度。 最近&#xff0c;微软官宣了将要在今年6月份降低OneNote for Windows 10的同步速度。软件也将和Windows10在今年的10月14日一同停止支持和维护。 这将影响实时协作和多设备访问。 对OneNote…

SpringMVC_day02

一、SSM 整合 核心步骤 依赖管理 包含 SpringMVC、Spring JDBC、MyBatis、Druid 数据源、Jackson 等依赖。注意点&#xff1a;确保版本兼容性&#xff08;如 Spring 5.x 与 MyBatis 3.5.x&#xff09;。 配置类 SpringConfig&#xff1a;扫描 Service 层、启用事务管理、导入…

Android14 原生PackageInstaller安装某些apk报错问题

最近遇到Android14安装客户一个大型app的时候&#xff0c;执行到开始安装的时候就直接闪退了&#xff0c;查看log发现下面报错&#xff1a; 03-25 18:01:29.531 3085 3085 E AndroidRuntime: java.lang.RuntimeException: Could not copy bitmap to parcel blob. 03-25 18:01:2…

SQLAlchemy关键词搜索技术深度解析:从基础过滤到全文检索

在数据驱动的应用开发中&#xff0c;基于关键词的模糊查询是常见的业务需求。SQLAlchemy作为Python生态中最流行的ORM框架&#xff0c;提供了多种实现关键词搜索的技术方案。本文将从性能、适用场景和技术复杂度三个维度&#xff0c;系统对比分析SQLAlchemy中关键词搜索的最佳实…

基于 ffmpeg 实现合并视频

ffmpeg是一个强大的多媒体处理工具&#xff0c;支持视频文件的合并。 列出目录下所有MP4文件 import os import glob# 当前目录 directory os.getcwd() directory "/directory/to/mp4/*"# 列出目录下所有MP4文件 files glob.glob(directory)# 排序 files.sort(…

算法每日一练 (20)

&#x1f4a2;欢迎来到张翊尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (20)不同路径 II题目描述解题思路解题代…