前端面试问题汇总 - JS篇

1. JS的数据类型,如何判断js的数据类型?

        数据类型有:NumberStringBooleanUndefinedNullObjectArray

        其中,Number,String,Boolean,Undefined等基本数据可以直接用 typeof 进行判定。但对于对象类型(如数组和null),typeof通常不能准确判断,它会简单地返回 "object"。为了更准确地判断数据类型,可以使用instanceof运算符来判断对象是否为某个构造函数的实例。对于数组和null,可以使用Array.isArray()方法来判断是否为数组使用== null来判断是否为null

2. 数组去重方法有哪些?

  • 新建数组,循环遍历去重
  • 借助Set数据类型,[...new Set(array)] 或  Array.from(new Set(arr))
  • 新建对象,遍历数组,在转回新的数组

3. 深拷贝和浅拷贝区别?如何实现深拷贝?

        深拷贝和浅拷贝的区别在于是否真正获取了一个对象的复制实体,而不是引用。只针对Object和Array这样的引用数据类型。

        浅拷贝仅仅是复制指向的内存地址,如果原地址中对象被改变,那么浅拷贝出来的对象也会相应改变。

        深拷贝是在计算机中开辟一块新的内存地址用于存放复制的对象。

4. 说一下防抖和节流,分别如何实现?

  • 防抖的原理是在事件触发后等待一段时间,如果在这段时间内没有再次触发事件,则执行该事件,否则重新等待一段时间。适用于用户输入(如搜索框输入)等频繁触发的事件。
// 封装
function debounce(func, delay) {let timerId;return function(...args) {clearTimeout(timerId);
    timerId = setTimeout(() => {func.apply(this, args);}, delay);};
}
// 引用示例const debouncedFunction = debounce(function() {
  console.log('Debounced function executed');
}, 300);
// 触发事件
debouncedFunction(); // 不会立即执行
debouncedFunction(); // 不会立即执行
// 等待300毫秒后执行
// 如果在300毫秒内再次触发,则重新等待300毫秒
  • 节流的原理是规定一个单位时间,在这个单位时间内只能执行一次事件,如果在这个单位时间内触发多次事件,只有一次会生效。适用于用户频繁操作,但是我们希望限制其触发频率的场景,比如滚动加载、拖拽等。
// 封装
function throttle(func, delay) {let canRun = true;return function(...args) {if (!canRun) return;
    canRun = false;setTimeout(() => {func.apply(this, args);
      canRun = true;}, delay);};
}
// 引用示例
const throttledFunction = throttle(function() {
  console.log('Throttled function executed');
}, 300);
// 触发事件
throttledFunction(); // 立即执行
throttledFunction(); // 在300毫秒内再次触发,不会执行

5. 闭包是什么?如何实现?使用场景有哪些?

        闭包(Closure)是指在函数内部创建另一个函数时,内部函数可以访问其外部函数作用域的变量,即使外部函数已经执行结束并返回了,这个内部函数仍然可以访问和修改外部函数的变量。闭包使得函数可以保留对自己定义时所处环境的引用,这样它就可以在其定义的作用域之外执行。

        使用场景:封装私有变量模块化开发延迟执行

6. 闭包优缺点分别有哪些针对闭包缺点有什么解决方案

闭包的优点:

  • 访问外部变量: 闭包可以访问函数外部作用域的变量,使得函数能够访问其创建时所处的环境。
  • 保护变量: 闭包可以帮助保护函数内部的变量,防止外部代码对其进行意外修改,提高了代码的安全性。
  • 实现私有变量和方法: 闭包可以模拟私有变量和方法,使得外部无法直接访问,从而实现了封装。
  • 保存状态: 闭包可以保存函数执行时的状态,使得函数在多次调用之间保持状态的连续性。

闭包的缺点:

  • 内存泄漏: 如果闭包中引用了外部函数的变量,而这个闭包又被长期引用(比如被存储在全局变量或定时器中),可能会导致外部函数的变量无法被释放造成内存泄漏
  • 性能损耗: 使用闭包会增加内存和 CPU 的开销,因为闭包会捕获外部变量的引用,导致函数的作用域链变长,查找变量时需要遍历更多的作用域。

解决闭包缺点的方法:

  • 手动释放引用: 在不再需要使用闭包时,手动释放对外部变量的引用,以便垃圾回收器能够回收相关的内存。
  • 减少闭包的使用范围: 尽量减少闭包的作用域范围,避免将闭包存储在全局变量中或长期引用,以减少内存占用和性能损耗。
  • 使用模块化: 将功能模块化,通过模块化的方式管理变量和方法,可以降低闭包的使用频率,从而减少潜在的内存泄漏问题。
  • 避免滥用闭包: 在设计和编写代码时,避免过度依赖闭包,只在必要的情况下使用闭包,以免造成性能问题和内存泄漏。

