(执行上下文作用域链)前端八股文修炼Day4

在这里插入图片描述

一 作用域作用域链

作用域(Scope)是指程序中定义变量的区域,作用域规定了在这个区域内变量的可访问性。在 JavaScript 中,作用域可以分为全局作用域和局部作用域。

  • 全局作用域:在代码中任何地方都可以访问的作用域,全局作用域中声明的变量在整个程序中都可以被访问。

  • 局部作用域:在函数内部定义的作用域,只能在函数内部访问到的变量称为局部变量,它们的作用域仅限于所在的函数内部。

在 JavaScript 中,作用域链(Scope Chain)是指当代码在某个作用域(比如函数)执行时,JavaScript 引擎会按照定义变量的位置来查找变量的过程。作用域链是由当前执行环境的变量对象、外部函数的变量对象和全局变量对象组成的链式结构。

作用域链的工作原理如下:

  1. 当函数被调用时,JavaScript 引擎会创建一个执行环境(Execution Context)。
  2. 在执行环境中,会创建一个变量对象(Variable Object),用于存储该函数内定义的变量。
  3. 如果在当前函数中无法找到某个变量,JavaScript 引擎会沿着作用域链向上查找外部函数的变量对象,直到找到匹配的变量或者到达全局作用域为止。

理解作用域和作用域链对于编写复杂的 JavaScript 程序至关重要,因为它决定了变量的可见性和访问规则。正确理解作用域链有助于避免变量命名冲突、提高代码可读性和维护性。

回答示例:

当回答关于作用域和作用域链的问题时,你可以采取以下方法来清晰地向面试官解释:

  1. 简明扼要的定义:开始时给出一个简单而清晰的定义,例如:“作用域是指变量和函数的可访问性范围,而作用域链是用来解析变量位置的机制”。

  2. 全局作用域和局部作用域:解释全局作用域和局部作用域的概念,说明全局作用域中定义的变量可以在整个程序中访问,而局部作用域中定义的变量只能在特定的函数内部访问。

  3. 作用域链的形成:说明作用域链是由当前执行环境的变量对象、外部函数的变量对象和全局变量对象组成的链式结构,用来确定变量的访问顺序。

  4. 作用域链的查找过程:描述在 JavaScript 中如何通过作用域链查找变量的过程,即从当前作用域开始查找,如果找不到则沿着作用域链向上查找,直至找到变量或者到达全局作用域。

  5. 闭包与作用域链的关系:提及闭包(Closure)是作用域链的一个重要应用,它可以让函数访问其父函数作用域中的变量。

  6. 举例说明:通过具体的代码示例来演示作用域和作用域链的概念,展示变量在不同作用域中的访问方式以及作用域链的影响。

  7. 回答问题:准备回答面试官可能提出的相关问题,以确保你能清晰表达你对作用域和作用域链的理解。

二 执行上下文

  1. 定义:执行上下文是 JavaScript 代码执行时的环境,其中包含了变量、函数和其他数据的作用域和环境信息。

  2. 执行上下文的:说明执行上下文是在代码执行时创建的,每个函数调用都会生成一个新的执行上下文。

  3. 执行上下文的组成部分:详细介绍执行上下文的主要组成部分:

    • 变量对象(Variable Object):用于存储该执行上下文中定义的变量、函数声明和形参。
    • 作用域链(Scope Chain):描述了当前执行上下文中可以访问的变量的链式结构。
    • this 值:指向当前执行上下文所在的对象,具体取决于函数被调用的方式。
  4. 执行上下文的生命周期:解释执行上下文的生命周期,包括创建、执行代码和销毁的过程。

  5. 作用域链的作用:强调作用域链在确定变量访问权限时的重要性,以及如何通过作用域链查找变量。

  6. 举例说明:通过一个简单的代码示例来演示执行上下文的概念,例如创建一个函数并访问其中定义的变量,展示执行上下文如何影响变量的访问。

三 闭包

闭包是指一个函数能够访问其词法作用域外部的变量,即使这个函数在词法作用域外被调用。闭包实际上是由函数和其相关的引用环境(包含了该函数创建时所处的词法作用域)组合而成的实体。

以下是一个闭包的示例:

function outerFunction() {let outerVariable = 'I am from the outer function';function innerFunction() {console.log(outerVariable);}return innerFunction;
}let closureExample = outerFunction();
closureExample(); // 输出:I am from the outer function

