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' 

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

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

相关文章

web服务器nginx下载及在win11的安装

一.背景 还是为了公司安排的师带徒任务。 操作系统版本&#xff1a;win11 家庭版 mginx版本&#xff1a;1.24.0 二.nginx版本选择与下载 我之前也写过下载nginx下载_ngnix stable 下载-CSDN博客 不想看寻找过程的&#xff0c;直接点这里去下载https://nginx.org/download…

Docker 使用原理流程

# docker 是如何来的&#xff1f; a. linux 内核本身支持容器技术&#xff0c;LXC (市面上有很多基于 LXC 开发的容器管理软件&#xff0c;如创建容器&#xff0c;查看容器&#xff0c;管理容器&#xff0c; docker 作为管理容器的一款代表工具软件) b. 容器的作用&#xff0c;…

利用python批量将.shp文件转换坐标生成.geojson文件,再将.geojson转换成.csv文件,最后将csv文件插入数据库表

第一步&#xff1a;.shp批量转.geojson # author: JMY # 创建时间: 2024/2/26 17:12 # 批量将.shp文件生成geojson文件并转换坐标为3857import os import geopandas as gpd# 定义输入和输出文件夹路径 input_folder shp文件 output_folder geojson文件# 定义输入和输出坐标系…

【王道操作系统】ch1计算机系统概述-04操作系统结构

文章目录 【王道操作系统】ch1计算机系统概述-04操作系统结构操作系统的内核操作系统的体系结构考纲新增内容&#xff08;红色为全新内容&#xff0c;黄色为原有内容&#xff09;&#xff1a;01 分层结构02 模块化03 宏内核&#xff08;大内核&#xff09;和微内核04 外核 【王…

redis03 八种数据类型

思维草图 String类型 字符串类型&#xff0c;是redis中最简单的存储类型&#xff0c;可以包含任何数据&#xff0c;例如jpg图片或者序列化的对象等&#xff0c;底层都是以字节数组形式存储&#xff0c;最大能存储512MB的数据。 常用命令 KEY命名规范 加前缀&#xff0c;分…

802.11局域网的 MAC 帧

目录 802.11 局域网的 MAC 帧 802.11 数据帧的三大部分 1.关于 802.11 数据帧的地址 最常用的两种情况 2.序号控制字段、持续期字段和帧控制字段 802.11 局域网的 MAC 帧 802.11 帧共有三种类型&#xff1a;控制帧、数据帧和管理帧。 802.11 数据帧的三大部分 MAC 首部&…

总结springboot启动jar,指定配置文件

第一&#xff1a;覆盖 -- 覆盖系统中的文件中的application-dev.yml文件&#xff0c;两种指定方法都可以 springboot默认优先读取application.properties>application.yml>指定文件(application-dev.yml) 公共配置可以在application.yml&#xff0c;其他配置在applicatio…

基于 STM32U5 片内温度传感器正确测算温度

目录预览 1、引言 2、问题 3、小结 01 引言 STM32 在内部都集成了一个温度传感器&#xff0c;STM32U5 也不例外。这个位于晶圆上的温度传感器虽然不太适合用来测量外部环境的温度&#xff0c;但是用于监控晶圆上的温度还是挺好的&#xff0c;以防止芯片过温运行。 02 问题…

C# - 类与类之间的继承关系判断

Type.IsSubclassof(Type type) 作用&#xff1a;用来确定 一个类是否派生自另一个类/ValueType/Enum/委托 不能用于确定&#xff1a;接口是派生自另一个接口&#xff0c;还是类实现接口 class A{} class B : A{}A a; B b;var boo b.GetType().IsSubclassOf(typeof(A)) // t…

sqllabs第五关floor报错注入

实验环境sqllabs第五关 floor()报错注入的原因是group by在向临时表插入数据时&#xff0c;由于rand()多次计算导致插入临时表时主键重复&#xff0c;从而报错&#xff0c;又因为报错前concat()中的SQL语句或函数被执行&#xff0c;所以该语句报错且被抛出的主键是SQL语句或函…