7. 什么是JS原型?原型链是什么?

        JS 原型是一个普通的对象,它包含了一组属性和方法,可以被其他对象共享。每个对象都有一个关联的原型对象,可以通过 __proto__ 属性来访问它的原型对象。

        原型链是由对象的原型对象构成的链式结构。当 JavaScript 查找对象的属性或方法时,如果当前对象本身没有该属性或方法,则会沿着原型链向上查找,直到找到相应的属性或方法,或者到达原型链的顶端(即 Object.prototype)。

        原型链的顶端是 Object.prototype,它是所有 JavaScript 对象的根原型对象。

8. 作用域是什么?

        作用域(Scope)是指在程序中定义变量的区域,确定了变量的可访问性和生命周期。

        作用域主要有全局作用域(Global Scope)、局部作用域(Local Scope)两种。

9. 数组的常用方法有哪些?

  • push(el_1, ..., el_N): 将一个或多个元素添加到数组的末尾,并返回数组的新长度
  • pop(): 删除数组的最后一个元素,并返回该元素的值
  • shift(): 删除数组的第一个元素,并返回该元素的值,同时将数组的长度减 1
  • unshift(el_1, ..., el_N): 将一个或多个元素添加到数组的开头,并返回数组的新长度
  • concat(arr_1, ..., arr_N): 返回一个新数组,该数组是由当前数组和其他数组或值连接而成的
  • join(''): 将数组中的所有元素连接成一个字符串,使用指定的分隔符来分隔元素
  • slice(start, end): 返回一个新数组,该数组包含从原始数组中指定开始到结束(不包含)的部分
  • splice(start, deleteCount, item1, ..., itemN): 从数组中添加/删除项目,返回被删除的项目
  • indexOf(query, fromIndex): 返回数组中第一个匹配指定值的索引,如果没有找到则返回 -1
  • lastIndexOf(query, fromIndex): 返回数组中最后一个匹配指定值的索引,如果没有找到则返回 -1
  • forEach((el, index, arr) => {}, thisArg): 对数组的每个元素执行提供的函数
  • map((el, index, arr) => {}, thisArg): 创建一个新数组,该数组的每个元素都是原始数组的对应元素上调用回调函数的结果
  • filter((el, index, arr) => {}, thisArg): 创建一个新数组,包含原始数组中所有通过提供的测试函数的元素
  • reduce((accumulator, currentValue, currentIndex, array) => {}, initialValue): 对数组中的每个元素执行一个提供的函数(从左到右),将结果汇总为单个值
  • find((el, index, arr) => {}, thisArg): 返回数组中满足提供的测试函数的第一个元素的值,如果没有找到则返回 undefined
  • findIndex((el, index, arr) => {}, thisArg): 返回数组中满足提供的测试函数的第一个元素的索引,如果没有找到则返回 -1
  • every((el, index, arr) => {}, thisArg): 测试数组的所有元素是否都通过了指定函数的测试
  • some((el, index, arr) => {}, thisArg): 测试数组的某些元素是否通过了指定函数的测试

10. 对象的常用方法有哪些?

  • Object.keys(obj): 返回一个包含对象所有可枚举属性的数组
  • Object.values(obj): 返回一个包含对象所有可枚举属性值的数组
  • Object.entries(obj): 返回一个包含对象所有可枚举属性键值对的数组,每个键值对表示为 [key, value] 的形式
  • Object.assign(target, source1, source2, ...): 将一个或多个源对象的属性复制到目标对象,并返回目标对象
  • Object.create(proto, propertiesObject): 使用指定的原型对象和属性来创建一个新对象
  • Object.defineProperty(obj, prop, descriptor): 定义对象的一个新属性,或者修改现有属性的特性
  • Object.defineProperties(obj, properties): 定义或修改对象的多个属性的特性
  • Object.getOwnPropertyDescriptor(obj, prop): 返回指定对象上一个自有属性对应的属性描述符
  • Object.getOwnPropertyNames(obj): 返回一个包含指定对象所有自身属性名称的数组
  • Object.freeze(obj): 冻结一个对象,防止对对象进行修改
  • Object.is(value1, value2): 判断两个值是否严格相等,类似于 === 运算符
  • Object.seal(obj): 封闭一个对象,防止添加新属性并将所有现有属性标记为不可配置
  • Object.setPrototypeOf(obj, prototype): 设置一个对象的原型(即 __proto__ 属性)为另一个对象或 null
  • Object.getOwnPropertySymbols(obj): 返回一个包含指定对象自有的所有 Symbol 属性的数组
  • Object.fromEntries(entries): 将一个键值对的列表转换为一个对象