在这个示例中,innerFunction 是一个闭包,因为它可以访问外部函数 outerFunctionouterVariable 变量。

使用场景:

  1. 保留状态:闭包可以在函数执行完毕后仍然保持对外部变量的引用,因此可以用于保留状态。
  2. 数据封装:闭包可以创建私有变量,实现数据的封装和隐藏,避免全局命名冲突。
  3. 模块化开发:闭包在模块化开发中起到重要作用,可以隐藏实现细节,提供公共接口。
  4. 事件处理程序:在事件处理程序中,闭包可以用来维持回调函数对外部状态的访问。
  5. 异步操作:闭包可以解决异步操作中的变量共享和保持状态的问题。

优点:

  1. 保留状态:可以保持函数执行时的状态,实现状态的保留。
  2. 数据封装:通过闭包可以创建私有变量,避免全局变量污染。
  3. 模块化开发:闭包可以帮助实现模块化设计,提高代码的模块性和可维护性。

缺点:

  1. 内存泄漏:如果闭包中持有大量变量或被长时间引用,可能导致内存泄漏问题。
  2. 性能开销:闭包会增加内存消耗和函数调用的复杂性,可能影响性能。
  3. 理解困难:对于初学者来说,闭包的概念可能比较抽象和难以理解,容易出现使用错误。

综上所述,闭包是 JavaScript 中强大且常用的特性,能够带来很多便利,但也需要注意潜在的问题。正确使用闭包可以提高代码的灵活性和可维护性。如果有任何疑问或需要进一步解释,请随时告诉我!

三 this

在 JavaScript 中,this 是一个关键字,指向当前对象。call()apply()bind() 是用来改变函数中 this 的指向的方法。

  • this:在函数内部,this 指向调用该函数的对象。
  • call():立即调用函数,可以指定函数内 this 的指向,并且允许传入参数列表。
  • apply():立即调用函数,可以指定函数内 this 的指向,并且允许传入参数数组。
  • bind():返回一个新函数,不会立即调用原函数,而是返回一个新函数,可以随后调用,并且固定了 this 的指向。
this 指向

在 JavaScript 中,this 的指向是动态的,取决于代码执行的上下文。下面是一些常见情况下 this 的指向:

  1. 全局环境:在全局环境中,this 指向全局对象(在浏览器中通常是 window 对象)。

  2. 函数中

    • 当函数作为普通函数调用时,this 指向全局对象或者 undefined(在严格模式下)。
    • 当函数作为对象的方法调用时,this 指向调用该方法的对象。
    • 当函数作为构造函数使用(通过 new 关键字调用)时,this 指向新创建的实例对象。
    • 使用 callapplybind 方法可以显式指定 this 的值。
  3. 事件处理函数:在事件处理函数中,this 通常指向触发事件的 DOM 元素。

  4. 箭头函数:箭头函数没有自己的 this,它会继承外层作用域的 this 值,且无法通过 callapplybind 方法改变。

总的来说,this 的指向是动态变化的,根据代码执行的上下文而定。

五 call/apply/bind

在 JavaScript 中,call()apply()bind() 这三个方法都可以用来改变函数内部的 this 指向。它们的参数传入方式略有不同:

  • call() 方法传入的参数是一个列表,可以是一个一个的参数;
  • apply() 方法传入的参数是一个数组,可以包含多个参数;
  • bind() 方法传入的参数是一个列表,与 call() 类似,但它不会立即调用原函数,而是返回一个新的函数。

下面是具体的解释:

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

    • thisArg:指定函数内部的 this 指向的对象。
    • arg1, arg2, ...:函数的参数,可以是多个单独的参数,按顺序传入。
  • apply(thisArg, [argsArray])

    • thisArg:指定函数内部的 this 指向的对象。
    • argsArray:一个数组,包含函数的参数,数组中的每个元素对应一个函数参数。
  • bind(thisArg, arg1, arg2, ...)

    • thisArg:指定函数内部的 this 指向的对象。
    • arg1, arg2, ...:函数的参数,可以是多个单独的参数,按顺序传入。

下面是一个示例,演示了这三种方法的用法:

function greet(name) {console.log(`Hello, ${name}!`);
}const person = {name: 'Alice'
};// 使用 call()
greet.call(person, 'Bob');// 使用 apply()
greet.apply(person, ['Bob']);// 使用 bind()
const greetBound = greet.bind(person, 'Bob');
greetBound();

当然,我可以为你提供一个简单的实现示例,请查看下面的代码:

// 实现 call 方法
Function.prototype.customCall = function(context, ...args) {context = context || window; // 如果未传入 context,默认为全局对象 windowconst fn = Symbol(); // 创建一个唯一的 Symbol 属性以防冲突context[fn] = this; // 将当前函数赋值给 context 的一个属性const result = context[fn](...args); // 执行函数delete context[fn]; // 删除临时属性return result; // 返回执行结果
};// 实现 apply 方法
Function.prototype.customApply = function(context, args) {context = context || window;const fn = Symbol();context[fn] = this;const result = context[fn](...args);delete context[fn];return result;
};// 实现 bind 方法
Function.prototype.customBind = function(context, ...args) {const fn = this;return function(...innerArgs) {return fn.customCall(context, ...args, ...innerArgs);};
};// 测试
function greet(name) {console.log(`Hello, ${name}! My name is ${this.name}.`);
}const person = {name: 'Alice'
};greet.customCall(person, 'Bob');
greet.customApply(person, ['Bob']);
const greetBound = greet.customBind(person, 'Bob');
greetBound();

以上代码演示了如何实现自定义的 call()apply()bind() 方法。这些方法会改变函数内部的 this 指向,并且允许传入参数来调用函数。
这两段代码是用来实现自定义的 call()apply() 方法的。它们的功能是类似的,都是用来改变函数的 this 指向并调用该函数,只是参数传入方式略有不同。让我解释一下它们之间的区别:

区别:
  1. 参数传入方式

    • customCall() 方法使用了 rest 参数 ...args,可以接收多个参数,这些参数会直接传递给被调用的函数。
    • customApply() 方法接收的第二个参数是一个数组 args,它接收一个包含函数参数的数组,然后将数组中的参数展开传递给被调用的函数。
  2. 调用方式

    • customCall() 方法中,使用 ...args 直接将参数列表传递给被调用的函数。
    • customApply() 方法中,将参数数组 args 直接传递给被调用的函数。

虽然它们的功能类似,但是在使用方式上有一定的差异。在实际使用时,可以根据具体情况选择使用哪种方式,如果参数是以数组的形式传递更合适的话,可以选择使用 customApply() 方法。

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

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

相关文章