go语言中的协程和Java中线程以及进程的区别

理解 Go 语言中的协程&#xff08;Goroutine&#xff09;、Java 中的线程和进程之间的区别可以从以下几个方面来看&#xff1a; 轻量性&#xff1a; Goroutine&#xff08;协程&#xff09;&#xff1a; 协程是非常轻量级的执行单位&#xff0c;创建和销毁的成本很低。在 Go 中…

深入理解Lambda表达式:基础概念与实战演练【第114篇—python:Lambda表达式】

深入理解Lambda表达式&#xff1a;基础概念与实战演练 在现代编程语言中&#xff0c;Lambda表达式作为一种轻量级的匿名函数形式&#xff0c;越来越受到程序员的青睐。特别是在函数式编程兴起的今天&#xff0c;Lambda表达式在简化代码、提高可读性方面发挥着重要作用。本文将…

C++笔记(六)--- 静态成员变量/函数(static)

目录 C语言中静态变量 C静态成员变量 C静态成员函数 C语言中静态变量 1.函数内部用static修饰的变量&#xff0c;只能在此函数使用&#xff0c;但所修饰的变量不随函数释放而释放&#xff0c;下次调用时的值仍为上次结束时的值2.static修饰的全局变量只能在其定义的文件使用…

华为OD技术面试案例6-2024年

个人情况&#xff1a;西电本&#xff0c;二战某985基本寄了。知识储备方面&#xff1a;无任何408基础&#xff0c;学校开过数据结构课程60分过&#xff0c;python纯靠自学&#xff0c;无任何刷题经验&#xff0c;无项目经验&#xff0c;简历东拼西凑。 大概是12月底和OD联系&a…

数据可视化原理-腾讯-热力图

在做数据分析类的产品功能设计时&#xff0c;经常用到可视化方式&#xff0c;挖掘数据价值&#xff0c;表达数据的内在规律与特征展示给客户。 可是作为一个产品经理&#xff0c;&#xff08;1&#xff09;如果不能够掌握各类可视化图形的含义&#xff0c;就不知道哪类数据该用…

CSP-201712-2-游戏

CSP-201712-2-游戏 解题思路 初始化变量&#xff1a;定义整数变量n和k&#xff0c;分别用来存储小朋友的总数和淘汰的特定数字。然后定义了num&#xff08;用来记录当前报的数&#xff09;和peopleIndex&#xff08;用来记录当前报数的小朋友的索引&#xff09;。 初始化小朋…

MATLAB环境下基于离散小波变换的体外血管图像处理

下面简要介绍小波变换的部分应用。 信号去噪。小波去噪是根据有效信号和噪声信号在小波变换后表现出的不同特性实现的&#xff0c;一般可用于去除语音、图像、视频等中的噪声信号。小波去噪方法根据对小波系数的非线性处理方式分为三类&#xff0c;分别是小波变换模极大值去噪…

电子电器架构新趋势 —— 最佳着力点:域控制器

电子电器架构新趋势 —— 最佳着力点&#xff1a;域控制器 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师&#xff08;Wechat&#xff1a;gongkenan2013&#xff09;。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师…

备战蓝桥杯---状态压缩DP基础1之棋盘问题

它只是一种手段&#xff0c;一种直观而高效地表示复杂状态的手段。 我们先来看一道比较基础的&#xff1a; 直接DFS是肯定不行&#xff0c;我们发现对某一行&#xff0c;只要它前面放的位置都一样&#xff0c;那么后面的结果也一样。 因此我们考虑用DP&#xff0c;并且只有0/…

Vue3+Element-Plus中ELMessage样式丢失处理

Vu3Element-Plus项目中,element-plus使用按需引入有时会出现样式失效和在vscode中使用会报错[找不到名称“ElMessage”。ts(2304)]错误 ELMessage弹框样式丢失处理方法 使用按需引入就不能手动再引入 import { ElMessage } from "element-plus";ElMessage.success…