11. 0.1+0.2等于0.3吗?为什么?如何解决?

        0.30000000000000004。这是因为 JavaScript 使用 IEEE 754 浮点数标准来表示数字,而浮点数在计算机中是以二进制形式存储的,有时无法精确地表示十进制小数

12. 如何改变一个函数的上下文?

        要改变一个函数的上下文,可以使用 bind()、call() 或 apply() 方法来实现。这些方法允许您显式地指定函数在调用时应该使用的上下文(即 this 值)。

  • bind() : 创建一个新的函数,该函数与原始函数具有相同的代码和作用域,但是在调用时,其 this 值被绑定到指定的对象
  • call() : 调用函数,并且可以指定函数内部 this 的值,以及其他参数以逗号分隔的形式传递给函数
  • apply() : 与 call() 方法类似,但是接收一个参数数组,而不是一系列单独的参数

13. 如何做全局错误统一处理?

        可以通过window.onerror注册全局错误处理函数并进行处理来实现全局错误的统一处理

14. 如何理解js是单线程的

        JavaScript 是单线程的意味着在任何给定的时刻,JavaScript 引擎只能执行一个任务

        在 JavaScript 中,这个单线程被称为主线程(也称为 UI 线程),它负责执行所有的 JavaScript 代码、处理事件、执行 DOM 操作等。这意味着,当 JavaScript 代码正在执行时,其他任务(如用户输入、定时器事件、HTTP 请求等)必须等待

        这种单线程模型的主要原因是为了简化开发,并减少在多线程编程中可能出现的复杂性和竞态条件。JavaScript 最初是作为浏览器中处理用户交互的脚本语言而设计的,因此,使用单线程模型可以避免多个线程同时修改页面状态引发的问题,如数据竞争、死锁等。

        虽然 JavaScript 引擎是单线程的,但是浏览器环境提供了一些机制来处理并发任务,比如事件循环(Event Loop)和异步编程模型。通过事件循环,JavaScript 可以在等待异步操作完成时继续执行其他任务,以保持页面的响应性和流畅性。

        因此,虽然 JavaScript 是单线程的,但通过异步编程模型和事件循环机制,可以在单线程中实现并发执行任务的效果,从而更好地满足用户交互和应用程序的需求。

15. 事件循环

事件循环的主要工作流程如下:

  1. 执行同步任务(Synchronous Tasks): 当 JavaScript 引擎开始执行代码时,会首先执行当前调用栈中的所有同步任务,直到调用栈为空。
  2. 执行微任务(Microtasks): 在每个宏任务执行完毕之后,会立即执行所有微任务队列中的任务。微任务包括 Promise.then()MutationObserver 和 process.nextTick(Node.js 中)等。
  3. 执行宏任务(Macrotasks): 在微任务执行完毕之后,会从宏任务队列中选择一个任务来执行。宏任务包括 setTimeoutsetIntervalrequestAnimationFrameI/O 操作等。
  4. 等待新的任务: 一旦当前宏任务执行完毕,事件循环会检查是否有新的宏任务需要执行。如果有,事件循环会继续执行宏任务队列中的下一个任务,否则将继续等待新的任务加入。

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

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

相关文章

NVM的安装与配置

目录 一、简介二、下载2.1、windows环境下载地址2.2、安装 三、配置3.1、查看可安装版本3.2、安装版本3.3、使用和切换版本3.4、模块配置 四、其他4.1、全局安装pnpm4.2、常用nvm命令 一、简介 NVM,全称为Node Version Manager,是一个流行的命令行工具&a…

VScode中C++里CompileDebug(winlinux)

C在vscode中配置 1.编译器环境搭建,c_cpp_properties.json生成 前置,mingw64添加入系统环境变量,编辑快捷键:ctrlshiftp修改选项:编译器路径 C:/mingw64/bin/g.exe IntelliSense 模式,这个应该是再说明一…

ucore 实验物理内存管理篇

实验汲取知识 基于段页式内存地址的转换机制页表的建立和使用方法物理内存的管理方法 首先了解如何发现系统中的物理内存;然后了解如何建立对物理内存的初步管理,即了解连续物理内存管理;最后了解页表相关的操作,即如何建立页表…

算法--目录

algorithm: 十种排序算法 二分法-各种应用 algorithm: 拓扑排序 算法中的背包问题 最长子序列问题 前缀和-解题集合 差分数组-解题

第41篇:有限状态机<四>

Q:本期我们介绍有限状态机的应用之二:米里状态机“1101”序列检测器。 A:摩尔状态机1101序列检测器有5个状态,而米里状态机只有4个状态。当状态为s_3且输入为1时,状态机输出1。这里输出与输入一起被标志在状态转移箭头…

vue3 动态class和style

1、需求:一个删除的弹窗,点击会提示“是否需要删除XXXXX(name)”,但是name不固定,所以删除弹窗的width不能写死。(如果不设置width,本项目的弹窗会自适应变得特别长)

