前端高频面试题2:JavaScript/TypeScript

1.什么是类数组对象

        一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法。常见的类数组对象有 arguments 和 DOM 方法的返回结果,还有一个函数也可以被看作是类数组对象,因为它含有 length 属性值,代表可接收的参数个数。

常见的类数组转换为数组的方法有这样几种:

(1)通过 call 调用数组的 slice 方法来实现转换

Array.prototype.slice.call(arrayLike);

(2)通过 call 调用数组的 splice 方法来实现转换

Array.prototype.splice.call(arrayLike, 0);

(3)通过 apply 调用数组的 concat 方法来实现转换

Array.prototype.concat.apply([], arrayLike);

(4)通过 Array.from 方法来实现转换

Array.from(arrayLike);

2.Js有哪些基本数据类型

  • 简单类型

    • Number

    • String

    • Boolean

    • Symbol

    • Null

    • Undefined

  • 复杂数据类型

    • Object

    • Array

    • Function

    • Map

    • Set

3.Js判断类型的几种方式,有什么区别

方法支持类型跨框架可靠性原始类型引用类型细分特殊说明
typeof原始类型、函数可靠✔️null 返回 "object"
instanceof引用类型不可靠✔️依赖原型链
Object.prototype.toString所有类型可靠✔️✔️最全面

1.typeof

作用:返回变量的原始类型(字符串形式)。 语法:typeof variable 返回值:

  • "undefined"(未定义)

  • "boolean"(布尔值)

  • "string"(字符串)

  • "number"(数字)

  • "bigint"(BigInt类型)

  • "symbol"(Symbol类型)

  • "function"(函数)

  • "object"(对象、数组、null等)

  • "object"(未识别的ES6+类型,如MapSet

特点:

  • 对原始类型(除 null)有效,但对引用类型无法细分(如数组、对象、null 均返回 "object")。

  • typeof null === "object"(历史遗留问题)。

  • 无法区分对象的具体类型(如 DateRegExp)。

适用场景:快速判断原始类型或函数。

2.instanceof

作用:检测变量是否为某个构造函数的实例(基于原型链)。 语法:variable instanceof Constructor 返回值:truefalse

特点:

  • 适合判断引用类型(如数组、自定义类)。

  • 无法判断原始类型(如 1 instanceof Numberfalse,除非用 new Number(1) 创建)。

  • 跨框架/窗口(iframe)时会失效,因为不同全局环境下的构造函数不共享原型。

  • 若原型链被修改,结果可能不准确。

3.Object.prototype.toString.call()

作用:返回变量的内部 [[Class]] 类型标识。 语法:Object.prototype.toString.call(variable) 返回值:形如 "[object Type]" 的字符串,如 "[object Array]""[object Null]"

特点:

  • 最全面的类型判断方法,支持所有内置类型(包括 nullundefined)。

  • 可通过 Symbol.toStringTag 自定义类型标签(ES6+),但大部分内置对象不受影响。

  • 对原始类型和引用类型均有效。

适用场景:需要精确判断所有类型(包括ES6+新增类型)。

4. Js的事件循环(Event Loop)是什么

        Js是一种单线程语言(HTML5提供了Web Worker可以开启子线程),同步代码直接交由Js引擎执行,异步代码则交由浏览器或Node.js执行。

        关键概念:

  1. 调用栈(Call Stack)​​:用于跟踪当前正在执行的函数(执行上下文)。当函数被调用时,它被压入栈;当函数返回时,它被弹出栈。
  2. ​任务队列(Task Queue)​​:也称为宏任务队列(Macro Task Queue),包括 setTimeout、setInterval、I/O、事件回调等。
  3. ​微任务队列(Micro Task Queue)​​:包括 Promise 的回调(then/catch/finally)、MutationObserver、queueMicrotask 等。微任务在当前宏任务结束后立即执行,且会清空整个微任务队列,直到队列为空。
  4. ​渲染(Render)步骤​​:在事件循环中,可能会在宏任务和微任务之间进行页面渲染(UI 更新),但这不是事件循环规范的一部分,而是浏览器行为

        事件循环执行过程:

  1. 首先依次执行调用栈中的全部同步代码
  2. 处理微任务:
    • 调用栈清空后会执行全部微任务
    • 微任务执行期间加入的微任务也会顺次执行
  3. 渲染更新(浏览器行为与Js事件循环无关)
  4. 执行一个宏任务
  5. 重复循环

        常见的宏任务与微任务

  • 宏任务
    • setTimeout/setInterval
    • I/O操作
    • 浏览器渲染
    • 事件回调(click等事件)
    • 脚本执行(不同的script标签)
  • 微任务
    • Promise相关方法(Promise.then等)
    • MutationObserver(Dom变化监视)

5.下面代码的输出顺序是什么(事件循环)

async function async1() {console.log('async1 start');await async2(); // 后续为微任务console.log('async1 end');
}async function async2() {console.log('async2');
}console.log('script start');setTimeout(function() {console.log('setTimeout');
}, 0) // 宏任务async1();new Promise(function(resolve) {console.log('promise1');resolve();
}).then(function() { // 微任务console.log('promise2');
});console.log('script end');
// 顺序如下
script start // 第一个同步任务
async1 start // async1方法中的第一个同步任务
async2 // await修饰的方法立即执行,输出async2,async1方法进入微任务队列
promise1 // 执行new Promise,输出promise1,并进入微任务队列
script end // 执行同步代码
async1 end // 执行微任务队列中的第一个任务
promise2 // 执行微任务队列的第二个任务
setTimeout // 执行宏任务

