this、闭包与作用域

this、闭包与作用域

this指针详解

        函数的this关键字在JavaScript中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定)。

  • this关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象。
  • 在函数执行过程中,this一旦被确定了,就不可以再更改。

        JavaScript中this不是固定不变的,它会随着执行环境的改变而改变。

  • 全局上下文:在全局作用域(也就是不在任何函数内部)中,this指向全局对象。在浏览器环境中,这个全局对象是window。
  • 函数被直接调用:函数被直接调用(即不是作为对象的方法或不是通过new关键字)时,this指向全局对象。
  • 对象的方法:函数作为对象的方法被调用时,this指向调用该方法的对象。
  • 构造函数:函数通过new关键字被调用时(作为一个构造函数),this指向一个新创建的对象实例。
  • 箭头函数:箭头函数不绑定自己的this,它继承自包围它的函数或全局作用域的this。箭头函数中,this指向不会改变,用apply等等都不行。
  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 类似 call() 和 apply() 方法可以将 this 引用到任何对象。

作用域详解

        作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。换句话说,作用域决定了代码区块中变量和其他资源的可见性。一般将作用域分成:全局作用域、函数作用域、块级作用域。

        可以理解为是一个对象包含了当前执行环境的信息。当查找变量的时候,会先从当前作用域对象中查找,如果没有找到,就会去父级查找,一直找到全局对象window,这样有多个执行上下文的变量对象构成的链条就叫做作用域链。作用域链的变量只能向上访问,变量访问到window对象即被终止。

        在js中,包含三种作用域:全局作用域/函数作用域/块级作用域。

全局作用域

        任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。

函数作用域

        函数作用域也叫局部作用域,如果一个变量是在函数内部声明的,它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。

块级作用域

        ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量。

默认绑定、显式绑定、隐式绑定

        根据不同使用场合,this有不同的值,主要分为下面几种情况:默认绑定、显式绑定、隐式绑定、new绑定。

默认绑定

  • 如果在全局作用域(或称为函数外部)调用函数,this指向全局对象。在浏览器中是window对象(在非严格模式下),在严格模式下是undefined。
    • 在严格模式下(代码文件顶部使用'use strict';),this会是undefined,不能将全局对象用于默认绑定,this会绑定到undefined。只有函数运行在非严格模式下,默认绑定才能绑定到全局对象。
  • 如果函数被当作普通函数调用(即不是作为一个对象的方法或不是通过new关键字),this也指向全局对象。

显式绑定

  • 使用call、apply或bind方法可以直接设置函数执行时this的值。
  • call和apply会立即执行函数,并接受一个对象作为this的值,同时还可以传递参数列表。
  • bind会创建一个新的函数,当这个新函数被调用时,this的值会被设置为bind的第一个参数,并且它也可以接受额外的参数传递给原函数。

隐式绑定

  • 当函数作为某个对象的方法被调用时,this会被隐式地绑定到那个对象上。这时this就指这个上级对象,就算一个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,this永远指向的是最后调用它的对象。
  • 如果函数不是通过对象来调用,即使它在对象内部定义,this也不会绑定到那个对象上。如果函数是在一个对象的方法内部被调用,并且这个函数是作为普通函数调用(而不是作为对象的方法调用),那么this可能并不会绑定到你所期望的对象上。为了避免这种情况,可以使用call或apply来显式地设置this的值,或者使用箭头函数来自动绑定this。

new 绑定

  • 当使用new关键字来调用函数时,会创建一个新的空对象,并将this绑定到这个新创建的对象上。
  • 如果函数没有显式地返回一个非原始值(如对象或函数),new表达式的结果就是这个新创建的对象。
  • 注意,null虽然也是对象,但是return null的时候,new仍然指向实例对象

闭包的概念

        一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来,作为函数内部与外部连接起来的一座桥梁。

function init() {var name = "Mozilla"; // name 是一个被 init 创建的局部变量function displayName() { // displayName() 是内部函数,一个闭包alert(name); // 使用了父函数中声明的变量}displayName();
}
init(); //displayName()没有自己的局部变量,由于闭包的特性,它可以访问到外部函数的变量

        闭包就是有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,并将函数返回。

存储空间、执行上下文

存储空间

        在JavaScript中,存储空间通常指内存中的区域,用于存储变量、函数、对象等。JavaScript引擎(如V8、SpiderMonkey等)管理着这部分内存,并且会自动进行垃圾回收,以释放不再使用的内存空间。

        存储空间可以大致分为以下几类:

堆内存:用于存储对象实例和闭包等。堆内存是由JavaScript引擎自动管理的,当不再需要某个对象时,垃圾回收器会将其释放。

栈内存:用于存储基本数据类型(如数字、字符串、布尔值)、函数调用的参数和局部变量等。栈内存是自动分配的,并且遵循后进先出(LIFO)的原则。

代码段:存储JavaScript代码本身。代码段是只读的,防止程序意外地修改了它的指令。

