JavaScript中的this
在实际应用中,了解
this的行为是非常重要的,特别是在编写库或框架时,或者当你需要在回调函数中访问特定的上下文时,通常推荐使用箭头函数或者其他方法来确保this的正确指向。
在ES6中,this 的值取决于它是如何被调用的。
this 不是一个函数或对象,而是一个特殊的关键字,其值在函数被调用时确定。
以下是在不同场景中 this 的值的概述:
01 全局作用域中的this
在JavaScript中,全局作用域指的是在代码的任何位置都可以访问的、变量和函数的范围。
具体可以这么理解:当你在脚本的顶层(不在任何函数或代码块内部)声明一个变量或函数时,它就在全局作用域中。
在全局作用域中,this 指向全局对象。
在浏览器环境中,全局对象是 window;
在 Node.js 环境中,全局对象是 global。
下面是一个在浏览器环境中演示这一点的简单例子:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>"use strict"// 在全局作用域中console.log(this === window); // 应该输出 true,表示 this 指向 window 对象console.log(this); // 输出window对象// 定义一个全局变量var globalVar = "I am a global variable";// 使用 this 访问全局变量console.log(this.globalVar); // 输出 "I am a global variable"// 使用 window 访问全局变量console.log(window.globalVar); // 输出 "I am a global variable"// 定义一个函数,并在全局作用域中调用它function testFunction() {console.log(this); // 在浏览器环境中,输出 window 对象,"use strict"下输出undefined}testFunction();</script>
</body>
</html>
在这个例子中,this 在全局作用域中指向 window 对象。我们通过比较 this 和 window 来验证这一点,并且使用 this 和 window 来访问一个全局变量 globalVar,以证明它们都可以用来访问全局作用域中的变量。
如果你在 Node.js 环境中运行代码,全局对象将是 global,你可以类似地测试:
// 在 Node.js 的全局作用域中
console.log(this === global); // 应该输出 true,表示 this 指向 global 对象// 定义一个全局变量
global.globalVar = "I am a global variable";// 使用 this 访问全局变量
console.log(this.globalVar); // 输出 "I am a global variable"// 使用 global 访问全局变量
console.log(global.globalVar); // 输出 "I am a global variable"// 定义一个函数,并在全局作用域中调用它
function testFunction() {console.log(this); // 在 Node.js 环境中,输出 global 对象
}testFunction();
在这个 Node.js 例子中,this 在全局作用域中指向 global 对象,并且我们同样使用 this 和 global 来访问一个全局变量 globalVar。
02 函数调用中的this
当一个函数不是作为对象的方法调用时(也就是说,它是独立调用的,或者作为回调函数等被调用),this 的值在非严格模式下默认为全局对象(在浏览器中通常是 window),而在严格模式下它是 undefined。
下面我将给出两个示例程序来演示这个行为。
首先是非严格模式下的示例:
// 非严格模式
function exampleFunction() {console.log(this); // 在非严格模式下,this 指向 window 对象console.log(this.globalVar); // => I am a global variable
}exampleFunction();// 你可以通过检查 window 对象来验证这一点
function setGlobalVar() {window.globalVar = "I am a global variable";
}
setGlobalVar();
exampleFunction(); // 输出包含 globalVar 的 window 对象
在这个例子中,exampleFunction 不是作为任何对象下的方法调用的,因此在非严格模式下,this 指向 window 对象。
我们在 setGlobalVar 函数中设置了一个全局变量 globalVar,然后在 exampleFunction 中通过 this 访问它,证明了 this 确实指向 window。
03 对象方法中的this
当一个函数作为对象的方法被调用时,this 关键字指向调用该方法的对象。下面是一个简单的示例来展示这个行为:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>03-对象方法中的this</title>
</head>
<body><script>// 定义一个对象,它有一个方法叫做 greetconst person = {name: "Alice",getName: function () {console.log(this.name);}};// 调用 person 对象的 getName方法person.getName(); // 输出 "Alice"// getName中this指向person对象,因为getName是作为 person 的方法被调用的</script>
</body>
</html>
在这个例子中,getName 函数是 person 对象的一个方法。当我们通过 person.getName() 调用这个方法时,this 关键字在函数内部指向了 person 对象。因此,this.name 访问的是 person 对象的 name 属性,并输出了相应的信息。
04构造函数中的this
当一个函数被用作构造函数,并使用 new 关键字调用时,this 关键字会指向新创建的对象实例。下面是一个简单的例子来说明这个行为:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>04-构造函数中的this</title>
</head>
<body><script>// 定义一个构造函数 function Person(name, age) {this.name = name;this.age = age;// 可以添加一个方法来访问实例属性 this.greet = function () {console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);};}// 使用 new 关键字来调用构造函数,创建一个新的对象实例 const alice = new Person('Alice', 25);alice.greet(); // 输出 "Hello, my name is Alice and I'm 25 years old." // 验证 this 指向的是 alice 对象 console.log(alice.name); // 输出 "Alice" console.log(alice.age); // 输出 25 // 创建一个新的对象实例 const bob = new Person('Bob', 30);bob.greet(); // 输出 "Hello, my name is Bob and I'm 30 years old." // 验证 this 指向的是 bob 对象 console.log(bob.name); // 输出 "Bob" console.log(bob.age); // 输出 30</script>
</body>
</html>
每次使用 new 关键字调用 Person 构造函数时,都会创建一个新的对象实例,并且 this 都会指向那个新对象。这就是为什么 alice 和 bob 有各自独立的 name 和 age 属性,以及它们各自的 greet 方法。
在这个例子中,Person 函数被用作构造函数,因为我们使用 new 关键字来调用它。当构造函数被调用时,JavaScript 会创建一个新的空对象,并将这个新对象的内部链接([[Prototype]])设置为构造函数的 prototype 对象。然后,构造函数中的代码执行,其中 this 关键字引用新创建的对象。
因此,当我们设置 this.name 和 this.age 时,我们实际上是在新创建的对象上设置属性。同样,this.greet 方法也是添加到新对象上的一个方法。
05箭头函数中的this
箭头函数在 JavaScript 中是一个非常重要的特性,它提供了一种更简洁的函数书写方式,并且它不绑定自己的 this,而是继承自包围它的函数或全局作用域的 this。
这意味着在箭头函数内部,this 的值是在定义箭头函数时确定的,而不是在调用时确定的。
下面是一个简单的示例来说明这个行为:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>05-箭头函数中的this</title>
</head>
<body><script>function OuterFunction() {this.value = 42;// 这是一个普通函数 function innerFunction() {console.log(this.value); // 这里的 this 指向 OuterFunction 的实例 }// 这是一个箭头函数 const arrowFunction = () => {console.log(this.value); // 这里的 this 继承自 OuterFunction 的实例 };// 调用普通函数和箭头函数 innerFunction(); // 输出 42 arrowFunction(); // 输出 42 }const obj = new OuterFunction();// 当我们在外部调用 innerFunction 时,this 指向全局对象(在浏览器中通常是 window) // 因此,以下代码会抛出一个错误,因为 this.value 是 undefined obj.innerFunction(); // Uncaught TypeError: Cannot read property 'value' of undefined // 但是,箭头函数不会改变它的 this 上下文 // 因此,即使我们在外部调用 arrowFunction,它仍然可以访问 OuterFunction 的 this 上下文 obj.arrowFunction(); // 输出 42</script>
</body>
</html>
在OuterFunction 中定义了一个普通函数 innerFunction 和一个箭头函数 arrowFunction。
当 OuterFunction 被调用时,它创建了一个新的对象实例,并且 this 在 innerFunction 和 arrowFunction 中都指向这个新创建的对象。
当我们直接调用 obj.innerFunction() 时,this 指向了全局对象(在浏览器中是 window),因此 this.value 是 undefined,导致抛出一个错误。
然而,当我们调用 obj.arrowFunction() 时,即使我们是在外部调用的,arrowFunction 内部的 this 仍然指向 OuterFunction 的实例,因此可以正确地访问 value 属性。这是因为箭头函数不绑定自己的 this,而是从定义它的上下文中继承 this。
TODO 嵌套函数
全局函数中的嵌套函数
对象方法中的嵌套函数
总结
| 场景 | this 的值 | 描述 |
|---|---|---|
| 全局作用域 | window (浏览器) 或 global (Node.js) | 在全局作用域中,this 指向全局对象。 |
| 函数调用 | undefined (严格模式) 或 window (非严格模式) | 当一个函数不是作为对象的方法调用时,this 的值在非严格模式下是 window,在严格模式下是 undefined。 |
| 对象方法 | 调用该方法的对象 | 当一个函数作为对象的方法被调用时,this 指向调用该方法的对象。 |
| 构造函数 | 新创建的对象 | 当一个函数作为构造函数使用 new 关键字调用时,this 指向新创建的对象。 |
| 箭头函数 | 定义时的上下文 | 箭头函数不绑定自己的 this,它继承自包围它的函数或全局作用域的 this。 |
| 事件处理器 | 调用事件处理器的对象 | 在DOM事件处理器中,this 通常指向触发事件的元素。 |
| 定时器函数 | undefined (严格模式) 或 window (非严格模式) | 在 setTimeout 或 setInterval 的回调函数中,this 的值在非严格模式下是 window,在严格模式下是 undefined。 |
| Call, Apply, Bind | 指定的对象 | 使用 call、apply 或 bind 方法可以显式地设置 this 的值。 |
请注意,箭头函数的行为略有不同,因为它们不绑定自己的 this。相反,它们从定义它们的上下文继承 this。
希望这个表格能帮助你理解ES6中 this 的不同行为!
在JavaScript中,特别是在ES6及其之后的版本中,回调函数中使用普通函数和箭头函数时,this 的值可能会有所不同。这主要取决于回调函数的调用方式和上下文。以下是普通函数和箭头函数在回调中作为方法使用时 this 的区别:
普通函数
当回调函数是一个普通函数时,this 的值通常取决于该函数如何被调用。如果该函数是作为对象的方法被调用,那么 this 将指向调用该方法的对象。如果该函数是作为回调函数被调用,并且没有使用 call、apply 或 bind 方法来显式地设置 this 的值,那么 this 可能会指向全局对象(在浏览器中是 window),或者在没有严格模式的情况下是 undefined。
例如:
function Example() {this.value = 5;setTimeout(function() {console.log(this.value); // this 指向全局对象或undefined(严格模式)}, 1000);
}const example = new Example(); // 输出可能是 undefined,取决于环境
箭头函数
箭头函数不绑定自己的 this,它继承自包围它的函数或全局作用域的 this。这意味着在箭头函数内部,this 的值将始终与包围它的外部函数的 this 保持一致。
因此,当回调函数是箭头函数时,this 将保持外部函数的 this 值,即使回调函数以不同的方式被调用。
例如:
function Example() {this.value = 5;setTimeout(() => {console.log(this.value); // this 继承自Example函数的this,所以输出5}, 1000);
}const example = new Example(); // 输出 5
在这个例子中,即使 setTimeout 是一个全局函数,并且通常会导致回调函数中的 this 指向全局对象,但由于使用了箭头函数,this 仍然保持了 Example 函数的上下文。
总结:在回调函数中,普通函数的 this 值可能会根据回调函数的调用方式而改变,而箭头函数的 this 值则始终与其外部函数的 this 保持一致。因此,在需要确保 this 的值始终为特定上下文时,使用箭头函数通常是更安全的选择。
this不是常量, 它在程序中的不同地方会求值为不同的值。
this是面向对象编程中使用的关键字。在方法体中,this求值为调用方法的对象。
this 在 标准函数 和 箭头函数 中有不同的行为。
1、标准函数中的 this
window.color = 'red';
// 全局上下文中调用函数时,this 指向 windows
function sayColor() { console.log(this.color);
}
sayColor(); // 'red' let o = { color: 'blue'
};
o.sayColor = sayColor;
o.sayColor(); // 'blue'
2、嵌套函数
嵌套函数普通函数内部的this是全局对象,嵌套箭头函数的this是外层对象的this
注意:vue中相反:vue中嵌套普通函数内部的this是vue,而嵌套箭头函数的this是全局对象
let o = {m:function(){let self = this;this === o;console.log('o.m() this:',this);f(); function f(){this === o;self ===o;console.log('o.m.f() this:',this);}const f2 = ()=>{console.log('o.m.f2() this:',this);}f2();const f3 = (function(){console.log('o.m.f3() this:',this);}).bind(this);f3();}
}
o.m();
console.log(o);
2、箭头函数中的this
window.color = 'red';
let sayColor = () => console.log(this.color);
sayColor(); // 'red' let o = { color: 'blue'
};
o.sayColor = sayColor;
o.sayColor(); // 'red'
相关文章:
JavaScript中的this
在实际应用中,了解 this 的行为是非常重要的,特别是在编写库或框架时,或者当你需要在回调函数中访问特定的上下文时,通常推荐使用箭头函数或者其他方法来确保 this 的正确指向。 在ES6中,this 的值取决于它是如何被调用…...
宝塔php站点设置伪静态规则 访问 a.com 时候跳转到 a.com/b.html
要在宝塔 PHP 站点中设置伪静态规则,实现访问a.com时跳转到a.com/b.html,可以按照以下步骤进行操作: 打开宝塔面板并登录到你的服务器管理界面。进入网站设置页面,找到你要设置伪静态规则的 PHP 站点。在站点设置中,找…...
git介绍4.2
git(版本控制工具) 一、git 介绍 1、git是目前世界上最先进的分布式版本控制系统,可以有效,高速的处理从小到大的项目版本管理。 2、git是linux torvalds 为了帮助管理linux内核开发二开发的一个开放源码的版本控制软件。 3、git作用:更好…...
【深入了解设计模式】组合设计模式
组合设计模式 组合模式是一种结构型设计模式,它允许你将对象组合成树状结构来表现“整体-部分”关系。组合模式使得客户端可以统一对待单个对象和组合对象,从而使得代码更加灵活和易于扩展。 概述 对于这个图片肯定会非常熟悉,上图我们可…...
4.Java---方法+重载
方法 方法的调用是需要开辟内存的,方法调用结束内存就被销毁了. 下面将介绍一个经典的错误标准的0分的示意! 我们日常中写交换两个数字的代码的时候都会用如下的方法进行描述: 你是不是觉得自己写的特别对!终于可以独立写一个小小的函数了? 下面运行一下看看结果 哦莫!怎么…...
蓝桥杯Java B组历年真题(2013年-2021年)
一、2013年真题 1、世纪末的星期 使用日期类判断就行,这里使用LocalDate,也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…...
C++笔记(五)--- 虚函数(virtual)
目录 虚函数介绍 虚函数、覆盖和重载区别 虚函数介绍 C的虚函数是多态性的表现 1.构造函数不能为虚函数2.子类继承时虚函数仍为虚函数3.虚函数类外实现时,不需要加virtual4.有虚函数的类,析构函数一定要写成虚函数(否则可能会造成内存泄漏&…...
编写加密程序,加密规则为:将所有字母转化为该字母后的第三个字母,即A->D、B->E
编写加密程序,加密规则为:将所有字母转化为该字母后的第三个字母,即A->D、B->E、C->F、…、Y->B、Z->C。小写字母同上,其他字符不做转化。输入任意字符串,输出加密后的结果。 例如:输入&qu…...
【笔记】:更方便的将一个List中的数据传入另一个List中,避免多重循环
这里是 simpleInfoList 集合,记为集合A(传值对象) List<CourseSimpleInfoDTO> simpleInfoList courseClient.getSimpleInfoList(courseIds);if(simpleInfoListnull){throw new BizIllegalException("当前课程不存在!");}这…...
Cisco Secure ACS 5.8.0.32 安装 + Crack 教程
Cisco Secure ACS 5.8.0.32 安装 Crack 教程 前言系统环境开始安装 开始破解导入授权文件 前言 在ESXi 6.7 上经历过无数次的安装尝试 测试了各种兼容版本都没有安装成功,记最后一次安装成功的过程. 系统环境 服务器 : Dell R720xd CPU : E5-2620 v2 系统 : ESXi 6.7…...
项目准备March
Nginx主要用来作为Http服务器,要实现Tomcat的负载均衡,就可以通过Nginx来实现。 正向代理代理的是客户端,反向代理代理的是服务端。SpringBoot采用约定优于配置的思想,简化Spring项目的配置开发。 前端请求其实并未直接发送到后…...
集智书童 | YOLO+混合注意力机制 | YOLOv5再加4.3%才可以做对手,Transformer混合设计依旧可以卷
本文来源公众号“集智书童”,侵权删,干货满满。YOLOv5重出江湖! 原文链接:https://mp.weixin.qq.com/s/vb7HsA0fKDgRc3uC8Z-2yw 在工业生产过程中,由于低效率、不统一的评估、高成本以及缺乏实时数据,传统…...
Codeforces Round 894 (Div. 3)----->C. Flower City Fence
题目总思路: 要判断是否对称,只需要判断两个放法得到的图形是否相同(竖着放,横着放),这两个放法有个很重要的特性:就是数组中大于1的个数,就是横着放时,第一竖排的高度。…...
CryoEM - CryoAI: Amortized Inference of Poses 工程源码复现
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/136384544 Paper: CryoAI: Amortized Inference of Poses for Ab Initio Reconstruction of 3D Molecular Volumes from Real Cryo-EM Images CryoAI: 基于摊…...
项目预备知识
导入两个头文件 #include <graphics.h> // 引入 EasyX 的图形库头文件 #include <conio.h> // 引入 conio.h 以使用 getch() 窗口创建函数:小黑屏 initgraph(640, 480, SHOWCONSOLE); closegraph(); //关闭一个窗口 设置背景颜色:这…...
redis实战笔记汇总
文章目录 1 NoSQL入门概述1.1 能干嘛?1.2 传统RDBMS VS NOSQL1.3 NoSQL数据库的四大分类1.4 分布式数据库CAP原理 BASE原则1.5 分布式集群简介1.6 淘宝商品信息的存储方案 2 Redis入门概述2.1 是什么?2.2 能干嘛?2.3 怎么玩?核心…...
elment-ui table表格排序后 清除排序箭头/恢复默认排序 的高亮样式
问题描述: 1.默认排序是按照名称升序排列(图一) 2.在选择了筛选项以及其他排序方式之后,箭头高亮是这样的(图二) 3.当我点击清空按钮后,类型清空了,并且传给后端的排序方式是名称/升…...
MySQL数据库基本操作(二)
查询语句 1. 排序查询* 语法:order by 子句* order by 排序字段1 排序方式1 , 排序字段2 排序方式2... * 排序方式:* ASC:升序,默认的。* DESC:降序。 * 注意:* 如果有多个排序条件&#…...
Unity(第十部)时间函数和文件函数
时间函数 using System.Collections; using System.Collections.Generic; using UnityEngine;public class game : MonoBehaviour {// Start is called before the first frame updatefloat timer 0;void Start(){//游戏开始到现在所花的时间Debug.Log(Time.time);//时间缩放值…...
【Java学习笔记】
常见算法 查找算法 1.基本查找 public class BasicSearchDemo01 {public static void main(String[] args) {//基本查找//核心://从0索引开始挨个往后查找//需求:定一个方法利用基本查找,查询某个元素是否存在//数据如下:{131&…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