6.Js原生如何获取cookie

document.cookie // 结果是一个Json字符串,可使用JSON.parse()转换

7.Promise.all/allSettled/any/race的区别

Promise.all

  • 核心:等待所有 Promise 全部完成(fulfilled),或遇到第一个失败(rejected)。

  • 结果:

    • 全部成功时:返回一个数组,元素为每个 Promise 的成功值(顺序与输入一致)。

    • 遇到失败时:立即拒绝(reject),返回第一个失败的 Promise 的原因。

  • 适用场景:多个异步操作强依赖,需要所有结果都成功(如:并发请求多个接口)。

  • 示例:

Promise.all([promise1, promise2]) .then(values => console.log(values)) // 所有成功:[value1, value2].catch(error => console.log(error)); // 任一失败(返回第一个错误)

Promise.allSettled

  • 核心:等待所有 Promise 全部完成(无论成功或失败)。

  • 结果:永远成功(resolve),返回一个数组,每个元素为对象:

    • { status: "fulfilled", value: <result> }(成功)

    • { status: "rejected", reason: <error> }(失败)

  • 适用场景:需知道每个操作的最终状态(无论成功失败)(如:批量操作后汇总结果)。

  • 示例:

Promise.allSettled([promise1, promise2]).then(results => { results.forEach(result => { if (result.status === "fulfilled") console.log(result.value); else console.error(result.reason); }); });

Promise.any

  • 核心:等待第一个 成功(fulfilled)的 Promise,或所有都失败。

  • 结果:

    • 任一成功时:返回第一个成功的值。

    • 全部失败时:拒绝(reject)并抛出 AggregateError,包含所有错误信息。

  • 适用场景:获取最快成功的操作(如:多服务器请求,取最快响应)。

  • 示例:

Promise.any([promise1, promise2]).then(value => console.log(value)) // 第一个成功的值.catch(errors => console.log(errors)); // 所有失败(AggregateError 包含错误数组)

Promise.race

  • 核心:等待第一个 完成(无论成功或失败)的 Promise。

  • 结果:返回第一个完成的 Promise 的结果(可能是成功值或失败原因)。

  • 适用场景:竞速场景(如:请求超时控制)。

  • 示例:

// 实现超时控制 
const timeout = new Promise((_, reject) =>setTimeout(() => reject("Timeout"), 1000) 
); 
Promise.race([fetchData(), timeout]).then(data => console.log(data)) // 在超时前完成.catch(error => console.log(error)); // 超时或请求失败

对比表格

方法行为描述成功条件失败条件返回值类型
​​Promise.all​​所有成功或任一失败(短路)全部成功第一个失败数组(成功值)
​​Promise.allSettled​​等待所有完成(无论成败)永不失败-对象数组(包含状态和值/原因)
​​Promise.any​​等待第一个成功或所有失败第一个成功全部失败第一个成功的值
​​Promise.race​​等待第一个完成(无论成败)第一个完成的结果是成功第一个完成的结果是失败第一个完成的结果