执行上下文

        执行上下文是JavaScript引擎在执行代码时创建的一个环境,它定义了变量和函数的可访问性。每当JavaScript引擎开始执行一段代码(全局代码、函数代码或eval代码)时,它都会创建一个新的执行上下文,并将其推入执行上下文栈。

执行上下文的类型分为三种:        

  • 全局执行上下文:只有一个,浏览器中的全局对象就是window对象,this指向这个全局对象。当脚本开始执行时创建,它包含了全局作用域中定义的变量和函数。全局执行上下文始终存在,并且在整个脚本执行期间都保持活动状态。
  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文。每当一个函数被调用时,JavaScript引擎都会为其创建一个新的函数执行上下文。函数执行上下文包含了函数内部的局部变量、参数、以及函数的内部作用域链。
  • Eval函数执行上下文:指的是运行在eval函数中的代码,很少用而且不建议使用。当使用eval()函数执行代码时,也会创建一个新的执行上下文。不过,由于eval()函数的安全风险和性能问题,现代JavaScript开发中很少使用它。

        只有全局上下文(的变量)能被其他任何上下文访问。可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问。

        执行上下文栈是JavaScript引擎用于管理执行上下文的数据结构。当一个新的执行上下文被创建时,它会被推入执行上下文栈的顶部。当当前执行上下文执行完毕后(例如,函数执行完成或遇到return语句),它会被从执行上下文栈中弹出,控制权返回到前一个执行上下文。

闭包的使用场景

        任何闭包的使用场景都离不开这两点:

  • 创建私有变量和方法
  • 延长变量的生命周期

        一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的。

        闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

