前端高级面试题-JS
1. 原型 / 构造函数 / 实例
- 原型( prototype ): ⼀个简单的对象,⽤于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含⼀个__proto__ (⾮标准)的属性指向它爹(该对象的原型),可 obj.proto 进⾏访问。
- 构造函数: 可以通过 new 来 新建⼀个对象 的函数。
- 实例: 通过构造函数和 new 创建出来的对象,便是实例。 实例通过 proto 指向原型,通过 constructor 指向构造函数。
- 以 Object 为例,我们常⽤的 Object 便是⼀个构造函数,因此我们可以通过它构建实例。
// 实例
const instance = new Object()
- 则此时, 实例为 instance , 构造函数为 Object ,我们知道,构造函数拥有⼀个 prototype 的属性指向原型,因此原型为:
// 原型
const prototype = Object.prototype
这⾥我们可以来看出三者的关系:
- 实例.proto === 原型
- 原型.constructor === 构造函数
- 构造函数.prototype === 原型
// 这条线其实是是基于原型进⾏获取的,可以理解成⼀条基于原型的映射线
// 例如:
// const o = new Object()
// o.constructor === Object --> true
// o.__proto__ = null;
// o.constructor === Object --> false
实例.constructor === 构造函数
2.原型链:
- 原型链是由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型, proto 将对象连接起来组成了原型链。是⼀个⽤来实现继承和共享属性的有限的对象链
- 属性查找机制: 当查找对象的属性时,如果实例对象⾃身不存在该属性,则沿着原型链往上⼀级查找,找到时则输出,不存在时,则继续沿着原型链往上⼀级查找,直⾄最顶级的原型对象 Object.prototype ,如还是没找到,则输出 undefined ;
- 属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进⾏添加该属性,如果需要修改原型的属性时,则可以⽤: b.prototype.x = 2 ;但是这样会造成所有继承于该对象的实例的属性发⽣改变。
3. 执⾏上下⽂(EC)
- 执⾏上下⽂可以简单理解为⼀个对象:
它包含三个部分:
- 变量对象( VO )
- 作⽤域链(词法作⽤域)
- this 指向
它的类型:
- 全局执⾏上下⽂
- 函数执⾏上下⽂
- eval 执⾏上下⽂
代码执⾏过程:
- 创建 全局上下⽂ ( global EC )
- 全局执⾏上下⽂ ( caller ) 逐⾏ ⾃上⽽下 执⾏。遇到函数时,函数执⾏上下⽂( callee ) 被 push 到执⾏栈顶层
- 函数执⾏上下⽂被激活,成为 active EC , 开始执⾏函数中的代码, caller 被挂起
- 函数执⾏完后, callee 被 pop 移除出执⾏栈,控制权交还全局上下⽂ ( caller ),继续执⾏
4.变量对象
- 变量对象,是执⾏上下⽂中的⼀部分,可以抽象为⼀种 数据作⽤域,其实也可以理解为就是⼀个简单的对象,它存储着该执⾏上下⽂中的所有 变量和函数声明(不包含函数表达式)。
- 活动对象 ( AO ): 当变量对象所处的上下⽂为 active EC 时,称为活动对象。
5. 作⽤域
- 执⾏上下⽂中还包含作⽤域链。理解作⽤域之前,先介绍下作⽤域。作⽤域其实可理解为该上下⽂中声明的 变量和声明的作⽤范围。可分为 块级作⽤域 和函数作⽤域
特性:
- 声明提前: ⼀个声明在函数体内都是可⻅的, 函数优先于变量
- ⾮匿名⾃执⾏函数,函数变量为 只读 状态,⽆法修改
let foo = function() { console.log(1) }
(function foo() {
foo = 10 // 由于foo在函数中只为可读,因此赋值⽆效
console.log(foo)
}())
// 结果打印: ƒ foo() { foo = 10 ; console.log(foo) }
6.作⽤域链
- 我们知道,我们可以在执⾏上下⽂中访问到⽗级甚⾄全局的变量,这便是作⽤域链的功劳。作⽤域链可以理解为⼀组对象列表,包含 ⽗级和⾃身的变量对象,因此我们便能通过作⽤域链访问到⽗级⾥声明的变量或者函数。
由两部分组成:
- [[scope]] 属性: 指向⽗级变量对象和作⽤域链,也就是包含了⽗级的 [[scope]] 和 AO
- AO : ⾃身活动对象
- 如此 [[scopr]] 包含 [[scope]] ,便⾃上⽽下形成⼀条 链式作⽤域。
7. 闭包
- 闭包属于⼀种特殊的作⽤域,称为 静态作⽤域。它的定义可以理解为: ⽗函数被销毁 的情况下,返回出的⼦函数的 [[scope]] 中仍然保留着⽗级的单变量对象和作⽤域链,因此可以继续访问到⽗级的变量对象,这样的函数称为闭包。
闭包会产⽣⼀个很经典的问题:
- 多个⼦函数的 [[scope]] 都是同时指向⽗级,是完全共享的。因此当⽗级的变量对象被修改时,所有⼦函数都受到影响。
••解决:** - 变量可以通过 函数参数的形式 传⼊,避免使⽤默认的 [[scope]] 向上查找
- 使⽤ setTimeout 包裹,通过第三个参数传⼊
- 使⽤ 块级作⽤域,让变量成为⾃⼰上下⽂的属性,避免共享
8. script 引⼊⽅式:
html 静态 <script> 引⼊
js 动态插⼊ <script>
<script defer> : 异步加载,元素解析完成后执⾏
<script async> : 异步加载,但执⾏时会阻塞元素渲染
9. 对象的拷⻉
浅拷⻉: 以赋值的形式拷⻉引⽤对象,仍指向同⼀个地址,修改时原对象也会受到影响
- Object.assign
- 展开运算符( … )
深拷⻉: 完全拷⻉⼀个新对象,修改时原对象不再受到任何影响
- JSON.parse(JSON.stringify(obj)) : 性能最快
- 具有循环引⽤的对象时,报错
- 当值为函数、 undefined 、或 symbol 时,⽆法拷⻉
- 递归进⾏逐⼀赋值
10. new运算符的执⾏过程
- 新⽣成⼀个对象
- 链接到原型: obj.proto = Con.prototype
- 绑定 this: apply
- 返回新对象(如果构造函数有⾃⼰ retrun 时,则返回该值)
11. instanceof原理
- 能在实例的 原型对象链 中找到该构造函数的 prototype 属性所指向的 原型对象,就返回 true 。即:
// __proto__: 代表原型对象链
instance.[__proto__...] === instance.constructor.prototype
// return true
12. 代码的复⽤
- 当你发现任何代码开始写第⼆遍时,就要开始考虑如何复⽤。⼀般有以下的⽅式:
- 函数封装
- 继承
- 复制 extend
- 混⼊ mixin
- 借⽤ apply/call
13. 继承
- 在 JS 中,继承通常指的便是 原型链继承,也就是通过指定原型,并可以通过原型链继承原型上的属性或者⽅法。
最优化: 圣杯模式
var inherit = (function(c,p){
var F = function(){};
return function(c,p){
F.prototype = p.prototype;
c.prototype = new F();
c.uber = p.prototype;
c.prototype.constructor = c;
}
})();
- 使⽤ ES6 的语法糖 class / extends
14. 类型转换
- ⼤家都知道 JS 中在使⽤运算符号或者对⽐符时,会⾃带隐式转换,规则如下:
- -、*、/、% :⼀律转换成数值后计算
- +:
-
数字 + 字符串 = 字符串, 运算顺序是从左到右
-
数字 + 对象, 优先调⽤对象的 valueOf -> toString
-
数字 + boolean/null -> 数字
-
数字 + undefined -> NaN
-
- [1].toString() === ‘1’
- {}.toString() === ‘[object object]’
- NaN !== NaN 、+ undefined 为 NaN
15. 类型判断
- 判断 Target 的类型,单单⽤ typeof 并⽆法完全满⾜,这其实并不是bug ,本质原因是 JS 的万物皆对象的理论。因此要真正完美判断时,我们需要区分对待:
- 基本类型( null ): 使⽤ String(null)
- 基本类型( string / number / boolean / undefined ) + function : - 直接使⽤typeof 即可
- 其余引⽤类型( Array / Date / RegExp Error ): 调⽤ toString 后根据 [objectXXX] 进⾏判断
很稳的判断封装:
let class2type = {}
'Array Date RegExp Object Error'.split(' ').forEach(e => class2type[ '[obje
function type(obj) {
if (obj == null) return String(obj)
return typeof obj === 'object' ? class2type[ Object.prototype.toString.
}
16. 模块化
- 模块化开发在现代开发中已是必不可少的⼀部分,它⼤⼤提⾼了项⽬的可维护、可拓展和可协作性。通常,我们 在浏览器中使⽤ ES6 的模块化⽀持,在Node 中使⽤ commonjs 的模块化⽀持。
分类:
-
es6: import / export
-
commonjs: require / module.exports / exports
-
amd: require / defined
require与import的区别
- require ⽀持 动态导⼊, import 不⽀持,正在提案 ( babel 下可⽀持)
- require 是 同步 导⼊, impor t属于 异步 导⼊
- require 是 值拷⻉,导出值变化不会影响导⼊值; import 指向 内存地址,导⼊值会随导出值⽽变化
17. 防抖与节流
- 防抖与节流函数是⼀种最常⽤的 ⾼频触发优化⽅式,能对性能有较⼤的帮助。
- 防抖 (debounce): 将多次⾼频操作优化为只在最后⼀次执⾏,通常使⽤的场景是:⽤户输⼊,只需再输⼊完成后做⼀次输⼊校验即可。
function debounce(fn, wait, immediate) {
let timer = null
return function() {
let args = arguments
let context = this
if (immediate && !timer) {
fn.apply(context, args)
}
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
- 节流(throttle): 每隔⼀段时间后执⾏⼀次,也就是降低频率,将⾼频操作优化成低频操作,通常使⽤场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms 执⾏⼀次即可。
function throttle(fn, wait, immediate) {
let timer = null
let callNow = immediate
return function() {
let context = this,
args = arguments
if (callNow) {
fn.apply(context, args)
callNow = false
}
if (!timer) {
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, wait)
}
}
}
18. 函数执⾏改变this
- 由于 JS 的设计原理: 在函数中,可以引⽤运⾏环境中的变量。因此就需要⼀个机制来让我们可以在函数体内部获取当前的运⾏环境,这便是 this 。
- 因此要明⽩ this 指向,其实就是要搞清楚 函数的运⾏环境,说⼈话就是,谁调⽤了函数。例如
- obj.fn() ,便是 obj 调⽤了函数,既函数中的 this === obj
- fn() ,这⾥可以看成 window.fn() ,因此 this === window
- 但这种机制并不完全能满⾜我们的业务需求,因此提供了三种⽅式可以⼿动修改 this 的指向:
- call: fn.call(target, 1, 2)
- apply: fn.apply(target, [1, 2])
- bind: fn.bind(target)(1,2)
19. ES6/ES7
- 由于 Babel 的强⼤和普及,现在 ES6/ES7 基本上已经是现代化开发的必备了。通过新的语法糖,能让代码整体更为简洁和易读。
声明
- let / const : 块级作⽤域、不存在变量提升、暂时性死区、不允许重复声明
- const : 声明常量,⽆法修改
解构赋值
class / extend: 类声明与继承
Set / Map: 新的数据结构
异步解决⽅案:
- Promise 的使⽤与实现
- generator :
- yield : 暂停代码
- next() : 继续执⾏代码
function* helloWorld() {
yield 'hello';
yield 'world';
return 'ending';
}
const generator = helloWorld();
generator.next() // { value: 'hello', done: false }
generator.next() // { value: 'world', done: false }
generator.next() // { value: 'ending', done: true }
generator.next() // { value: undefined, done: true }
- await / async : 是 generator 的语法糖, babel 中是基于 promise 实现。
async function getUserByAsync(){
let user = await fetchUser();
return user;
}
const user = await getUserByAsync()
console.log(user)
20. AST
- 抽象语法树 ( Abstract Syntax Tree ),是将代码逐字⺟解析成 树状对象 的形式。这是语⾔之间的转换、代码语法检查,代码⻛格检查,代码格式化,代码⾼亮,代码错误提示,代码⾃动补全等等的基础。例如:
function square(n){
return n * n
}
21. babel编译原理
- babylon 将 ES6/ES7 代码解析成 AST
- babel-traverse 对 AST 进⾏遍历转译,得到新的 AST
- 新 AST 通过 babel-generator 转换成 ES5
22. 函数柯⾥化
- 在⼀个函数中,⾸先填充⼏个参数,然后再返回⼀个新的函数的技术,称为函数的柯⾥化。通常可⽤于在不侵⼊函数的前提下,为函数 预置通⽤参数,供多次重复调⽤。
const add = function add(x) {
return function (y) {
return x + y
}
}
const add1 = add(1)
add1(2) === 3
add1(20) === 21
相关文章:
前端高级面试题-JS
1. 原型 / 构造函数 / 实例 原型( prototype ): ⼀个简单的对象,⽤于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含⼀个__proto__ (⾮标准)的属性指向它爹(该对象的原型),可 obj.p…...
AcWing 1564:哈希 ← 只具有正增量的二次探测法
【题目来源】https://www.acwing.com/problem/content/1566/【题目描述】 将一个由若干个不同正整数构成的整数序列插入到一个哈希表中,然后输出输入数字的位置。 哈希函数定义为 H(key)key%TSize,其中 TSize 是哈希表的最大大小。 利用只具有正增量的二…...
什么是媒体代发布?媒体代发布注意事项
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 媒体代发布是指将新闻稿或其他宣传内容委托给专业的媒体代理机构或公司进行发布和推广的活动。这些机构通常拥有丰富的媒体资源、人脉和经验,能够更好地将信息传递给目标受众…...
docker版jxTMS使用指南:使用jxTMS采集数据之二
本文是如何用jxTMS进行数据采集的第二部分,整个系列的文章请查看:docker版jxTMS使用指南:4.4版升级内容 docker版本的使用,请查看:docker版jxTMS使用指南 4.0版jxTMS的说明,请查看:4.0版升级内…...
系列六、Springboot操作RocketMQ
一、同步消息 1.1、发送&接收简单消息 1.1.1、发送简单消息 /*** 测试发送简单消息*/ Test public void sendSimpleMessage() {SendResult result rocketMQTemplate.syncSend("BOOT_TOPIC_SIMPLE", "我是一个简单消息");// 往[BOOT_TOPIC_SIMPLE]主…...
【jupyter异常错误】Kernel started:No module named ipykernel_launcher
尝试过的方案 pip install ipykernel 执行之后提示已经安装,但是执行代码依然报错 解决方案 python -m pip install ipykernel -U --force-reinstall 相当于是强制重新安装 安装成功后没有报错 注:根本原因应该是原来安装的包存在问题,虽然检测出来已经存在…...
使用langchain与你自己的数据对话(五):聊天机器人
之前我已经完成了使用langchain与你自己的数据对话的前四篇博客,还没有阅读这四篇博客的朋友可以先阅读一下: 使用langchain与你自己的数据对话(一):文档加载与切割使用langchain与你自己的数据对话(二):向量存储与嵌入使用langc…...
爬虫与搜索引擎优化:通过Python爬虫提升网站搜索排名
作为一名专业的爬虫程序员,我深知网站的搜索排名对于业务的重要性。在如今竞争激烈的网络世界中,如何让自己的网站在搜索引擎结果中脱颖而出,成为关键。今天,和大家分享一些关于如何通过Python爬虫来提升网站的搜索排名的技巧和实…...
2024软考系统架构设计师论文写作要点
一、写作注意事项 系统架构设计师的论文题目对于考生来说,是相对较难的题目。一方面,考生需要掌握论文题目中的系统架构设计的专业知识;另一方面,论文的撰写需要结合考生自身的项目经历。因此,如何将自己的项目经历和专业知识有机…...
【Maven】依赖范围、依赖传递、依赖排除、依赖原则、依赖继承
【Maven】依赖范围、依赖传递、依赖排除、依赖原则、依赖继承 依赖范围 依赖传递 依赖排除 依赖原则 依赖继承 依赖范围 在Maven中,依赖范围(Dependency Scope)用于控制依赖项在编译、测试和运行时的可见性和可用性。通过指定适当的依赖…...
数组slice、splice字符串substr、split
一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用,包括:slice、splice。对字符串操作的两种方法进行介绍和使用,包括:substr、split (一)、数组 slice:可以操作的数据类型有:数组字符串 splice:数组 操作数组…...
程序漏洞:安全威胁的隐患
在当今数字化时代,计算机程序是现代社会的核心基石。然而,随着技术的进步,程序漏洞也成为了一个不可忽视的问题。程序漏洞可能导致数据泄露、系统崩溃、恶意攻击和经济损失等一系列问题。本文将深入探讨程序漏洞的定义、分类、影响和预防措施…...
0基础学C#笔记09:希尔排序法
文章目录 前言一、希尔排序的思想二、使用步骤总结 前言 希尔排序可以说是插入排序的一种变种。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它…...
DOCKER的容器
1. 什么是Container(容器) 要有Container首先要有Image,也就是说Container是通过image创建的。 Container是在原先的Image之上新加的一层,称作Container layer,这一层是可读可写的(Image是只读的࿰…...
跳跃游戏——力扣55
文章目录 题目描述解法一 贪心题目描述 解法一 贪心 bool canJump(vector<int>& nums){int n=nums....
将本地项目上传至gitee的详细步骤
将本地项目上传至gitee的详细步骤 1.在gitee上创建以自己项目名称命名的空项目2.进入想上传的项目的文件夹,然后右键点击3. 初始化本地环境,把该项目变成可被git管理的仓库4.添加该项目下的所有文件5.使用如下命令将文件添加到仓库中去6.将本地代码库与远…...
iOS开发-导航栏UINavigationBar隐藏底部线及透明度
iOS 导航栏UINavigationBar隐藏底部线及透明度 苹果官方给出的解释: 如果你不调用方法设置一张背景图片的话,那就给你默认一张,然后同时还有一张阴影图片被默认设置上去,这就是导航栏上1px黑线的由来。 解决办法: 方…...
题目:2520.统计能整除数字的位数
题目来源: leetcode题目,网址:2520. 统计能整除数字的位数 - 力扣(LeetCode) 解题思路: 逐位判断即可。 解题代码: class Solution {public int countDigits(int num) {int res0;int ori…...
matplotlib 笔记 注释annotate
在图中的特定位置添加文本注释、箭头和连接线,以便更清晰地解释图形中的数据或信息 主要参数 text文本内容xy箭头指向的目标点的坐标xytext注释文本的坐标arrowprops 一个字典,指定注释箭头的属性,如颜色、箭头样式等 没有arrowprops的时候…...
Windows 无法安装到这个硬盘。选中的磁盘具有MBR分区。在EFI系统上,Windows只能安装到GPT磁盘
Windows无法安装到这个磁盘,选中的磁盘具有MBR分区表的解决方法 - 知乎 (zhihu.com) Windows无法安装到这个磁盘 选中的磁盘具有MBR分区表 - 知乎 (zhihu.com) 选中的磁盘具有MBR分区表,在EFI系统上,windows只能安装到GPT磁盘_选中的磁盘具有mbr分区表…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