关键区别

  • all vs allSettledall 会在遇到失败时立即终止,而 allSettled 始终等待所有结果。

  • any vs raceany 只关心第一个成功(忽略失败),race 关心第一个完成(无论成败)。

  • 错误处理: any 在所有失败时返回 AggregateError;其他方法直接返回单条错误原因。

根据实际需求选择合适的方法:需要全部成功用 all,容忍失败用 allSettled,取最快成功用 any,竞速场景用 race

 8.原型对象、构造函数、实例之间的关系

对象指向关系属性/方法
​​构造函数​​prototype → 原型对象Person.prototype
​​原型对象​​constructor → 构造函数Person.prototype.constructor
​​实例​​__proto__ → 原型对象person.__proto__

9.Proxy和Object.defineProperty的区别 

  • Object.defineProperty: 只能对已存在的属性进行劫持,无法拦截新增的属性和删除的属性(需要通过Vue.setVue.delete实现响应式),由于劫持基于属性级别,对于大规模对象或者数组来说会导致性能下降;(Vue2响应式的实现方法)

  • Proxy: 劫持整个对象,并返回一个代理对象,提高了初始化性能,同时可以拦截新增属性和删除属性。(Vue3响应式的实现方法)

10.使用Proxy代理一个对象,是对这个对象所有层级进行了劫持吗

        不会,proxy只代理外层对象,内层对象需要单独proxy代理

 11.简单数组去重的方法

  • 使用Set只运行存储唯一值的特点
const arr = [1, 2, 2, 3, 3, 4, 5, 5, 6]
const uniqueArr = [...new Set(arr)] 
// 或 const uniqueArr = Array.from(new Set(arr))
  • 使用includes方法检查新数值中是否存在该元素

