2024年前端面试中JavaScript的30个高频面试题之中级知识

基础知识
高级知识

13. 什么是闭包?闭包的用例有哪些?

闭包是一个功能,它允许函数捕获定义该函数的环境(或保留对作用域中变量的访问)即使在该作用域已经关闭后。

我们可以说闭包是函数和词法环境的组合,其中定义了该函数。

换句话说,闭包为函数提供了访问自己的作用域、外部函数的作用域和全局作用域的能力,允许它“记住”并继续访问这些作用域中的变量和参数。

function outerFunction() {
  let outerVariable = 'I am from the outer function';
  
  return innerFunction() {
    console.log(outerVariable); // 访问外部函数作用域中的outerVariable
  }
  
}

let myFunction = outerFunction();
myFunction(); // 输出:I am from the outer function

每次在函数创建时以及在另一个函数内部定义函数时都会创建闭包。

执行上下文是一个执行JavaScript代码的环境。 对于每个函数调用,都会创建一个单独的执行上下文并推送到执行堆栈中。 一旦函数执行完成,它就会从堆栈中弹出。

每个执行上下文都有一个内存空间,其中存储了其变量和函数,一旦从执行堆栈中弹出函数,JavaScript垃圾收集器就会清除所有这些内容。

在JavaScript中,只有当没有引用某个对象时,该对象才会被垃圾回收。

在上面的示例中,匿名执行上下文仍对其外部环境的内存空间中的变量有引用。 即使outerFunction()已完成(它可以访问 outerVariable 变量并在console.log(outerVariable)中使用它)。

JavaScript中的闭包有几个重要用例:

  1. 数据隐私和封装:闭包可用于创建私有数据和封装有限范围内的功能。 通过在另一个函数内定义函数,内部函数可以访问外部函数的变量,但这些变量对外部函数不可访问。 这允许创建对外不直接可访问的私有数据和方法,从而增强了数据隐私和封装。

  2. 状态维护:闭包通常用于在异步操作和事件处理中维护状态。 例如,在处理异步任务时,闭包可以捕获和保留跨多个异步操作的变量状态,确保在异步任务完成时可以访问到正确的变量。

  3. 柯里化和偏函数应用:闭包有助于函数式编程技术如柯里化和偏函数应用。 通过使用闭包捕获和记住特定参数并返回使用这些捕获参数的新函数,可以实现柯里化和偏函数应用。 这允许创建具有预设参数的特化函数,提供灵活性和可重用性。

  4. 模块模式:闭包在实现JavaScript中的模块模式中至关重要。 通过使用闭包创建私有变量并只公开必要的公共方法,开发人员可以创建模块化和组织良好的代码,防止对内部模块数据的不必要访问和修改。

  5. 回调函数:在使用回调函数时,经常使用闭包。 闭包可用于在异步操作的上下文中捕获和维护变量的状态,以确保在调用回调函数时可以访问到正确的变量。

14. 解释JavaScript中的变量提升概念。

JavaScript中的变量提升是变量和函数声明自动移至其包含作用域顶部的默认行为。 这发生在编译阶段,在实际代码执行之前。 这意味着您可以在代码中声明之前使用变量或调用函数。

使用 var声明变量时,声明会被提升到包含函数或块的顶部,并使用默认值“undefined”初始化

console.log(x); // 输出:undefined
var x = 5; 

使用 letconst 声明的变量也会被提升,但是它们有一个“暂时性死区”,在该区域中不能在声明之前被访问。

console.log(x); // 抛出错误(ReferenceError) 
let x = 5; 

函数声明也会被提升到其包含作用域的顶部。您可以在代码中声明之前调用函数。

sayHello(); // 输出:Hello, world!
function sayHello() {
  console.log("Hello, world!"); 
}

箭头函数、函数表达式或变量初始化不会被提升。

15. 什么是暂时性死区?

暂时性死区(TDZ)是与使用 letconst 声明变量相关的 JavaScript 概念。

当您使用 letconst 声明一个变量时,它会被提升到其包含作用域的顶部,但是与 var 不同,使用 letconst 声明的变量在 TDZ 中保持未初始化状态。

