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&…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...

【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 编写的,需要先安…...