面试题小结(真实面试)

news2025/6/8 1:00:07

面试题

        • 1.call与apply的区别
        • 2.vue3的响应式原理
        • 3.js的垃圾回收机制
        • 4.说说原型链
        • 5.什么是防抖和节流
        • 6.说一下作用域链
        • 7.在一个页面加载数据时(还没加载完成),切换到另一个页面,怎么暂停之前页面的数据加载。
      • 浏览器自动中止机制

这些都是本人之前亲自遇到过的面试问题,本文是某次面试的记录

1.call与apply的区别

在 JavaScript 中,applybindcall 都是用来改变函数执行时的上下文,即改变函数运行时的 this 指向。它们的主要区别在于参数的传递方式和函数的执行时机。

call(this指向(原型对象),…arg)

function fn(...args) {
	console.log(this, args);
}
let obj = { myname: "张三" };
fn.call(obj, 1, 2); // this 指向 obj,参数以列表形式传入

apply(this指向(原型对象),[…arg])

function fn(...args) {
	console.log(this, args);
}
let obj = { myname: "张三" };
fn.apply(obj, [1, 2]); // this 指向 obj,参数以数组形式传入

bind与call类似,不同的是会返回一个改变this指向的新方法

function fn(...args) {
	console.log(this, args);
}
let obj = { myname: "张三" };
const bindFn = fn.bind(obj); // 返回一个新的函数,this 指向 obj
bindFn(1, 2); // 执行新函数,this 指向 obj
2.vue3的响应式原理

Vue3的响应式系统是基于ES6的ProxyReflect实现的,相较于Vue2使用的Object.defineProperty,Vue3在性能和功能上都有显著提升

在Vue2中,响应式系统是通过Object.defineProperty来实现的。它通过拦截对象属性的读取和设置操作来实现响应式。

function reactive(obj, key, value) {
Object.defineProperty(obj, key, {
get() {
console.log(`访问了${key}属性`);
return value;
},
set(val) {
console.log(`${key}由->${value}->设置成->${val}`);
if (value !== val) {
value = val;
}
}
});
}

const data = { name: '林三心', age: 22 };
Object.keys(data).forEach(key => reactive(data, key, data[key]));

console.log(data.name); // 访问了name属性 // 林三心
data.name = 'sunshine_lin'; // 将name由->林三心->设置成->sunshine_lin
console.log(data.name); // 访问了name属性 // sunshine_lin

Object.defineProperty有一个显著的缺陷:它无法监听对象新增或删除的属性

Vue3通过Proxy来实现响应式,解决了Vue2的缺陷。Proxy可以拦截并重新定义基本操作(例如属性查找、赋值、枚举、函数调用等)

function reactive(target) {
const handler = {
  get(target, key, receiver) {
      console.log(`访问了${key}属性`);
      return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
      console.log(`${key}由->${target[key]}->设置成->${value}`);
      return Reflect.set(target, key, value, receiver);
  }
};
	return new Proxy(target, handler);
}

const data = { name: '林三心', age: 22 };
const proxyData = reactive(data);

console.log(proxyData.name); // 访问了name属性 // 林三心
proxyData.name = 'sunshine_lin'; // 将name由->林三心->设置成->sunshine_lin
console.log(proxyData.name); // 访问了name属性 // sunshine_lin

Proxy不仅可以监听对象的新增和删除属性,还可以直接监听数组的变化

Vue3的响应式系统还包括依赖收集触发更新的机制。通过track函数收集依赖,trigger函数触发更新

const targetMap = new WeakMap();

function track(target, key) {
let depsMap = targetMap.get(target);
if (!depsMap) {
	targetMap.set(target, depsMap = new Map());
}
let dep = depsMap.get(key);
if (!dep) {
	depsMap.set(key, dep = new Set());
}
dep.add(activeEffect);
}

