(执行上下文作用域链)前端八股文修炼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,默认为全局对象 window
    const 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.mfbz.cn/a/490623.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

systemd-journal(一)之journalctl命令详解

文章目录 写在前面概述描述不传递参数传递一个或多个匹配参数示例 源选项用法--system, --user-M, --machine-m, --merge-D DIR, --directoryDIR--fileGLOB--rootROOT--imageIMAGE--image-policypolicy--namespaceNAMESPACE 过滤选项用法-S, --since, -U, --until举例&#xff…

Navicat15安装教程

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

力扣--并查集1631.最小体力消耗路径

这题将图论和并查集联系起来。把数组每个位置看成图中的一个节点。 这段代码的主要思路是: 遍历地图中的每个节点,将每个节点与其相邻的下方节点和右方节点之间的边加入到边集合中(因为从上到下和从下到上他们高度绝对值一样的,…

浅谈如何自我实现一个消息队列服务器(3)—— 细节分析

文章目录 2.2 消息存储在文件时涉及到的流对象2.3 序列化、反序列化的方法2.3.1 JSON的ObjectMapper2.3.2 ObjectOutputStream 、 ObjectInputStream2.3.3 第三方库的Hessian2.3.4 protobuffer2.3.5 thrift 2.4 使用类MessageFileManager封装文件存储操作2.4.1 sendMessage()实…

【保姆级讲解Edge兼容性问题解决方法】

🌈个人主页:程序员不想敲代码啊🌈 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家🏆 👍点赞⭐评论⭐收藏 🤝 希望本文对您有所裨益,如有不足之处,欢迎在评论区提…

【JavaScript】JavaScript 程序流程控制 ⑦ ( do-while 循环概念 | do-while 循环语法结构 )

文章目录 一、while 循环1、while 循环概念2、do-while 循环语法结构 二、do-while 循环代码示例1、打印 1-5 数字2、打印 1-10 累加和 一、while 循环 1、while 循环概念 JavaScript 中的 do-while 循环 是 while 循环的变体 , 是 一种 后测试 循环 , 该循环的 循环体 至少执行…

Windows系统安装PyTorch框架支持AMD Radeon显卡/Intel显卡

前言 PyTorch框架作为一种主流的、对新手友好的深度学习框架,应用的范围越来越广泛,但是作为一种深度学习框架,使用显卡进行加速训练是一种常见的需求,而PyTorch框架官方支持对NVIDIA卡支持更加友好,这一点从官方的安…

fastadmin学习01-windows下安装部署

下载源代码 官网 安装 解压,然后使用phpstorm打开 修改配置文件 创建数据库 -- drop database fastadmin01; create database fastadmin01;这样fastadmin就部署好了 访问主页也能看到前台页面

什么是 SD-WAN 云端部署?

SD-WAN(软件定义广域网)是一种网络架构,可以通过软件定义和控制来管理广域网连接,提高网络的灵活性、可靠性和安全性。而SD-WAN的云端部署则是将SD-WAN 解决方案部署在云端环境中,利用云计算的优势来实现网络管理和优化…

MySQL详细教程

文章目录 前言一、数据库管理1.查看已有的数据库2.创建数据库3.删除数据库4.进入数据库 二、 数据表管理1.查看当前数据库下的所有数据表2.创建数据表3.删除表4.查看表结构 三、常用数据类型1.整型tinyintintbigint 2.浮点型floatdoubledecimal 3.字符型char(m)varchar(m)textm…

错误 LNK1104 无法打开文件“mfc140.lib”

如图,编译一个别人已有的项目,我的编译报错为: 但是我所有文件夹全局搜索了一下,这个文件是存在的。但是当前项目访问不到。 更改方法:项目->属性->配置属性->VC目录->库目录 全局搜索找到mfc140.lib的…

【工具篇】总结比较几种绘画软件的优缺点

目录 一、Visio二、Processon三、draw.io四、亿图图示五、wps 写在文章开头,感谢你的支持与关注!小卓的主页 一、Visio Visio 是微软公司开发的一款流程图和图表绘制软件。我们可以用它来创建各种类型的图表,如流程图、组织结构图、网络图、平…

计算机基础--发展史

1进化史 计算工具,机械计算机,电子计算机(目前) 1.1计算工具 1算筹,算盘(这些都是计算工具,算数还是得靠大脑算 ) 2机械计算机 2.1帕斯卡计算器 2.2莱布尼茨乘法器 2.3Curta计数…

聚类分析|基于层次的聚类方法及其Python实现

聚类分析|基于层次的聚类方法及其Python实现 0. 基于层次的聚类方法1. 簇间距离度量方法1.1 最小距离1.2 最大距离1.3 平均距离1.4 中心法1.5 离差平方和 2. 基于层次的聚类算法2.1 凝聚(Agglomerative)2.3 分裂(Divisive) 3. 基于…

【蓝桥杯】tarjan算法

一.概述 Tarjan 算法是基于DFS的算法,用于求解图的连通性问题。 Tarjan 算法可以在线性时间内求出: 无向图: 割点与桥双连通分量 有向图: 强连通分量必经点与必经边 1.割点: 若从图中删除节点 x 以及所有与 x 关联的…

【Java项目】jspm九宫格日志网站

目录 背景 技术简介 系统简介 界面预览 背景 互联网的迅猛发展彻底转变了全球各类组织的管理策略。自20世纪90年代起,中国的政府机关和各类企业便开始探索利用互联网技术来处理管理信息。然而,由于当时网络覆盖不广、用户接受度不高、互联网法律法规…

一文说清:AI大模型在制造业中的应用类型

在过去的几年里,全球制造业的竞争格局正在发生重构,数字化和智能化成为推动变革的关键力量。AI 大模型作为一种通用人工智能技术,其革命性特征体现在能够生成代码、构建人机交互新模式,并与产品研发、工艺设计、生产作业、产品运营…

羊大师解析,孩子喝羊奶的好处

羊大师解析,孩子喝羊奶的好处 孩子喝羊奶有诸多好处。羊奶富含多种营养物质,包括蛋白质、脂肪、维生素和矿物质等,对孩子的生长发育和身体健康都有积极的促进作用。羊奶中的蛋白质含量丰富,且易于消化吸收。这些优质蛋白质可以为…

《海王2》观后感

前言 我原本计划电影上映之后,去电影院观看的,但时间过得飞快,一眨眼这都快4月份了,查了一下,电影院早就没有排片了,所以只能在B站看了,这里不得不吐槽一下,原来花了4块钱购买观看还…

Hudi部署

目录 前言 Hudi的介绍 一、Hudi是什么? 二、Hudi的特点功能和优势 三、Hudi的使用场景 Hudi的搭建部署 一、准备 二、搭建 1)搭建JAVA环境和Hadoop环境 2)部署zookeeper 3)部署Spark on yarn 4)部署maven环…
最新文章