基于Springboot的狱内罪犯危险性评估系统的设计与实现(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的狱内罪犯危险性评估系统的设计与实现(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller&#…

宝塔部署项目

如何在云服务器上使用宝塔 登录到你的云服务器后,执行宝塔面板安装命令,阿里云服务器网使用的CentOS操作系统,命令如下 yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh …

题。。。。

O - 胜利大逃亡(续) 题目分析 bfs状态压缩(在bfs的基础上,存储持有不同钥匙时,此点位是否走过的情况); -----状态压缩使用二进制实现,同时通过位运算修改是否转移至另一状态(详情见代码及注释…

解决 Xshell 等工具连接虚拟机失败

这里以 Xshell 等工具连接 Linux 虚拟机为例 对于我们使用 Xshell 等工具连接虚拟机失败,我们可以从以下的几个方面进行检查和解决 检查连接工具中的连接会话配置是否正确 对于这方面,我们要检查连接工具中连接会话配置的虚拟机 IP 地址和端口号是否正…

Postman核心功能解析-参数化和测试报告

一、参数化处理 参数化:针对于某一个接口,有大量的的测试数据需要批量验证,一个一个的更改请求参数太耗时耗力,使用参数化批量处理数据会比较高效,常规通过文档参数化实现。 创建文件 格式CSV 文件内第一行信息 需要…

操作系统的理解|冯·若依曼体系结构|进程的状态

操作系统的理解 冯诺伊曼体系结构为什么必须通过内存然后到cpu存储金字塔冯诺伊曼结构的改进在哪?我们可不可以全部用寄存器来做存储器在硬件数据流动角度学以致用:解释程序运行为什么要加载到内存程序没被运行之前存在哪里? 操作系统概念广义…

应急响应实战笔记04Windows实战篇(2)

第2篇:蠕虫病毒 0x00 前言 ​ 蠕虫病毒是一种十分古老的计算机病毒,它是一种自包含的程序(或是一套程序),通常通过网络途径传播,每入侵到一台新的计算机,它就在这台计算机上复制自己&#xff…

第一个C++程序,我也没看明白,暂时。

#include<iostream> using namespace std; int main() { cout << "hello world and you too number!" << endl; system("pause"); return 0; } 运行结果为&#xff1a;

优化生产流程,解决无尘布擦拭留下划痕问题

在现代化工生产中&#xff0c;无尘布被广泛应用于清洁工作&#xff0c;然而&#xff0c;河北一家化工企业在使用无尘布进行擦拭时却发现产品表面留下了划痕&#xff0c;给生产过程带来了不小的困扰。针对这一问题&#xff0c;一家化工企业向供应商优斯特寻求解决方案&#xff0…

AI视频激光综合驱鸟装置:全自动、大范围驱鸟 | 真驱鸟科技

在电力系统中&#xff0c;鸟害事故已成为一个不容忽视的问题&#xff0c;直接威胁到电网的正常运行。但鸟类拥有极强的环境适应能力&#xff0c;它们能够在各种环境中生存和繁衍。这种强大的适应性使得传统的单一功能驱鸟器&#xff0c;在面对鸟类时显得力不从心&#xff0c;无…

苹果与百度合作,将在iPhone 16中使用生成式AI

3月25日&#xff0c;《科创板日报》消息&#xff0c;苹果将与百度进行技术合作&#xff0c;为今年即将发布的iPhone16、Mac系统和iOS 18提供生成式AI&#xff08;AIGC&#xff09;功能。 据悉&#xff0c;苹果曾与阿里巴巴以及另外一家国产大模型厂商进行了技术合作洽谈。最终…

#Linux系统编程(ps和kill命令)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;ps命令 可以列出系统中当前运行的那些进程。 命令格式&#xff1a;ps 参数(常用-aux) 命令功能&#xff1a;用来显示当前进程的状态 常…

[STL]priority_queue类及反向迭代器的模拟实现

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今日主菜&#xff1a; priority_queue类及反向迭代器 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 向着c&…

istio 设置 istio-proxy sidecar 的 resource 的 limit 和 request

方式一 修改 configmap 查看当前 sidecar 的 cpu 和 memory 的配额 在 istio-sidecar-injector 中查找,修改后重启 pod 可以生效(下面那个 proxy_init 配置不管,不知道是干嘛的) 方式二 如果是通过 iop 安装的 istio,可以修改 iop 文件中的配置 spec:values:global:…

程序员35岁真的就是危机吗?

前言 35岁被认为是程序员职业生涯的分水岭&#xff0c;许多程序员开始担忧自己的职业发展是否会受到年龄的限制。有人担心随着年龄的增长&#xff0c;技术更新换代的速度会使得资深程序员难以跟上&#xff1b;而另一些人则认为&#xff0c;丰富的经验和深厚的技术积累是年轻程…

LeetCode 309—— 买卖股票的最佳时机含冷冻期

阅读目录 1. 题目2.解题思路3. 代码实现 1. 题目 2.解题思路 根据题意&#xff0c;每一天有这样几个状态&#xff1a;买入股票、卖出股票、冷冻期、持有股票&#xff0c;因此&#xff0c;我们假设 f 为每天这几个状态下对应的最大收益&#xff0c;由于持有股票时不知道是哪天买…

RocketMQ学习笔记:消息存储模型,持久化文件,过期文件删除

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、消息存储结构1.1、CommitLog详解1.1.1、CommitLog存储的优点 1.2、ConsumeQueue详解1.3、Index详解 2、持久化文件3、过期文件删除机制3.1、判断过期文件3.2、删除的时机 1、消息存储结构…

Navicat15安装教程

直接开始Navicat15的安装教程 下载好上面的资源&#xff0c;解压后得到以下文件 1. 安装 Navicat ①双击 navicat150_premium_cs_x64.exe&#xff0c;准备安装 Navicat 15 ②无脑一直下一步就行&#xff0c;到下图画面就安装成功了。 2.安装完成以后&#xff0c;先不要启动…

第三十一天-Flask-ORM-sqlalchemy

目录 1.什么是ORM 2.flask-sqlalchemy 1安装 2.配置 3.数据库模型设计 ​编辑 4.插入修改删除 5.查询 1.什么是ORM 2.flask-sqlalchemy 1安装 2.配置 3.数据库模型设计 4.插入修改删除 5.查询

LangChain核心概念与组件

Chains Chains可以让你按照一定的顺序和逻辑来执行不同的任务。Chains有以下四种类型&#xff1a; 类型作用LLMChain用于在语言模型周围添加一些功能的简单Chain&#xff0c;它由一个PromptTemplate和一个语言模型&#xff08;LLM或chat model&#xff09;组成&#xff0c;它…