function trigger(target, key) {
let depsMap = targetMap.get(target);
if (depsMap) {
	const dep = depsMap.get(key);
  if (dep) {
      dep.forEach(effect => effect());
  }
}
}

function reactive(target) {
const handler = {
  get(target, key, receiver) {
  	track(receiver, key);
  	return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
  	Reflect.set(target, key, value, receiver);
  	trigger(receiver, key);
  }
};
return new Proxy(target, handler);
}
3.js的垃圾回收机制

浏览器的 Javascript 具有自动垃圾回收机制(GCGarbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存。其原理是:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存

对于寻找到那些没有使用的变量的方法,通常情况下有两种实现方式:标记清除引用计数

标记清除(主要)

这是JS最常用的垃圾回收方式。垃圾回收器会定期执行以下流程:

  1. 标记阶段:从根对象(全局对象、当前调用栈等)开始递归遍历,将所有可访问的对象标记为可达

  2. 清除阶段:回收所有未被标记的对象内存

以函数为例,在此函数内定义两个变量,如下

function demo(){
	const a = 'a';  // 标记可达
	const b = 1;    // 标记可达
}

demo();  // 函数调用后,执行上下文消失

函数执行时:a 和 b 被调用栈引用,在GC标记阶段会被标记为可达
函数结束后:执行上下文销毁,a 和 b 失去所有引用
下一次GC运行时:

  1. 标记阶段:从根对象无法访问 a 和 b → 不被标记
  2. 清除阶段:回收内存

闭包情况

function ex() {
 const a = 'a';
 return () => console.log(a); // 闭包引用a
}

const closure = ex(); // 保存返回的函数

函数执行结束后:变量 a被返回的闭包函数引用,只要 closure 变量可达(如全局引用),aGC标记阶段就始终被标记为可达

总结

当上下文消失时,其中不再被任何可达对象引用的变量,会在下一次垃圾回收的标记阶段未被标记,随后在清除阶段被回收

注意点:

  1. 标记是周期性行为:不是声明时立即标记,而是在GC的标记阶段统一处理
  2. 没有"取消标记":变量因失去引用在下一次GC时不被标记,而非主动取消
  3. 闭包的关键是引用链:必须保持闭包函数本身可达,内部变量才会保留
  4. 回收非即时:从变量失去引用到实际回收可能有延迟(取决于GC运行时机)

引用计数法

引用计数的含义是跟踪记录每个值被引用的次数。
例如,定义一个变量a值为1,值1的引用次数为1,后面有b=a引用次数+1,c=a引用次数+1,b=’'引用次数-1,如下:

const a = 1;      // 值`1`的引用计数 = 1(由`a`引用)
const b = a;      // 值`1`的引用计数 = 2(`a`和`b`都引用)
const c = a;      // 值`1`的引用计数 = 3(`a`, `b`, `c`)
b = '';           // `b`不再引用`1`,计数减1 → 变为2

当变量的最终引用次数为0时,则会被GC清除。
只有当a和c都不再引用1时,计数才会归零并被回收。

这种方法遇到循环引用就会出问题

function createObjects() {
 const objA = { name: 'A' }; // 引用计数 = 1
 const objB = { name: 'B' }; // 引用计数 = 1
 
 objA.ref = objB; // objB计数 = 2
 objB.ref = objA; // objA计数 = 2
}
createObjects(); // 函数执行结束

函数结束后:objA和objB的局部引用消失 → 计数各减1
但objA.ref和objB.ref互相引用 → 计数保持1
结果:两个对象永远不会被回收 → 内存泄漏
所以不会怎么使用这种方法。

4.说说原型链

js是基于原型生成对象的方式

所有对象都有它的原型对象

使用class创建一个Object类,Object本质是一个构造函数,可以使用 const obj = new Object(…)创建一个新的实例对象,而所有对象都有原型对象,所以obj._proto_ 会指向原型对象,构造函数的prototype也会指向同一个原型对象,他们基于同一个原型对象产生,如下图:

image-20240507170307699

这就是最常见的原型链,整个的原型链还包括函数对象以及其他方式创建的对象

原型链的实际作用

之所以要挂在原型对象上面,是因为由构造函数实例化出来的每一个实例对象,属性值是不相同的,所以需要每个对象独立有一份

但是对于方法而言,所有对象都是相同的,因此我们不需要每个对象拥有一份,直接挂在原型对象上面共用一份即可

function Computer(name, price) {
this.name = name;
this.price = price;
}
Computer.prototype.showPrice = function () {
console.log(`${this.name}的电脑价格为${this.price}`);
};

const huawei = new Computer("华为", 5000);
const apple = new Computer("苹果", 8000);
5.什么是防抖和节流

防抖目的是防止事件过于频繁的触发,让函数如同电梯一样,在规定时间内有人按电梯就重新计时。常见场景于百度输入框,连续输入时设置一个定时时间,在此时间内继续输入就更新定时时间,直到超出定时时间调用搜索事件。

节流也是为了防止事件过于频繁的触发,不过思想不一样,它是让事件每隔一个固定时间触发一次。常见场景于窗口缩放时间,一般缩放窗口时会触发特别多的resize事件,节流就是定时每隔一段时间触发一次,以此优化性能。

6.说一下作用域链

作用域

作用域相当于地盘,有全局作用域,函数作用域,块级作用域,作用域可以很好的隔绝不同作用域的变量,外层作用域就访问不到内层作用域的内容。

作用域链

所有相邻的作用域会形成一条链路,就是作用域链,内层作用域可以沿着作用域链找到外层作用域的变量进行使用。

7.在一个页面加载数据时(还没加载完成),切换到另一个页面,怎么暂停之前页面的数据加载。

在单页应用(SPA)中切换页面时,暂停或取消之前页面的数据加载是优化性能和避免资源浪费的关键。以下是具体实现方案:

核心解决方案使用 AbortController

现代浏览器提供了 AbortController API,可优雅地取消网络请求。

import { useEffect, useState } from 'react';

function PageA() {
const [data, setData] = useState(null);

useEffect(() => {
// 1. 创建控制器
const abortController = new AbortController();

// 2. 发起带取消信号的请求
fetch('https://api.example.com/data', {
signal: abortController.signal // 关键:绑定取消信号
})
.then(response => response.json())
.then(setData)
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求被取消'); // 正常取消不报错
} else {
console.error('请求出错', err);
}
});

// 3. 组件卸载时取消请求
return () => abortController.abort();
}, []);