function makeSizer(size) { //例子:在页面上添加一些可以调整字号的按钮return function() {document.body.style.fontSize = size + 'px';};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;

柯里化函数

        目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用。 指的是将一个多参数的函数拆分成一系列函数,每个拆分后的函数都只接受一个参数。将多参数的函数转换成单参数的形式。

使用闭包模拟私有方法

        在JavaScript中,没有支持声明私有变量,但我们可以使用闭包来模拟私有方法。

其他

        例如计数器、延迟调用、回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期。

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

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

相关文章

MySQL认证方法介绍

阅读本文之前请参阅----MySQL 数据库安装教程详解(linux系统和windows系统) MySQL数据库的认证方法对于确保数据安全和维护系统完整性至关重要。在MySQL中,有多种认证方法可供选择,每种方法都有其特定的用途和配置方式。本文将详细…

2024.1.9-1.24

2024.1.9 TUE 类路径 feign远程调用 content-service的test调用media-api的如下接口,用来上传图片 nginx的代理 如上图,proxy_pass 后面跟的代理到的地址后面须有/否则不生效!!!! content-service定义…

C++的发展历史、简介及应用

文章目录 一、C的来历及诞生背景二、C的每个版本时间三、C的详细应用领域 一、C的来历及诞生背景 C是一种编程语言,它是在C语言的基础上发展而来的。 C的作者:C的创始人是丹尼斯里奇(Dennis Ritchie)和贝尔实验室的团队。他们在2…

医学试纸条图像处理技术

医学试纸条图像处理是一个重要的领域,它涉及到从医学试纸条上提取和分析信息的各种技术。这里是一些常见的工作步骤: 一、图像预处理:在处理任何图像之前,通常需要进行预处理步骤,以改善图像质量并准备后续分析。这可…

ETH Denver见!来参加DAO的领袖和爱好者的活动吧

我们将和 DAOBase 在美国丹佛举办 DAO 领袖和爱好者的盛会——“去中心化对话:DAO 治理的新时代”活动! 随着加密货币和区块链技术的快速发展,DAO 已成为数字经济不可或缺的一部分。目前,已有超过 10 万个 DAO,拥有超…

算法刷题 DAY60

647.回文子串 int countSubstrings(char* s) {int res0;int lenstrlen(s);bool dp[len][len];for(int i0;i<len;i){for(int j0;j<len;j){dp[i][j]false;}}for(int ilen-1;i>0;i--){for(int ji;j<len;j){if(s[i]s[j]){if(j-i<1){dp[i][j]true;res;}else {if(dp[…

Go语言必知必会100问题-05 接口污染

接口污染 在Go语言中&#xff0c;接口是我们设计和编写代码的基石。然而&#xff0c;像很多概念一样&#xff0c;滥用它是不好的。接口污染是指用不必要的抽象来编写代码&#xff08;刻意使用接口&#xff09;&#xff0c;使得代码更难以理解。这是具有不同习惯&#xff0c;特…

qt creator5.15.2用的是什么版本的图形api?

Qt Creator 5.15.2 使用的图形API取决于配置和目标平台。 Qt Creator是一个跨平台的集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于Qt应用程序的开发。它支持多种编译器和开发工具链&#xff0c;并且可以针对不同的平台和设备进行应用程序的编译和调试。在Qt 5…

Rust-windows安装环境

文章目录 前言一、Using rustup (Recommended)二、配置vscode解决办法&#xff1a;在终端依次运行如下两条指令&#xff1a; 总结 前言 Rust学习系列&#xff0c;之前介绍了macOS环境下的rust安装方式macOS rust安装。这篇学习windows的rust安装方式。 提示&#xff1a;以下是…

Cocoa Touch 框架及其步骤

Cocoa Touch 框架是 Apple 为 iOS 应用开发提供的一套原生开发工具包&#xff08;SDK&#xff09;&#xff0c;它包含了一系列用于构建 iOS 应用程序的 API 和服务。使用 Cocoa Touch 框架&#xff0c;开发者可以创建具有丰富用户界面和流畅交互体验的应用程序。 构建应用界面…

【STM32备忘录】【STM32WB系列的BLE低功耗蓝牙】一、测试广播配置搜不到信号的注意事项

文章目录 一、预备知识&#xff1a;二、准备工具&#xff1a;三、FUS和无线协议栈更新流程四、广播例程测试五、DEBUG输出调试 一、预备知识&#xff1a; WB系列是双核单片机&#xff0c;用户写M4&#xff0c;无线协议栈使用M0新买到手的单片机&#xff0c;需要自己刷入使用的…

TF-IDF,textRank,LSI_LDA 关键词提取

目录 任务 代码 keywordExtract.py TF_IDF.py LSI_LDA.py 结果 任务 用这三种方法提取关键词&#xff0c;代码目录如下&#xff0c; keywordExtract.py 为运行主程序 corpus.txt 为现有数据文档 其他文件&#xff0c;停用词&#xff0c;方法文件 corpus.txt 可以自己…

DP读书:《半导体物理学(第八版)》(一)绪论 3min速通

DP读书&#xff1a;《半导体物理学&#xff08;第八版&#xff09;》刘恩科 3min速通半导体物理之绪论 DP读书&#xff1a;《半导体物理学&#xff08;第八版&#xff09;》刘恩科绪论第一章 半导体中的电子状态1.1 半导体的晶格结构和结合性质1.1.1 金刚石型结构和共价键1.1.2…

代码随想录算法训练营day37 | 738.单调递增的数字、 968.监控二叉树

738.单调递增的数字 暴力超时&#xff0c;需要找到规律&#xff0c;比如98结果为89&#xff0c;214结果为199&#xff0c;从后向前遍历&#xff0c;如果i-1位>i位&#xff0c;则i-1位减一&#xff0c;后面其他位都改为9 class Solution:def monotoneIncreasingDigits(self…

探索未来:人工智能的前沿技术与应用

探索未来&#xff1a;人工智能的前沿技术与应用 人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;作为一项前沿技术&#xff0c;正日益深入到我们的生活和工作中。在未来&#xff0c;人工智能将扮演着越来越重要的角色&#xff0c;影响着我们的社会、经…

Linux 内核和操作系统发行版的关系

目录 1. 查看当前&#xff08;Linux&#xff09;操作系统的内核版本 2. 查看当前&#xff08;Linux&#xff09;操作系统的发行版本 2.1. 典例 3. 内核和操作系统的关系&#xff1f; 4.参考 1. 查看当前&#xff08;Linux&#xff09;操作系统的内核版本 uname -r 系统将…

Java static final 常量详解

1. static 可以用来修饰 成员变量——类变量成员方法——类方法内部类——静态内部类&#xff0c;不能修饰普通类 因为由static修饰&#xff0c;均存在方法区中。 1.1 类变量 修饰变量时&#xff0c;变量属于类&#xff0c;不属于实例对象&#xff0c;直接使用 类名.变量…

yaml-cpp开源库使用

源码下载&#xff1a;https://github.com/jbeder/yaml-cpp 1.yaml-cpp编译 步骤主要如下&#xff1a;进入源码目录后 mkdir build cd build cmake … make make install 2.代码示例 #include "funset.hpp" #include <string> #include <fstream> #i…

MySQL 的存储引擎有哪些?它们各自有什么特点?解释一下 ACID 是什么?在 MySQL 中如何保证 ACID?

MySQL 的存储引擎有哪些&#xff1f;它们各自有什么特点&#xff1f; MySQL 支持多种存储引擎&#xff0c;每种引擎都有其特定的使用场景和特性。以下是一些常见的 MySQL 存储引擎及其特点&#xff1a; InnoDB&#xff1a; 事务安全&#xff1a;支持 ACID 事务。 行级锁定&…

直播|千帆杯Al原生应用开发挑战赛——对话第一期最强挑战者

百度智能云千帆杯Al原生应用开发挑战赛正在如火如荼进行中&#xff0c;经过几百位参赛选手的激烈角逐&#xff0c;第一期游乐场排队规划助手赛题&#xff0c;24岁的南京大学研三学生杨之正荣获最强挑战者。 2月22日19:00-20:00&#xff0c;我们邀请第一期最强挑战者杨之正、百…