http请求头有哪些
Content-Type:请求的与实体对应的MIME信息。
Content-Length:请求内容长度
Content-Language:响应体的语言。
Connection:是否需要持久连接
Date:时间
Expect:请求的特定的服务器行为
Host:指定请求的服务器的域名和端口号。
Location:用来重定向接收方到非请求URL的位置来完成请求或标识新的资源
```javascript
1、基于冒泡事件的无痕埋点方案
原理:
1、页面挂载时,监听页面跳转和点击事件
2、页面监听方法addViewListener:基于vue-router的beforeEach钩子,进行监听,收集页面router的值
3、点击事件addClickListener:基于冒泡事件原理监听document.onclick方法,获取元素最近一层级dom上绑定的data-xxx属性,进行数据通信
2、基于decorator实现无痕埋点
原理:在钩子函数中 (activated - created - mounted) 依次寻找这三个钩子
for和forEach的却别
1、for性能比forEach好,for循环没有额外的函数调用栈和上下文
2、for循环中会用到一些中断行为,对于优化数组遍历查找是很好的,但由于forEach属于迭代器,只能按序依次遍历完成,所以不支持上述的中断行为。
3、forEach 的循环起点只能为0不能进行人为干预,而for循环不同,能控制
为什么用CDN给网站加速?
CDN指的是内容分发网络。其基本思路是尽可能的避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定,将用户导离最近的服务节点上。
好处:
网站加速,利于Google的排名
有利于提高网站的转化率
提升网站的稳定性和安全性
trycatch 不能捕获运行时异常_面试官:用一句话描述 JS 异常是否能被 try catch 捕获到 ?
能捕捉到的异常必须是线程执行已经进入 try catch 但 try catch 未执行完的时候抛出来的。
页面渲染是微任务还是宏任务?
宏任务,因为它是通过 Event Loop一帧一帧渲染出来的
echarts内存释放?
1、echarts进行视图渲染的时候,我们一般都会使用定时器来进行试图的更新,所以每次开启新的定时器的时候都要清空定时器
2、再渲染数据视图的时候,我们先要销毁实例然后再进行渲染,先获取echars实例,然后 dispose()销毁
html页面渲染过程?
1、浏览器解析html源码,然后创建一个 DOM树
2、解析css,创建cssdom树(浏览器默认设置 < 用户设置 < 外链样式 < 内联样式 < html中的style。)
3、css+domtree组合成渲染树(rendering tree)
webpack内存溢出解决方案?
1、增加v8内存 increase-memory-limit
2、缩减sourcemap配置
把devtool关闭,不添加sourcemap到内存
webpack?
1、增加v8内存 increase-memory-limit
2、缩减sourcemap配置
把devtool关闭,不添加sourcemap到内存
如何通过webpack做页面性能优化的?
代码分割与懒加载
原理:将代码拆分成多个较小的包,在需要时再加载,减少初始加载的代码量。
做法:使用动态导入(import())实现懒加载,还可配置 splitChunks 进行代码分割。例如,对于单页应用中的路由组件,可采用动态导入按需加载。
压缩与合并代码
原理:去除代码中的多余空格、注释等,减小文件体积,同时合并文件以减少 HTTP 请求。
做法:使用 terser-webpack-plugin 压缩 JavaScript 代码,css-minimizer-webpack-plugin 压缩 CSS 代码。还可通过配置将多个 CSS 或 JS 文件合并。
资源优化
图片:使用 image-webpack-loader 压缩图片,根据不同的图片格式(如 JPEG、PNG)进行针对性优化。
字体:仅加载页面实际使用的字体子集,减少字体文件大小。
缓存
原理:利用浏览器缓存机制,避免重复加载未修改的文件。
做法:通过配置文件名的哈希值(如 [contenthash]),当文件内容改变时哈希值才会变化,使浏览器仅重新加载有变化的文件。
提取公共代码
原理:将多个模块中共享的代码提取到单独的文件中,减少重复代码。
做法:在 splitChunks 配置中,将公共依赖项提取到一个或多个公共文件中。
Tree Shaking
原理:在打包时去除未使用的代码,减小包的体积。
做法:确保代码使用 ES6 模块语法,Webpack 会自动进行 Tree Shaking。同时,配置 optimization.usedExports 为 true 开启此功能。
构建分析与优化
原理:分析构建结果,找出性能瓶颈。
做法:使用 webpack-bundle-analyzer 生成可视化报告,直观了解每个模块的大小和占比,从而针对性地优化。
判断属性类型?
typeof
instanceof
Object.prototype.toString
原型链的理解?
个人理解:追溯本源,向上寻找,找不到本身就找原型
function Person(age) {
this.age = age;
}
Person.prototype.name = "kavin";
var person1 = new Person();
person1.name = 123
console.log(person1.name);
delete person1.name
console.log(person1.name);
类继承?
1、原型继承
优点:父类新增原型方法/原型属性,子类都能访问到
缺点:子不能向父传参
2、构造函数继承
优点:解决了原型继承中,子类实例共享父类引用属性的问题
缺点:继承单一、子不能向父传参
3、类继承
extend suprer
class Person{
constructor(name){
this.name = name;
}
showName( ){
return ` 名字为:${this.name}`;
}
showTest( ){
return ` 测试父类和子类有相同的方法名`;
}
}
class Student extends Person{
constructor(name,skill){
super(name);
this.skill = skill;
}
showSkill( ){
return `张三的技能为${ this.skill }`
}
showTest( ){
return '子类里的showTest'
}
}
let stu1 = new Student('Strive', '逃学');
console.log(stu1.showName( ));
console.log(stu1.showSkill( ));
console.log(stu1.showTest( ));
npm原理
npm 脚本的原理非常简单。每当执行npm run,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。
比较特别的是,npm run新建的这个 Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,执行结束后,再将PATH变量恢复原样。
这意味着,当前目录的node_modules/.bin子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有 Mocha,只要直接写mocha test就可以了。
webpack原理
把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。
js,css等需要放在多个域名的原因
主要的原因,是为了并行下载。
老的浏览器,同一时间只能从相同域名下载两个文件,新一点的,可以到6-8个。
如果一个页面有10个js,css,都在同一个域名,那么就得排队下载。
如果有个下载卡住了,后面都会被连累。
如果域名不重复,就可以并行下载
但域名数目也不是越多越好因为解析域名也要时
插槽和具名插槽的区别
https:
插槽
<template slot-scope="scope"></template>
具名插槽
<template>
<button name="left">
</template>
替换
<h1 slot="left">
冻结数据
Object.freeze(o)
vue Mixins的理解
混合模式(局部和全局)
理解:代码的复用性
vue动画过渡
<transition name = "nameoftransition">
<div></div>
</transition>
vue 把router-link修改成指定标签
<router-link tag="div">sdfsdfadsfsdf</router-link>
vue父组件如何监听到到子组件到达某个生命周期
@hook:mounted="handleChildMounted"
vue过滤器
filters: {
'过滤器名称': function (value1[,value2,...] ) {
// 逻辑代码
}
}
})
<div>{{数据属性名称 | 过滤器名称}}</div>
<div>{{数据属性名称 | 过滤器名称(参数值)}}</div>
<div v-bind:id="数据属性名称 | 过滤器名称"></div>
<div v-bind:id="数据属性名称 | 过滤器名称(参数值)"></div>
vue如何实现按需加载
vue-router 配置 resolve+require加载
import()
pinia和vuex的区别?
(1)它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据
(2)他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦一点
(3)语法上比vuex更容易理解和使用,灵活。
(4)pinia没有modules配置,没一个独立的仓库都是definStore生成出来的
(5)state是一个对象返回一个对象和组件的data是一样的语法
vue seo的方法
1、nuxt
优点:更快的到达页面,减少页面的缓存时间
缺点:缺少document、window、import,限制比较多
2、Phantomjs 针对爬虫做处理
这种解决方案其实是一种旁路机制,原理就是通过Nginx配置, 判断访问的来源UA是否是爬虫访问,如果是则将搜索引擎的爬虫请求转发到一个node server,再通过PhantomJS来解析完整的HTML,返回给爬虫。
有没有了解过react的 fiber
Fiber 是 React 16.x 版本之后的协调算法核心,主要为解决旧协调算法在复杂应用中性能瓶颈问题。下面是其简洁介绍:
核心概念
Fiber 本质是一种数据结构,也是一种工作单元。每个 React 元素对应一个 Fiber 节点,它记录了组件的状态、属性以及需要执行的工作。
工作原理
任务拆分:Fiber 把渲染更新过程拆分成多个小任务。旧协调算法是递归一次性完成渲染,遇到大任务容易导致页面卡顿。而 Fiber 将任务切片,可在浏览器空闲时逐步处理。
暂停与恢复:Fiber 在执行任务时,能在必要时暂停当前任务,去处理高优先级任务,之后再恢复之前暂停的任务。例如在用户交互(如点击按钮)时,优先处理交互带来的更新任务。
优势
提升响应能力:避免长时间占用主线程,使页面在渲染过程中仍能及时响应用户操作,增强用户体验。
优化调度:可以根据任务优先级来安排执行顺序,保证关键任务优先处理。
vue中父子组件的加载时机
Vue 2
挂载:父 beforeCreate -> created -> beforeMount,子完整创建挂载,父 mounted。
更新:父 beforeUpdate,子 beforeUpdate -> updated,父 updated。
销毁:父 beforeDestroy,子 beforeDestroy -> destroyed,父 destroyed。
Vue 3
挂载:父 setup -> onBeforeMount,子 setup -> 完整挂载,父 onMounted。
更新:父 onBeforeUpdate,子 onBeforeUpdate -> onUpdated,父 onUpdated。
销毁:父 onBeforeUnmount,子 onBeforeUnmount -> onUnmounted,父 onUnmounted。
vuex和pinia 有什么异同? 简洁描述
相同点
状态管理:两者都是 Vue 的状态管理库,用于集中存储应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
响应式:都能保证状态的响应式,状态变更时会自动更新依赖该状态的组件。
应用场景:适用于多组件共享状态的场景,如用户登录状态、购物车数据等。
不同点
API 风格:Vuex 采用传统的 mutations、actions、getters 等概念;Pinia 简化了 API,去掉 mutations,使用更直观的 state、actions、getters。
代码复杂度:Vuex 配置和使用相对复杂;Pinia 更简洁,代码量少。
类型支持:Pinia 对 TypeScript 支持更好,Vuex 早期对 TypeScript 支持较弱。
模块结构:Vuex 有严格的模块嵌套结构;Pinia 模块更扁平化,易于扩展。
vite为啥比webpack快?
1、webpack是先打包在启动开发服务器,请求服务器时给予打包的结果
2、vite是直接启动开发服务器,需要哪个模块就对哪个模块进行实时编译
3、现代浏览器中exmodules会主动获取所需文件,vite就是利用这一个特性将开发文件变成浏览器所需的执行文件,而不是像webpack一样交给浏览器是打包后的文件
4、vite不需要打包,因此不需要模块依赖、编译,所以启动速度快,浏览器需要哪个模块在对哪个模块进行按需动态编译
5、在内容改变的时候,vite会直接去请求该模块,而webpack会把该模块相关的依赖和本身在重新执行一边
vuex为什么刷新页面会丢失数据
vuex的数据是保存在缓存中的
父子传值或者子父或者兄弟
vuex 状态管理
props 父子传值
$attrs 除了clss和style、props以外 子组件从过this.$attrs都可以拿到父组件的值
$listeners 事件
inheritAttrs为true 除 props 之外的所有属性
ref
reject与provide
$bus
vuex
emit
#### caddy和nginx的区别
```javascript
Nginx 在部署HTTPS 时比较麻烦(相对其它两者来说),Caddy、 SSLDocker 都是自动配置并且更新HTTPS,这对我这样的懒人来说很有用
为什么v-for需要key
1、提高渲染性能的
2、避免数据混乱的情况
解释:diff
vue中create和mouted的时间间隔会受那些因素的影响
代码量、数据量
vue3和vue2有什么不同,vue3做了哪些优化?
1- Vue 2 使用 Object.defineProperty() 来实现响应式,这存在一些局限性,例如无法检测对象属性的添加和删除,以及数组部分方法的变化。Vue 3 则采用了 ES6 的 Proxy 对象来实现响应式,它可以拦截对象的所有操作,解决了 Vue 2 响应式的局限性,性能也有所提升。
2- Vue 3 采用了基于 ES 模块的设计,支持 Tree - Shaking。这意味着在生产环境中,只有实际使用到的代码才会被打包,从而减小了包的体积。
3- Vue 3 的编译器进行了重大优化,通过静态提升、Patch Flag 和 Block Tree 等技术,减少了不必要的虚拟 DOM 比较,提高了渲染性能。
4-Vue 2 主要使用选项式 API(Options API),代码按照 data、methods、computed 等选项进行组织。当组件变得复杂时,相同逻辑的代码会分散在不同的选项中,导致代码难以维护。Vue 3 引入了组合式 API(Composition API),允许开发者根据逻辑功能来组织代码,将相关的逻辑放在一起,提高了代码的可读性和可维护性。
vue路由的模式有哪些,他们的区别
hash 模式
URL 格式:URL 中带
原理:基于hashchange事件,
优点:兼容性好,无需服务器额外配置。
缺点:URL 不美观,且有
history 模式
URL 格式:正常的 URL 路径,如http://example.com/home。
原理:利用 HTML5 的History API(pushState、replaceState)实现,会向服务器发送请求。
优点:URL 更美观、自然,符合常规习惯。
缺点:需要服务器端进行配置,否则刷新页面会出现 404 错误。
如何解决props层级过深的问题
vuex
computed和watch的区别先详细解释下再用-句话总结?
computed名称不能与data 里对象重复,只能用同步,必须有return;是多个值变化引起一个值变化,是多对一.
watch:名称必须和data里对象- -样,可以用于 异步,没有return;是一对多,监听一-个值,一个值变化引起多个值变化。
hash和history模式的区别
1、是否带有#号
2、hahs不会影响后端,改变hash不会刷新数据,而且不包含在http请求中
3、history应用于浏览器历史记录中,提供了一个对历史记录修改的功能,他虽然也可以改变地址,但浏览器不会立即向服务器发送请求
reactive 和 ref 响应式的区别
- Vue3 中的 reactive 是基于 ES6 的 Proxy 代理实现的响应式系统。它*专门用于处理引用类型数据(如对象或数组),通过拦截对象属性的访问和修改操作实现响应式。具体工作原理是:当我们访问对象属性时,会触发 Proxy 的 get 陷阱(trap),此时进行依赖收集,将当前正在执行的副作用函数(effect)与该属性关联起来;当我们修改对象属性时,会触发 Proxy 的 set 陷阱,系统会通知所有依赖于该属性的副作用函数重新执行,从而实现界面的自动更新。reactive 的局限性在于它只能处理对象类型,不能直接代理原始类型值。
- ref 是 Vue3 提供的另一种响应式解决方案,它可以处理任何类型的数据,包括原始类型(如数字、字符串、布尔值等)和引用类型。当我们使用 ref 包装一个原始类型值时,它会创建一个带有 value 属性的 RefImpl 对象,并通过 Object.defineProperty 的 get/set 拦截器实现这个 value 属性的响应式。当我们使用 **ref 包装一个引用类型值时,它会在内部调用 reactive 来处理这个值,然后将其包装在 RefImpl 对象的 value 属性中**。这就是为什么使用 ref 时需要通过 .value 访问或修改值的原因。在模板中使用 ref 时,Vue 会自动解包,不需要手动添加 .value。
vue3生命周期
- 初始化阶段、更新阶段 和 销毁阶段:”挂载前,挂载后,更新前,更新后,卸载前,卸载后
- onBeforeMount:挂载前调用,dom未生产。DOM 渲染之前执行一些逻辑,比如初始化数据或者设置一些状态,
- onMounted:dom 挂载,执行如网络请求等。`onMounted` 是在组件挂载完成后触发的生命周期函数。它非常适合操作 DOM 或发起网络请求,因为此时 DOM 已经渲染完成。
- onBeforeUpdate:更新前面dom,比如取消定时器等,防止内存泄漏
- onUpdated 更新后
- onBeforeUnmount 卸载前
- onUnmounted 卸载后
keep-alive底层原理
- keep-alive 是一个Vue内置组件,主要用于缓存组件实例,避免重复创建和销毁,提高性能。(不会渲染出 DOM 元素,也不会出现在父组件链中)。它的底层实现主要依靠以下几个关键部分:
- 缓存机制:keep-alive 内部使用一个对象 cache 来存储缓存的组件实例,键是组件的唯一标识key,值就是对应组件的虚拟节点vnode。同时,使用一个数组keys 来维护这些实例缓存顺序
- 而每个缓存顺序通过 lru 算法进行维护,当缓存的组件数量超过max 属性指定的上限时,会优先移除最久未使用的组件实例。
- 另外,keep-alive 还会在组件声明周期中添加activated 和 deactivated 钩子,当组件被激活时触发activated,被缓存时触发deactivated,并且不会再触发mounted 和 unmounted 钩子。
- 最后,核心代码逻辑是在keep-alive 的render 函数里面,会获取默认插槽的第一个组件节点,再根据include 和exclude 属性判断是否需要缓存该组件。若需要缓存,就检查cache 中是否已有该组件实例,有则直接从缓存获取,没有则添加到缓存里。
- keep-alive 内置组件,可以使组件在切换时保持状态,避免重新渲染。
- 可以通过 include 和 exclude 属性来指定需要缓存的组件。
- 可以缓存 、列表渲染、组件缓存等。
- 需要缓存的组件push 到include 数组中,不需要缓存的组件push 到exclude 数组中
react vue 性能方面的差异
React 和 Vue 的性能差异可简单总结为:
- 数据更新触发:
- React:需手动优化(如 `React.memo`),可能因父组件更新导致子组件重复渲染。
- Vue:自动追踪数据变化,精准更新绑定的 DOM,较少冗余渲染。
- 渲染机制: - React:全量虚拟 DOM Diff,适合复杂交互场景,但计算开销可能较高。
- Vue:模板编译时标记静态节点,Diff 更轻量,中小型项目性能更优。
- 优化成本: - React:需主动使用 `memo`、`useMemo` 等优化,大型项目优化门槛较高。 - Vue:默认优化更高效,开发中无需频繁手动处理,上手更简单。
总结:Vue 初始性能更友好,React 适合大型动态场景(需配合优化)。
vue 有 computed,react 是怎么处理的
`useMemo`(最接近):缓存计算结果,仅依赖项变化时重新计算。
const fullName = useMemo(() => `${firstName} ${lastName}`, [firstName, lastName]);
核心差异:Vue 自动追踪依赖,React 需手动指定依赖项。
react子组件没有任何的 props,父组件在渲染的时候,子组件会跟着渲染吗
默认会渲染。
React 父组件更新时,子组件无论是否有 `props` 都会**默认重新渲染**。
需用 `React.memo` 包裹子组件来阻断无意义渲染:
const Child = React.memo(() => <div>子组件</div>);
react 优化需要手动优化、有没有一些方案可以自动处理这个问题
1. 使用 Immer + use-immer**:自动生成不可变数据,减少引用比较
2. reselect 库:自动缓存计算结果(类似 Vue computed)
3. SWC/Babel 插件:编译时自动添加 React.memo
4. 状态管理库:如 Zustand、Redux Toolkit 内置浅层比较
5. 框架特性:Next.js 自动代码分割、懒加载 **注意**:自动方案无法完全替代手动优化,但可大幅减少工作量。
react 什么情况下会触发组件更新?
React 组件更新的触发条件:
1. 自身 state 变化:通过 `setState` 或 `useState` 更新状态
2. 父组件重新渲染:无论 props 是否变化,子组件默认会重新渲染
3. context 变化:消费的 Context 值更新
4. forceUpdate:手动调用强制更新(类组件)
优化提示:使用 `React.memo`(函数组件)或 `shouldComponentUpdate`(类组件)可阻断不必要的更新。
react函数式组件,在一个应用周期里,什么时机会被调用到呢,函数会被调用多少次
在 React 函数式组件的生命周期中,函数的调用时机和次数取决于:
1. 初始渲染:组件首次被挂载时调用 1 次
2. 父组件重新渲染:每次父组件渲染时,子组件函数默认会被重新调用
3. 自身状态更新:每次调用 `setState`/`useState` 触发重渲染时调用
4. context 变化:依赖的 Context 值更新时调用
关键点: - 默认行为:只要父组件渲染,子组件函数就会被调用(无论 props 是否变化)
- 优化后:使用 `React.memo` 可避免重复调用,仅在 props 变化时重新执行
总结:函数调用次数 = 初始渲染(1 次) + 后续重渲染次数。若无优化,父组件每次更新都会触发子组件函数调用。
虚拟dom和dom的区别
虚拟dom不会重绘和排版的操作,真实dom是由虚拟dom转换的,真实的dom重绘和排版效率低,虚拟DOM会进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!),最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
IP地址与域名的关系
一个域名必须对应一个ip地址,但是一个ip地址可以有多个域名。域名通过DNS服务器解析为ip才能被计算机识别,而域名则是由于ip比较难记,而域名对人来说比较容易记忆而对应ip 产生的,直接输入ip同样可以反问网站
jsonp的原理与实现?
首先是利用script标签的src属性来实现跨域。
通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。
由于使用script标签的src属性,因此只支持get方法
cors的原理与实现?
CORS 是一个 W3C 标准,全称是 "跨域资源共享"(Cross-origin resource sharing),它新增的一组 HTTP 首部字段,允许服务器声明哪些来源的请求有权访问当前资源,从而克服了 Ajax 只能同源使用的限制。
基于 Ajax 请求跨域获取数据失败的真正原理是:浏览器禁止与当前网页不同来源的数据被使用。CORS 的解决办法是,在服务端程序中,在发送消息之前手动修改响应头,将带有客户端浏览器的 IP 地址的数据包发送给客户端浏览器,然后客户端浏览器在查验服务端返回的数据时,发现响应头激活中的 IP 和当前网页的 IP 一样,那浏览器就认为这个数据包合法,可以使用该数据
symbol是什么?
指定一个唯一类型 let a = symbol()
如何知道某个对象属性是否存在
Object.prototype.hasOwnProperty() 返回的是true和false
引用数据类型对比时为什么返回的是false?
[] {} 内存地址不一样
JS为什么是单线程?
因为它是脚本语言,只要用于与浏览器进行交互和操作dom,当出现多任务的时候,就会出现同步问题
JS怎么监听窗口变化
window.onresize 或者element-resize-detector
如何删除对象的某个属性
delete name
如何判断数组或者字符串是否包含某个值
indexOf includes
indexof 当匹配的时候 返回的是0
inclides 返回的是true和fasle
let a = "1213212313";
let b = [1,2,3.4];
var myArray = [
{
hello: 'stevie',
foo: 'baz'
}
];
console.log(myArray.map(x=>x.hello).indexOf('stevie'))
b.indexOf(1)
this简单理解
当this是在函数内的时候,this指向的是windows
当this是在对象的时候,且对象里面有函数,指向的是对象,如果里面还嵌套对象,则指向就近的对象
理解this简单理解,谁是老大或者就近老大
递归函数
函数方法嵌套另一个函数方法 a(){a()}
三点运算符的作用
解构数组
随机生成一个长度为10的数组
let n = new Array(10);
console.log(n.fill(1))
http和tcp的区别
http是无状态的短连接,tcp是有状态的长连接,http建立在tcp之上
https和http的区别
一个明文传输,一个是加密的ssl传输
一个端口为443,一个为8080
http传输速度比https快
https比http安全,但比较消耗成本,要买ssl证书
tcp和udp的区别
一个是传输协议,一个是用户数据报协议
一个面向连接,一个面向无连接
一个需要传输,一个不需要传输
一个1对1,一个1对多
axios中取消请求及阻止重复请求的方法
CanelToken
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
// 必须对请求进行cancelToken设置
cancelToken: source.token
}).catch(function (thrown) {
// 如果请求被取消则进入该方法判断
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
// 取消上面的请求
// source.cancel('messge') message为可选项,必须为String
source.cancel('Operation canceled by the user.');
如何捕捉异常
try{}cahcth(err){}
原型链
function Parent(month){
this.month = month;
}
var child = new Parent('Ann');
console.log(child.month);
console.log(child.father);
如何组织小程序冒泡事件?
catchtap 组织小程序冒泡事件
var let const 区别?
1、var可以重复声明变量,第二次赋值会覆盖第一次的值,let无法重复声明,会报错
2var和let声明变量未定义打印都是untif
3、var是函数作用域,let是块级作用域
4、var会提升变量,let不会
5、conts定义常量无法修改,定义对象可以修改
event-loop的理解
事件循环,异步操作的原理
自我理解:js是单线程,当出现多个任务的时候,可能因为某一个任务阻塞,导致代码无法执行,出现一个假死的状态,无法响应给用户,而eveent-loop就是处理这种阻塞行为,变成非阻塞,它会先执行主线程任务,也就是我们所谓的同步,将异步行为放入到队列中,也就是任务对列,它会等主线程执行完毕之后,再去任务队列里面循环读取任务。
内存泄漏的理解
指当一块内存不再被应用程序使用的时候,由于某种原因,这块内存没有返还给操作系统或者内存池的现象
sessionstorage和localstorage的缺点
都无法被服务端获取,都无法设置日期
重绘和重排的区别?
重绘一定会触发重排,重排不一定会触发重绘。
深拷贝和浅拷贝?
浅拷贝只是增加了一个指针指向已存在的内存地址,仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。深拷贝是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。”
深拷贝 json.stringify、手写循环递归、_.cloneDeep()后再JSON(如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式)
浅拷贝 object.assion({},list) 、Array.prototype.slice()、拓展运算符实现的复制,如果只有一级属性就是深拷贝,如果有两级是浅拷贝
假如a有一个对象,这个赋值给了b,修改b的时候,a会发生改变,为什么?
会,因为在直接赋值的时候,它是一个浅拷贝,它的指针还是指向了原来的内存空间,当我们给这个对象用扩展运算符进行展开,并赋给另外一个值,就可以避免。
原始数据类型跟引用数据类型?
原始数据类型分为null,string等等,引用数据类型分为对象,函数,数组
区别:原始数据类型的值是存在于栈内存中,引用数据类型是存在于堆中,因为它的数据大小是大小不固定,所占空间大
对象数组去重
function unique(arr) {
const res = new Map();
return arr.filter((a) => !res.has(a) && res.set(a, 1))
}
原生JS如何监听对象属性变化
var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{ get:function (){
set:function (value){
obj.newKey = 'change value'; console.log( obj.newKey );
如何写一个闭包
简单写法
let a = 3
const b = ()=>{
Console.log(a)
}
困难写法
function foo(){
var local = 1
function bar(){
local++
return local
}
return bar
}
当某个元素频繁创建和销毁,如何进行性能优化
var div = document.createElement("div");
div.id="mydiv";
document.body.appendChild(div);
按钮点击先判断节点是否存在,不存在就创建,如何存在,我就动态修改它的显示与隐藏,如何不存在我就创建一个元素,再绑定一个id,并赋予值
bind、call、apply的作用、区别?
改变某个类、某个方法的运行环境
call、bind将参数以逗号的方式分割传入,apply直接传入数据
call、bind唯一的区别,bind返回的是一个函数,实际过程中,bind不推荐使用,消耗性能
bind的缺点
消耗性能内存
浏览器缓存
强缓存和协商缓存
强缓存 直接从缓存取出 express
协商缓存 由服务器告诉浏览器缓存是否可用 etag
export和module.exports的区别
1、exports只能使用.语法向外暴露内部变量 例 exports.xxx=xxx
2、module.exports既可以通过点语法,也可以直接赋值一个对象 例 module.exports.xxx=xxx
3、exports = module.exports = {};
4、如果给exports 和 module.exports直接复制,则会指向新的内存,切断两者之间的联系
什么是nodejs?我们在哪里使用它?
Nodejs是服务器端的一门技术。它是基于Google V8 JavaScript引擎而开发的。用来开发可扩展的服务端程序。
为什么要使用node js?
nodejs会让我们的编程工作变得简单,它主要包含如下几点几个好处:
执行快速、永远不会阻滞、JavaScript是通用的编程语言、异步处理机制
什么叫做回调地狱?
回调地狱是由嵌套的回调函数导致的。这样的机制会导致有些函数无法到达,并且很难维护。
什么是回调函数?
回调函数是指用一个函数作为参数传入另一个函数,这个函数会被在某个时机调用。
回调函数中callback和return的区别?
callback是作为参数传入另一个函数,另一个函数相当于获取了callback这个的值,而return是直接指向了他的调用者,获取的结果同样给了调用者
什么是错误优先的回调函数?
错误优先的回调函数用于传递错误和数据。第一个参数始终应该是一个错误对象, 用于检查程序是否发生了错误。其余的参数用于传递数据
如何避免回调地狱
使用Promises
运算错误与程序员错误的区别
运算错误并不是bug,这是和系统相关的问题,例如请求超时或者硬件故障。而程序员错误就是所谓的bug。
什么是Stub?
Stub是用于模拟一个组件或模块的函数或程序。在测试用例中, 简单的说,你可以用Stub去模拟一个方法,从而避免调用真实的方法, 使用Stub你还可以返回虚构的结果。你可以配合断言使用Stub。
流是什么?
Stream 流是从源读取或写入数据并将其传输到连续流目标的管道
如何解释NodeJS 适用于IO密集型不适用CPU密集型?
1.Node还没有简单易用的多核计算接口。Cluster并不是那么好用。
2.Node的单核效率虽然比传统脚本语言高,但是和C、C++、Java比并没有优势。
req,res分别代表什么?
req:全称request请求对象
res:全称 response响应对象
_dirname表示什么
当前文件所在目录
_ _filename表示什么
当前文件路径
什么是orm,为什么要使用orm?
关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
require和import的区别
import和require都是被模块化所使用
2、require是运行时调用,可以运用在代码的任何地方,require可以理解为一个全局方法,import是编译时调用,只能放在文件开头xxxxxxxxxx import和require都是被模块化所使用2、require是运行时调用,可以运用在代码的任何地方,require可以理解为一个全局方法,import是编译时调用,只能放在文件开头vuex
websocket的状态
连接成功 接收数据 失败连接 关闭连接
webscok连接之后的状态是多少?
201
node事件循环机制(不懂)
在这里插入代码片
是否了解Generator
Generator(生成器)是 JavaScript 中一种特殊的函数,以下是简洁描述:
定义与特征
定义时使用 function* 语法,函数内部可使用 yield 关键字。
调用生成器函数不会立即执行函数体,而是返回一个迭代器对象。
执行过程
通过迭代器对象的 next() 方法来执行函数体,每次遇到 yield 就暂停执行,并返回 { value: yield 后的值, done: false }。
再次调用 next() 时,从暂停处继续执行,直到函数结束或遇到 return,此时 done 为 true。
用途
实现自定义迭代器,按需生成值。
用于异步编程,配合 async/await 简化异步操作。
ES6 有哪些新特性
块级作用域:通过let和const声明变量,解决变量提升和全局污染问题。
箭头函数:语法简洁,this指向更明确,适合简单函数和回调。
模板字符串:用反引号定义,支持变量插值和多行字符串。
解构赋值:方便地从数组和对象中提取值并赋给变量。
类和继承:提供更清晰的面向对象编程语法,通过class和extends实现类的定义和继承。
模块系统:使用import和export进行模块的导入和导出,实现代码的模块化。
Promise:用于处理异步操作,避免回调地狱,使异步代码更易读和维护。
Symbol:一种新的原始数据类型,创建唯一的标识符。
Set和Map:Set存储唯一值的集合,Map是键值对的集合,键可以是任意类型。
for...of循环:用于遍历可迭代对象,如数组、字符串、Set和Map等。
js 的显式类型转化和隐私类型转化
显式类型转换
概念:通过特定的方法或构造函数,明确地将一种数据类型转换为另一种数据类型。
示例
转换为字符串:使用toString()方法或String()函数,如(123).toString()或String(123),将数字123转换为字符串"123"。
转换为数字:利用Number()函数、parseInt()函数或parseFloat()函数。例如,Number("123")将字符串"123"转换为数字123;parseInt("12.34")会提取字符串中的整数部分,返回12。
转换为布尔值:使用Boolean()函数,如Boolean(0)返回false,Boolean(1)返回true。
隐式类型转换
概念:JavaScript 自动进行的数据类型转换,通常发生在某些操作或表达式中,根据上下文需要将数据类型转换为合适的类型。
示例
算术运算中的转换:当不同类型的数据进行算术运算时,会自动转换为数字类型。例如,"3" + 5会先将字符串"3"转换为数字3,然后进行加法运算,结果为8。
比较运算中的转换:在比较运算中,会根据不同的情况进行类型转换。例如,"1" == 1会将字符串"1"转换为数字1,然后进行比较,结果为true。
逻辑运算中的转换:逻辑运算中,会将操作数转换为布尔值。例如,!!"hello"会将字符串"hello"转换为布尔值true,因为非空字符串在布尔语境中被视为true。
是否了解暂时性死区
暂时性死区(Temporal Dead Zone,TDZ)是 ES6 引入 let 和 const 后出现的概念。
定义
在代码块内,使用 let 或 const 声明变量前,该变量处于暂时性死区,此时访问变量会报错,哪怕变量已在作用域内。
原理
let 和 const 不存在变量提升,从块级作用域开始到变量声明语句之间,变量不可用。
示例
javascript
console.log(a); // 报错,a 处于暂时性死区
let a = 1;
暂时性死区能让开发者更清晰变量声明和使用顺序,避免因变量提升引发的问题。
Promise的三种状态、优点、缺点
1、pending/reslove/reject 。pending就是未决,resolve可以理解为成功,reject可以理解为拒绝。
2、Promise用来封装一个异步操作并可以获取其结果
3、优点:1、解决回调地狱(Callback Hell)问题,让回调函数变成了规范的链式写法,程序流程可以看的很清楚
缺点:1、编写的难度比传统写法高,而且阅读代码也不是一眼可以看懂。2、无法取消Promise,一旦新建它就会立即执行,无法中途取消
Promise和定时器谁先执行
promise,因为promise是微任务
async和await的理解
async await返回的是一个promise 对象 它会优先执行同步的方法在执行异步的方法 如果里面调用了另一个函数方法 那个方法里面也有异步操作 也视为同步执行 如果await 上面有一个异步请求 则先执行异步请求在执行await 同理 await 下面是一个异步请求 先执行await 在执行异步 如果是await btn() 该方法变成异步 反正一句理解 异步遵循谁先谁执行 await最终的作用我大概理解成 将鸭子变成鸡 这里的鸡指的是异步 如果类似let a =await console 直接将await赋值给了一个对象 它就会变成与普通对象方法一样 变成同级从上往下执行
async和await为什么不支持在回调函数中
async和await是原生函数里面的语法,目前回调函数暂不支持async。
async/await 是如何把promise 变成同步的写法的,原理是什么?
1-async/await 本身并没有将 Promise 真正变成同步代码,只是在写法上让异步代码看起来像同步代码,从而提升了代码的可读性和可维护性。
2-async 关键字用于定义一个异步函数,异步函数总是返回一个 Promise 对象。如果函数内部返回的是一个值,async 函数会自动将这个值包装成一个已解决(resolved)状态的 Promise 对象;如果返回的本身就是一个 Promise,则直接返回该 Promise
3-await 关键字只能在 async 函数内部使用。当执行到 await 表达式时,它会暂停 async 函数的执行,等待 Promise 解决(resolved)或被拒绝(rejected),并返回 Promise 的解决值。一旦 Promise 有了结果,async 函数会恢复执行,并继续处理后续代码。
4-从本质上来说,async/await 是基于 Promise 和生成器(Generator)实现的语法糖。JavaScript 引擎会将 async 函数转换为一个生成器函数,并使用状态机来管理异步操作的执行流程。await 关键字实际上是在生成器函数内部暂停和恢复执行的一个标记。
通过这种方式,async/await 让异步代码的编写和阅读更加符合同步代码的思维习惯,但实际上异步操作仍然是通过 Promise 来处理的,并没有改变异步操作的本质。
async和promise的区别
使用async和await明显节约了不少代码,不需要.then,不需要写匿名函数处理promise的resolve的值,不需要定义多余的data变量,还避免了嵌套代码。
async/await让try/catch 可以同时处理同步和异步错误。try/catch不能处理JSON.parse的错误,因为他在promise中。此时需要.catch,这样的错误处理代码非常冗余。并且,在我们的实际生产代码会更加复杂
async里面不写await,但是用return返回值,如何获取return的值
async function timeout() { return 'hello world' }
timeout().then(result => { console.log(result); })
promise的原理是什么,他怎么实现异步的 简洁描述
原理
Promise 是一个对象,代表一个异步操作的最终完成或失败,并返回其结果。它有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败),状态一旦改变就不能再变。其内部维护一个状态和结果值,通过构造函数传入一个执行器函数,该函数有 resolve 和 reject 两个参数,用于改变 Promise 的状态。
异步实现
Promise 本身不创造异步,而是管理异步操作。在执行器函数里可放置异步代码,如 setTimeout、网络请求等。当异步操作完成,调用 resolve 或 reject 改变 Promise 状态,触发 then 或 catch 方法中的回调函数执行后续逻辑,以此实现对异步操作的链式处理。
移动端开发一般怎么判断是什么平台,安卓、IOS、微信?
通过检测 User-Agent 中的关键字(如 `Android`、`iPhone`、`iPad`)区分系统:
function getPlatform() {
const ua = navigator.userAgent.toLowerCase();
if (ua.includes('android')) return 'android';
if (ua.includes('iphone') || ua.includes('ipad')) return 'ios';
return 'other';
}
console.log(getPlatform());
事件循环,这些是谁在处理
事件循环由宿主环境(浏览器或 Node.js 等)负责处理,具体如下:
- 浏览器:通过内核(如 Chrome 的 V8 引擎 + 渲染引擎)管理宏任务和微任务队列。
- Node.js:基于 Libuv 库实现,按阶段(如 timers、poll 等)处理异步任务。
总结:JavaScript 引擎(如 V8)负责执行代码,事件循环由宿主环境的底层机制实现。