return <div>{data ? data : 'Loading...'}</div>;
}

// 页面切换时,React 自动触发清理函数取消请求

Vue的解决方法也是如此

<script setup>
import { ref, onBeforeUnmount } from 'vue';

const data = ref(null);
let controller = null; // 存储 AbortController

const fetchData = async () => {
// 如果已有请求进行中,先取消
if (controller) controller.abort();

controller = new AbortController();

try {
const response = await fetch('https://api.example.com/data', {
signal: controller.signal
});
data.value = await response.json();
} catch (err) {
if (err.name !== 'AbortError') {
console.error('请求错误', err);
}
}
};

// 组件挂载时获取数据
fetchData();

// 组件卸载前取消请求
onBeforeUnmount(() => {
if (controller) controller.abort();
});
</script>

在非单页应用(传统多页应用)中,当用户切换页面时,浏览器会自动中止所有未完成的网络请求。这是浏览器内置行为,无需开发者手动处理。

浏览器自动中止机制

页面卸载时自动终止

  • 当用户点击链接/提交表单/刷新页面时
  • 浏览器触发 beforeunloadunload 事件
  • 所有进行中的网络请求会被自动取消
  • 包括:XHR、Fetch、图片加载、CSS/JS文件下载等

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

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

相关文章

计算机网络领域所有CCF-A/B/C类期刊汇总!