mybatis自制插件+注解实现数据脱敏

欢迎来到我的博客,代码的世界里,每一行都是一个故事 mybatis自制插件注解实现数据脱敏 前言数据脱敏的实现方式构思从哪个地方进行脱敏?它怎么知道我什么数据需要脱敏 项目实现拦截器实现注解实现枚举实现效果图展示 前言 在数字时代&#x…

Java哈希查找(含面试大厂题和源码)

哈希查找(Hash Search)是一种基于哈希表(Hash Table)的数据查找方法。哈希表通过使用哈希函数将键(Key)映射到表中的位置来存储数据,从而实现快速的数据访问。哈希查找的效率通常取决于哈希函数…

hive了解系列一

“ 随着智能手机的普及,互联网时代红利的爆发,用户数量和产生的数据也越发庞大。为了解决这个问题,提高数据的使用价值。 Hadoop生态系统就被广泛得到应用。 在早期,Hadoop生态系统就是为处理如此大数据集而产生的一个合乎成本效益…

力扣第20题有效的括号

typedef char STDataType; //动态栈 #define allocator_may_return_null 1typedef struct ST {STDataType* _a;int _top;//栈顶元素int _capacity;//最大容量 }Stack; //初始化栈 void StackInit(Stack *pst);//入栈 void StackPush(Stack* pst, STDataType x);//出栈 void Sta…

英语写作中“大量的”“重大的”“显著的”substantial、considerable、significant的用法

一般“大量的”“重大的”会用a great number of 、a great amount of 、a plenty of 、great等,这些表达都过于trivial ,用好substantial、considerable、significant 会对写作增色不少。 一、对于可数事物,用a considerable/substantial n…

小程序变更主体需要多久?

小程序迁移变更主体有什么作用?小程序迁移变更主体的好处有很多哦!比如可以获得更多权限功能、公司变更或注销时可以保证账号的正常使用、收购账号后可以改变归属权或使用权等等。小程序迁移变更主体的条件有哪些?1、新主体必须是企业主体&am…

每日OJ题_BFS解决最短路①_力扣1926. 迷宫中离入口最近的出口

目录 力扣1926. 迷宫中离入口最近的出口 解析代码 力扣1926. 迷宫中离入口最近的出口 1926. 迷宫中离入口最近的出口 难度 中等 给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 . 表示)和墙&…

Hibernate入门经典与注解式开发大全

本博文主要讲解介绍Hibernate框架,ORM的概念和Hibernate入门,相信你们看了就会使用Hibernate了! 什么是Hibernate框架? Hibernate是一种ORM框架,全称为 Object_Relative DateBase-Mapping,在Java对象与关系数据库之间建…

【uniapp踩坑记】使用z-paging组件,微信小程序端加载不出来问题解决

使用z-paging组件,h5端加载正常,微信小程序端显示空白 今天做分页列表,在插件市场找到了z-paging,照着示例代码写了进去,在h5端能正常使用,在小程序端一直显示空白 尝试过以下无效操作: 1.清除所…

Scrapy 框架基础

Scrapy框架基础Scrapy框架进阶 Scrapy 框架基础 【一】框架介绍 【1】简介 Scrapy是一个用于网络爬取的快速高级框架,使用Python编写他不仅可以用于数据挖掘,还可以用于检测和自动化测试等任务 【2】框架 官网链接https://docs.scrapy.org/en/late…

WPS二次开发系列:WPS SDk功能就概览

作者持续关注WPS二次开发专题系列,持续为大家带来更多有价值的WPS开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397) 作者通过深度测试使用了WPS SDK提供的Demo&#xff0…

给你的 vscode 扩展增加测试设置

文章目录 1. 目的2. vitest 作为 vscode 扩展单元测试3. vscode-test 集成测试4. 自定义 Runner 集成测试5. 小结 1. 目的 vscode 作为当前最多人使用的编辑器和开发工具,其最强大之处就是有成熟的插件社区,但是使用过程中难免就会遇到插件功能不够称心…

Python 内置函数 format() 详解

在 Python 中,format() 是一个内置函数,用于格式化字符串。它提供了灵活的方式来将变量插入到字符串中,并控制它们的显示格式。让我们深入了解一下这个函数的用法、参数、示例以及注意事项。 1. format() 函数概述 format() 函数是 Python …

SPI 设备驱动编写流程:SPI 设备数据收发处理流程

一. 简介 前面一篇文章学习了SPI设备驱动数据收发过程中,涉及的结构体与函数,文章如下: SPI 设备驱动编写流程:SPI 设备数据收发处理流程中涉及的结构体与函数-CSDN博客 本文学习SPI设备驱动中数据收发处理过程。 二. SPI 设备…