在作用域内实际声明变量之前尝试访问或使用该变量会导致 ReferenceError。这可防止在变量被适当定义之前使用它。

了解暂时性死区很重要,因为它有助于防止变量在初始化之前使用导致的相关错误。它还通过鼓励在使用之前适当声明变量来推广JavaScript编码的最佳实践。

16. 什么是原型链? 以及 Object.create() 方法?

在 JavaScript 中,每个函数和对象默认都有一个名为 prototype 的属性。

JavaScript中的每个对象都有一个原型。 原型是当前对象继承属性和方法的另一个对象。 您可以将原型视为模板或父对象。

原型链是允许对象从其他对象继承属性和方法的机制

在对象上访问某个属性或方法时,JavaScript会首先在对象本身上查找它。 如果找不到,它会在原型链上向上查找,直到找到该属性或方法。 此过程会一直持续到到达链顶部的 Object.prototype 为止。

17. Call、Apply和Bind方法的区别是什么?

Call: call()方法使用指定的this值调用函数,并以逗号分隔的值的形式传入单独的参数

const person1 = { name: 'John' };
const person2 = { name: 'Jane' };

function greet(greeting) {
    console.log(greeting + ' ' + this.name); 
}

greet.call(person1, 'Hello'); // 输出:Hello John
greet.call(person2, 'Hi'); // 输出:Hi Jane  

使用 call() 方法,一个对象可以调用另一个对象所拥有的方法。

const o1 = {
  name: 'ravi',
  getName: function(){  
    console.log(`Hello, ${this.name}`)
  }
}

const o2 = {
  name: 'JavaScript Centric'  
}

o1.getName.call(o2) // Hello, JavaScript Centric

Apply: 使用给定的 this 值调用函数,但是它使用数组的形式接受参数。 当参数的数量未知或者参数已在数组中时,Apply非常有用。

const numbers = [1, 2, 3, 4, 5];   

const max = Math.max.apply(null, numbers); 
console.log(max); // 输出:5

Bind: 与调用它不同,bind() 会返回一个新函数,并允许您传入任意数量的参数。bind() 方法接受一个对象作为第一个参数,并创建一个新函数。

const module = {
    x: 42,
    getX: function() {
        return this.x; 
    }  
};  

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); // 输出:42

18. 什么是lambda或箭头函数?

JavaScript中有两种类型的函数:

  1. 常规函数
  2. 箭头函数(在 ES6 中引入)

常规函数: 我们可以通过两种方式编写常规函数,即函数声明函数表达式

箭头函数或胖箭头函数:也称为 lambda 函数,是在 JavaScript(ES6)中引入的一种更简洁的函数表达式语法。 与传统的函数表达式相比,它们具有较短的语法,在创建匿名函数和使用函数式编程概念方面特别有用

这里没有声明方法,我们只能通过函数表达式来编写。

箭头函数和常规函数之间有一些区别:

  1. 语法
  2. 没有参数 (参数是类数组对象)
  3. 箭头函数没有原型对象
  4. 不能用 new 关键字调用 (不是构造函数)
  5. 没有自己的 this (call、apply 和 bind 不会按预期工作)
  6. 它不能用作生成器函数
  7. 不允许重复命名的参数

19. 什么是柯里化函数?

柯里化是函数式编程中的一种技术,它将接受多个参数的函数转换成一系列每个接收单个参数的函数。 通过组合这些柯里化的函数,可以构建更复杂的函数。

在 JavaScript 中,您可以使用闭包和返回函数来实现柯里化。

// 接收两个参数的常规函数  
function add(x, y) {
    return x + y;
} 
// 函数的柯里化版本  
function curryAdd(x) {
    return function(y) {
        return x + y;
    };
}const add5 = curryAdd(5); // 偏函数应用,创建新函数  
console.log(add5(3)); // 输出:8

柯里化在函数式编程中很有用,它可以使代码更模块化和可重用。 当您想要使用变参函数或者构建数据转换流水线时,它特别有用。

20. ES6的特性有哪些?