本期小编统计了【计算机网络】领域CCF推荐所有期刊的最新影响因子&#xff0c;分区、年发文量以及投稿经验&#xff0c;供大家参考&#xff01; CCF-A类 1 IEEE Journal on Selected Areas in Communications 【影响因子】13.8 【期刊分区】JCR1区&#xff0c;中科院1区TOP …

有意向往gis开发靠,如何规划学习?

听说GIS开发工资不错、还不像互联网那么卷&#xff1f;心动了&#xff1f;但一看那些“WebGL”、“空间分析”、“OGC规范”的词儿就头大&#xff1f;别急&#xff01; 今天咱就聊聊零基础/转行选手&#xff0c;咋规划学习GIS开发这条路。不整高大上&#xff0c;就讲实在的&am…

五、查询处理和查询优化

五、查询处理和查询优化 主要内容 查询概述查询处理过程关系操作的基本实现算法查询优化技术代数优化基于存取路径的优化基于代价估算的优化 1. 查询概述 查询是数据库管理系统中使用最频繁、最基本的操作&#xff0c;对系统性能有很大影响。 对于同一个SQL查询&#xff0c…

缓解骨质疏松 —— 补钙和补维 D

骨质老化/疏松原理&#xff08;机制&#xff09;骨密度下降与骨小梁结构退化局部受压导致的微损伤或压力集中 诊断要点治疗策略吃什么食物能补钙呢&#xff1f;钙片吃什么食物能补维生素 D 呢&#xff1f; 骨质老化/疏松 骨质老化&#xff08;常指骨密度下降或骨质疏松&#x…

《PMBOK® 指南》第八版草案重大变革:6 大原则重构项目管理体系

项目管理领域的权威指南迎来关键升级&#xff01;PMI 最新发布的《PMBOK 指南》第八版草案引发行业广泛关注&#xff0c;此次修订首次将项目管理原则浓缩为 6 大黄金法则&#xff0c;重构 7 大绩效域&#xff0c;并首度公开过程组与绩效域的映射关系。本文将全面解析新版核心变…

Ctrl+R 运行xxx.exe,发现有如下问题.

CtrlR 运行xxx.exe,发现有如下问题. (1)找不到Qt5Core.all,Qt5Cored.dll,Qt5Gui.dll,Qt5Guid.dll,Qt5Widgets.all,Qt5Widgetsd.dll? (2)之后找不到libwinpthread-1.dll 从这个目录拷贝相应的库到运行xx.exe目录下 方法二:将库路径添加到系统PATH环境变量里: 在Path中添加路…

极智项目 | 基于PyQT+Whisper实现的语音识别软件设计

这是一个基于OpenAI的Whisper模型的语音识别应用程序&#xff0c;使用PyQt5构建了简洁直观的用户界面。该应用支持多语言识别&#xff0c;特别优化了中文识别体验。 项目下载&#xff1a;链接 功能特点 简洁现代的深色主题界面支持多语言识别&#xff08;中文、英语、日语等…

vue+cesium示例:地形开挖(附源码下载)

基于cesium和vue绘制多边形实现地形开挖效果&#xff0c;适合学习Cesium与前端框架结合开发3D可视化项目。 demo源码运行环境以及配置 运行环境&#xff1a;依赖Node安装环境&#xff0c;demo本地Node版本:推荐v18。 运行工具&#xff1a;vscode或者其他工具。 配置方式&#x…

升级:用vue canvas画一个能源监测设备和设备的关系监测图!

用vue canvas画一个能源电表和设备的监测图-CSDN博客 上一篇文章&#xff0c;我是用后端的数据来画出监测图。这次我觉的&#xff0c;用前端来控制数据&#xff0c;更爽。 本期实现功能&#xff1a; 1&#xff0c;得到监测设备和设备的数据&#xff0c;然后进行存库 2&…

深入理解 transforms.Normalize():PyTorch 图像预处理中的关键一步