const arr = [1, 2, 2, 3, 3, 4, 5, 5, 6] 
const uniqueArr = [] 
arr.forEach(val => { if(!uniqueArr.includes(val)) { uniqueArr.push(val) } 
}
  • 使用indexOf方法,检查新数组中是否存在该元素

const arr = [1, 2, 2, 3, 3, 4, 5, 5, 6]
const uniqueArr = [] 
arr.forEach(val => { if(uniqueArr.indexOf(val) === -1) { uniqueArr.push(val) } 
}
  • 使用filter方法过滤第一次出现的元素

const arr = [1, 2, 2, 3, 3, 4, 5, 5, 6]
const uniqueArr = arr.filter((val, index, self) => self.indexOf(val) === index
}
  • 使用reduce方法遍历数组元素

const arr = [1, 2, 2, 3, 3, 4, 5, 5, 6]
const uniqueArr = arr.reduce((res, current) => {if(!res.includes(current) {res.push(current) } return res 
}, [])

12.对象数组如何去重

  • id(或其他键相同算为重复)

    • 使用Map

function uniqueById(arr) { return [ ...new Map( arr.map(item => [item.id, item]) ).values() ]; 
} // 使用示例 
const users = [ { id: 1, name: 'John' },{ id: 2, name: 'Jane' }, { id: 1, name: 'Johnny' }, // 相同id { id: 3, name: 'Alice' } 
]; 
console.log(uniqueById(users)); 
// [ 
// { id: 1, name: 'Johnny' }, 
// { id: 2, name: 'Jane' }, 
// { id: 3, name: 'Alice' } 
// ]
  • 使用filter+缓存 
function uniqueById(arr) { const seen = new Set(); return arr.filter(item => { const duplicate = seen.has(item.id); seen.add(item.id);     return !duplicate; }); 
}
  •  使用reduce 
function uniqueById(arr) { return Object.values(arr.reduce((acc, item) => { acc[item.id] = item; return acc; }, {}) ); 
}
  • 完全相同算重复
    • 使用JSON.stringify(简单对象)
      
function deepUnique(arr) { const seen = new Set(); return arr.filter(item => { const serialized = JSON.stringify(item); return seen.has(serialized) ? false : seen.add(serialized); }); 
} 
// 使用示例 
const items = [ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 1, name: 'Apple' }, // 相同对象 { id: 1, name: 'apple' } // 不同对象 
]; 
console.log(deepUnique(items)); 
// [ 
// { id: 1, name: 'Apple' }, 
// { id: 2, name: 'Banana' }, 
// { id: 1, name: 'apple' } 
// ]
  •  Lodash的isEqual方法(复杂对象推荐)                 
// 需要安装lodash:npm install lodash 
import _ from 'lodash'; 
function deepUnique(arr) { return arr.reduce((acc, item) => { const isDuplicate = acc.some(accItem => _.isEqual(accItem, item)); return isDuplicate ? acc : [...acc, item]; }, []); 
}

创建于2025.6.2,后续继续更新

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

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

相关文章

Spring Security入门:创建第一个安全REST端点项目

项目初始化与基础配置 创建基础Spring Boot项目 我们首先创建一个名为ssia-ch2-ex1的空项目(该名称与配套源码中的示例项目保持一致)。项目需要添加以下两个核心依赖: org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-secur…

秋招Day12 - 计算机网络 - UDP

说说TCP和UDP的区别&#xff1f; TCP使用无边界的字节流传输&#xff0c;可能发生拆包和粘包&#xff0c;接收方并不知道数据边界&#xff1b;UDP采用数据报传输&#xff0c;数据报之间相互独立&#xff0c;有边界。 应用场景方面&#xff0c;TCP适合对数据的可靠性要求高于速…

【QQ音乐】sign签名| data参数加密 | AES-GCM加密 | webpack (下)

1.目标 网址&#xff1a;https://y.qq.com/n/ryqq/toplist/26 我们知道了 sign P(n.data)&#xff0c;其中n.data是明文的请求参数 2.webpack生成data加密参数 那么 L(n.data)就是密文的请求参数。返回一个Promise {<pending>}&#xff0c;所以L(n.data) 是一个异步函数…

Codeforces Round 1028 (Div. 2)(A-D)

题面链接&#xff1a;Dashboard - Codeforces Round 1028 (Div. 2) - Codeforces A. Gellyfish and Tricolor Pansy 思路 要知道骑士如果没了那么这个人就失去了攻击手段&#xff0c;贪心的来说我们只需要攻击血量少的即可&#xff0c;那么取min比较一下即可 代码 void so…

【存储基础】存储设备和服务器的关系和区别

文章目录 1. 存储设备和服务器的区别2. 客户端访问数据路径场景1&#xff1a;经过服务器处理场景2&#xff1a;客户端直连 3. 服务器作为"中转站"的作用 刚开始接触存储的时候&#xff0c;以为数据都是存放在服务器上的&#xff0c;服务器和存储设备是一个东西&#…

macOS 安装 Grafana + Prometheus + Node Exporter

macOS 安装指南&#xff1a;Grafana Prometheus Node Exporter 目录简介&#x1f680; 快速开始 安装 Homebrew1. 安装 Homebrew2. 更新 Homebrew 安装 Node Exporter使用 Homebrew 安装验证 Node Exporter 安装 Prometheus使用 Homebrew 安装验证安装 安装 Grafana使用 Home…

不可变集合类型转换异常

记录一个异常&#xff1a;class java.util.ImmutableCollections$ListN cannot be cast to class java.util.ArrayList (java.util.ImmutableCollections$ListN and java.util.ArrayList 文章目录 1、原因2、解决方式一3、解决方式二4、关于不可变集合的补充4.1 JDK8和9的对比4…

【DAY37】早停策略和模型权重的保存

内容来自浙大疏锦行python打卡训练营 浙大疏锦行 知识点&#xff1a; 过拟合的判断&#xff1a;测试集和训练集同步打印指标模型的保存和加载 仅保存权重保存权重和模型保存全部信息checkpoint&#xff0c;还包含训练状态 早停策略 作业&#xff1a; 对信贷数据集训练后保存权…

【Zephyr 系列 3】多线程与调度机制:让你的 MCU 同时干多件事

好的,下面是Zephyr 系列第 3 篇:聚焦 多线程与调度机制的实践应用,继续面向你这样的 Ubuntu + 真板实战开发者,代码清晰、讲解通俗、结构规范,符合 CSDN 高质量博客标准。 🧠关键词:Zephyr、线程调度、k_thread、k_sleep、RTOS、BluePill 📌适合人群:想从裸机开发进…

实现RabbitMQ多节点集群搭建

目录 引言 一、环境准备 二、利用虚拟机搭建 ​ 三、镜像集群配置 四、HAProxy实现负载均衡(主用虚拟机操作) 五、测试RabbitMQ集群搭建情况 引言 在现代分布式系统中&#xff0c;消息队列&#xff08;Message Queue&#xff09;扮演着至关重要的角色,而 RabbitMQ 作为…

异步上传石墨文件进度条前端展示记录(采用Redis中String数据结构实现-苏东坡版本)

昔者&#xff0c;有客临门&#xff0c;亟需自石墨文库中撷取卷帙若干。此等文册&#xff0c;非止一卷&#xff0c;乃累牍连篇&#xff0c;亟需批量转置。然吾辈虑及用户体验&#xff0c;当效东坡"腹有诗书气自华"之雅意&#xff0c;使操作如行云流水&#xff0c;遂定…

Axure 基础入门

目录 认识产品经理 项目团队* 基本概述 认识产品经理 A公司产品经理 B公司产品经理 C公司产品经理 D公司产品经理 产品经理工作范围 产品经理工作流程* 产品经理的职责 产品经理的分类 产品经理能力要求 产品工具 产品体验报告 原型设计介绍 原型设计概述 为…

零基础学习计算机网络编程----socket实现UDP协议

本章将会详细的介绍如何使用 socket 实现 UDP 协议的传送数据。有了前面基础知识的铺垫。对于本章的理解将会变得简单。将会从基础的 Serve 的初始化&#xff0c;进阶到 Client 的初始化&#xff0c;以及 run。最后实现一个简陋的小型的网络聊天室。 目录 1.UdpSever.h 1.1 构造…

普中STM32F103ZET6开发攻略(二)

接上文&#xff1a;普中STM32F103ZET6开发攻略&#xff08;一&#xff09;-CSDN博客 各位看官老爷们&#xff0c;点击关注不迷路哟。你的点赞、收藏&#xff0c;一键三连&#xff0c;是我持续更新的动力哟&#xff01;&#xff01;&#xff01; 目录 接上文&#xff1a;普中…

用提示词写程序(3),VSCODE+Claude3.5+deepseek开发edge扩展插件V2

edge扩展插件;筛选书签,跳转搜索,设置背景 链接: https://pan.baidu.com/s/1nfnwQXCkePRnRh5ltFyfag?pwd86se 提取码: 86se 导入解压的扩展文件夹: 导入扩展成功: edge扩展插件;筛选书签,跳转搜索,设置背景

电脑桌面便签软件哪个好?桌面好用便签备忘录推荐

在日常办公中&#xff0c;一款优秀的桌面便签工具能显著提升工作效率。面对市面上琳琅满目的选择&#xff0c;不少用户都难以抉择。如果你正在寻找一款兼具轻量化与多功能性的便签软件&#xff0c;那么集实用性与便捷性于一身的"好用便签"&#xff0c;或许就是你的理…

性能优化 - 工具篇:基准测试 JMH

文章目录 Pre引言1. JMH 简介2. JMH 执行流程详解3. 关键注解详解3.1 Warmup3.2 Measurement3.3 BenchmarkMode3.4 OutputTimeUnit3.5 Fork3.6 Threads3.7 Group 与 GroupThreads3.8 State3.9 Setup 与 TearDown3.10 Param3.11 CompilerControl 4. 示例代码与分析4.1 关键点解读…

2025年十大AI幻灯片工具深度评测与推荐

我来告诉你一个好消息。 我们已经亲自测试和对比了市面上最优秀的AI幻灯片工具&#xff0c;让你无需再为选择而烦恼。 得益于AI技术的飞速发展&#xff0c;如今你可以快速制作出美观、专业的幻灯片。 这些智能平台的功能远不止于配色美化——它们能帮你头脑风暴、梳理思路、…

雪花算法:分布式ID生成的优雅解决方案

一、雪花算法的核心机制与设计思想 雪花算法&#xff08;Snowflake&#xff09;是由Twitter开源的分布式ID生成算法&#xff0c;它通过巧妙的位运算设计&#xff0c;能够在分布式系统中快速生成全局唯一且趋势递增的ID。 1. 基本结构 雪花算法生成的是一个64位&#xff08;lo…

第1章:走进Golang

第1章&#xff1a;走进Golang 一、Golang简介 Go语言&#xff08;又称Golang&#xff09;是由Google的Robert Griesemer、Rob Pike及Ken Thompson开发的一种开源编程语言。它诞生于2007年&#xff0c;2009年11月正式开源。Go语言的设计初衷是为了在不损失应用程序性能的情况下…