ES6,也称为 ECMAScript 2015,为 JavaScript 引入了许多新特性和增强功能,极大地扩展了该语言的功能。 ES6的一些关键特性包括:

  1. 箭头函数
  2. 块作用域变量
  3. 模块
  4. 模板字面量: 模板字面量允许使用反引号嵌入表达式和多行字符串,这提供了在 JavaScript 中创建复杂字符串的更方便的方法。
  5. 默认参数
  6. Rest和Spread运算符
  7. 解构赋值
  8. Promise
  9. Map、Set、WeakMap、WeakSet: ES6 引入了新的内置数据结构,如 Map 和 Set,可以更高效和专门地处理集合和键值对。
  10. 迭代器和生成器
  11. 增强的对象字面量

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

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

相关文章

vulnhub靶场之DC-5

一.环境搭建 1.靶场描述 DC-5 is another purposely built vulnerable lab with the intent of gaining experience in the world of penetration testing. The plan was for DC-5 to kick it up a notch, so this might not be great for beginners, but should be ok for p…

深度学习笔记(四)——TF2构建基础网络常用函数+简单ML分类网络实现

文中程序以Tensorflow-2.6.0为例 部分概念包含笔者个人理解,如有遗漏或错误,欢迎评论或私信指正。 截图和程序部分引用自北京大学机器学习公开课 TF2基础常用函数 1、张量处理类 强制数据类型转换: a1 tf.constant([1,2,3], dtypetf.floa…

鸿蒙开发环境搭建-高频环境问题解决

1.Node版本问题 由于SDK的部分工具依赖Node.js运行时,推荐使用配套API版本的Node.js,保证工程的兼容性。 匹配关系见下表: API LevelNode.js支持范围API Level≤914.x(≥14.19.1)、16.xAPI Level>914.x&#xff0…

Linux tail命令详解和高级用法举例

目 录 一、概述 二、tail命令解释 1.命令格式; 2.功能 3.选项 4.选项的基本用法 (1) 显示行号 (2)忽略指定字符数 (3) 不显示文件名 三…

小白进公司快速熟悉环境和代码的方法

1.企业开发模式 企业开发模式里,我们的项目模块可能非常多此时我们是不能将所有模块都拉取到本地的,主要原因如下: 我们很可能并没有全部工程代码的权限 微服务集群部署非常复杂,本地部署成本太高 微服务模块众多,本…

NAND Separate Command Address (SCA) 接口命令解读

CA output packet和CA input packet是Separate Command Address (SCA) NAND接口协议中用于命令和地址传输的关键数据结构。 CA Input Packet: 在SCA接口中,输入到NAND器件的命令和地址信息被组织成并行至串行转换的CA(Command and Address)输…

装机必看:电脑Bios里的CSM兼容模块是啥?打开有啥用?

前言 最近朋友装了一台新的电脑,用的i5-13490f的CPU。但是由于预算有限,手边只有一块GTX650ti,没办法,只好先这么用着了。 谁知道出现了个大问题:电脑开机居然没办法显示。 由于电脑所有的配件基本上都是全新的&…

查看SQL Server的表字段类型、长度、描述以及是否可为null

文章目录 初步理解小步测试组合一下参考文章有更详细评述 继续理解得到大部分信息 本文参考:https://blog.csdn.net/josjiang1/article/details/80558068。 也可以直接点击这里文章链接: sql server查询表结构(字段名,数据类型&a…

Jmeter Linux环境压测Lottery接口

1、把Dubbo插件放到Linux中Jmeter的lib/ext目录下 2、参数化 3、设置线程数 4、把测试计划中的Dubbo路径替换成Linux中的路径 /home/apache-jmeter-5.5/lib/ext 5、上传压测脚本到压力机 6、执行压测,观察是否有消息积压 ①Jmeter中执行压测脚本 ②检查mq控制台是…

开箱即用之 获取系统的CPU、内存、网络、磁盘使用率

页面示例 引入对应pom依赖 <!-- 系统信息相关 --><dependency><groupId>com.github.oshi</groupId><artifactId>oshi-core</artifactId><version>6.4.0</version></dependency> 代码示例 /*** 获取cpu信息*/public sta…

Javaweb之SpringBootWeb案例查询部门以及前后端联调的详细解析

2.1 查询部门 2.1.1 原型和需求 查询的部门的信息&#xff1a;部门ID、部门名称、修改时间 通过页面原型以及需求描述&#xff0c;我们可以看到&#xff0c;部门查询&#xff0c;是不需要考虑分页操作的。 2.1.2 接口文档 部门列表查询 基本信息 请求路径&#xff1a;/depts …

视频转码:掌握mp4视频格式转FLV视频的技巧,视频批量剪辑方法

在多媒体时代&#xff0c;视频格式的转换成为一种常见的需求。把MP4格式转换为FLV格式&#xff0c;FLV格式的视频文件通常具有较小的文件大小&#xff0c;同时保持了较好的视频质量。批量剪辑视频的方法能大大提高工作效率。下面来看云炫AI智剪如何进行MP4到FLV的转码&#xff…

【Scala】——流程控制

1 if-else 分支控制 让程序有选择的的执行&#xff0c;分支控制有三种&#xff1a;单分支、双分支、多分支 1.1单分支 if (条件表达式) {执行代码块 }1.2 双分支 if (条件表达式) {执行代码块 1 } else {执行代码块 2 }1.3 多分支 if (条件表达式1) {执行代码块 1 } else …

真实可用,Xshell7 期待您的安装使用

xshell https://pan.baidu.com/s/1OKC1sQ1eYq6ZSC8Ez5s0Fg?pwd0531 1.鼠标右击【Xshell7.zip】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09; 2.双击Xshell-7.0.0065.exe 执行安装操作 3.选择【是】 4.点击【下一步】 5.选择【我接受...】 6.点击…

Linux中DNS域名解析服务及实验

一、DNS介绍 1、DNS 是域名系统&#xff0c;应用层协议&#xff0c;是互联网的一项服务&#xff0c;是将域名转换成网络可以识别的IP地址&#xff0c;再通过IP地址访问主机。这种由文字组成的名称更容易记忆。 DNS是“域名系统"的英文缩写。它作为将域名和IP地址相互映…

Android开发基础(四)

Android开发基础&#xff08;四&#xff09; 本篇将从Android数据存储方式去理解Android开发。 Android数据存储方式 Android提供了多种数据存储方式。 一、SharedPreferences存储 主要用于存储一些简单的配置信息&#xff0c;如登录账号密码等&#xff1b; 这种存储方式采…

更换电脑必装软件【mac电脑】快速装机流程

一、安装软件 source treevscodeapifoxchromerectangleclashx pro 二、开发环境构建 安装nvm&#xff0c;参考这篇文章使用nvm 安装node 三、使用vscode 运行 js 文件 3.1 安装vscode插件 code-runner 3.2 如果报错/bin/sh: node: command not found 解决办法&#xff0c…

Java常用类---Math类和Random类

Math类 简介 Java中&#xff0c;Math类包含了用于执行基本数学运算的属性和方法。Math类的方法都被定义为static形式(静态方法)&#xff0c;通过Math类可以直接在主函数中直接调用。 如下图所示&#xff0c;Math.PI等于圆周率π、Math.E等于常量e……等属性和方法。 部分Mat…

【MIdjourney】关于图像中人物视角的关键词

本篇仅是我个人在使用过程中的一些经验之谈&#xff0c;不代表一定是对的&#xff0c;如有任何问题欢迎在评论区指正&#xff0c;如有补充也欢迎在评论区留言。 1.全景镜头(panorama) 全景镜头是一种广角镜头&#xff0c;可以捕捉到比普通镜头更广阔的视野范围。全景镜头&…

C++内存分配策略

目录 基础概念 内存布局 分配方式 实现 1.new和delete 2.利用空间配置器alloc 3.用malloc和free 4.静态内存分配 基础概念 在讲内存分配之前&#xff0c;先对一些基础概念进行阐述&#xff0c;以便能更好的讨论问题 内存布局 代码编译为可执行程序后运行占用的内存可…