深入理解 transforms.Normalize()&#xff1a;PyTorch 图像预处理中的关键一步 在使用 PyTorch 进行图像分类、目标检测等深度学习任务时&#xff0c;我们常常会在数据预处理部分看到如下代码&#xff1a; python复制编辑transform transforms.Compose([transforms.ToTensor…

爆炸仿真的学习日志

今天学习了一下【Workbench LS-DYNA中炸药在空气中爆炸的案例-哔哩哔哩】 https://b23.tv/kmXlN29 一开始 如果你的 ANSYS Workbench 工具箱&#xff08;Toolbox&#xff09;里 只有 SPEOS&#xff0c;即使尝试了 右键刷新、重置视图、显示全部 等方法仍然没有其他分析系统&a…

[华为eNSP] OSPF综合实验

目录 配置流程 画出拓扑图、标注重要接口IP 配置客户端IP 配置服务端IP 配置服务器服务 配置路由器基本信息&#xff1a;名称和接口IP 配置路由器ospf协议 测试结果 通过配置OSPF路由协议&#xff0c;实现跨多路由器的网络互通&#xff0c;并验证终端设备的访问能力。 …

完美搭建appium自动化环境

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 桌面版appium提供可视化操作appium主要功能的使用方式&#xff0c;对于初学者非常适用。 如何在windows平台安装appium桌面版呢&#xff0c;大体分两个步骤&…

c++中的输入输出流(标准IO,文件IO,字符串IO)

目录 &#xff08;1&#xff09;I/O概述 I/O分类 不同I/O的继承关系 不同I/O对应的头文件 &#xff08;2&#xff09;iostream 标准I/O流 iostream头文件中的IO流对象 iostream头文件中重载了<<和>> 缓冲区示意图 标准输入流 cin用法 cin&#xff1a;按空…

2025年渗透测试面试题总结-ali 春招内推电话1面(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 ali 春招内推电话1面 一、Web安全核心理解 二、熟悉漏洞及防御方案 三、UDF提权原理与防御 四、XSS Fuzz…

Reactor和Proactor

reactor的重要组件包括&#xff1a;Event事件、Reactor反应堆、Demultiplex事件分发器、Eventhandler事件处理器。

黄晓明新剧《潜渊》定档 失忆三面间谍开启谍战新维度

据悉&#xff0c;黄晓明领衔主演的谍战剧《潜渊》已于近日正式定档6月9日&#xff0c;该剧以“失忆三面间谍”梁朔为核心&#xff0c;打破传统谍战剧的框架和固有角度&#xff0c;以一种特别的视角将悬疑感推向极致。剧中&#xff0c;梁朔因头部受伤失去记忆&#xff0c;陷入身…

物联网嵌入式开发实训室建设方案探讨(高职物联网应用技术专业实训室建设)

一、建设背景与目标 在当今数字化时代&#xff0c;物联网技术正以前所未有的速度改变着人们的生活和工作方式。从智能家居到工业自动化&#xff0c;从智能交通到环境监测&#xff0c;物联网的应用场景无处不在。根据市场研究机构的数据&#xff0c;全球物联网设备连接数量预计…

集成学习三种框架

集成学习通过组合多个弱学习器构建强学习器&#xff0c;常见框架包括Bagging&#xff08;装袋&#xff09;、Boosting&#xff08;提升&#xff09; 和Stacking&#xff08;堆叠&#xff09; 一、Bagging&#xff08;自助装袋法&#xff09; 核心思想 从原始数据中通过有放回…

在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新

​原因​&#xff1a;未重新编译UI文件​​ Qt的UI文件&#xff08;.ui&#xff09;需要通过​​uic工具&#xff08;Qt的UI编译器&#xff09;​​生成对应的ui_*.h头文件。如果你在Qt Designer中修改了对象名&#xff0c;但没有​​重新构建&#xff08;Rebuild&#xff09;…