2月21日 上海昊仓系统(光谷总部时代) 100-499人 3-5年 智慧水务 10-15k
** position属性有哪些?**
- static:元素框正常生成,默认定位。
- relative:生成相对定位的元素,相对于其正常位置进行定位,它原本所占的空间仍保留。
- absolute:元素框从文档流中完全删除,并相对于其其包含块定位。生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。元素的位置通过“left","top""right""bottom"属性进行规定。
- fixed:生成绝对定位的元素,相对于浏览器窗口进行定位
flex布局了解过吗?
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
flex-direction 属性决定主轴的方向(也就是排列方向)。有4个属性值可以设置。
- row(默认值):主轴为水平方向,起点在左端。
- row-reverse:主轴为水平方向,起点在右端。
- column:主轴为垂直方向,起点在上沿。
- column-reverse:主轴为垂直方向,起点在下沿。
align-items 属性定义项目在交叉轴上如何对齐。 justify-content 属性定义了项目在主轴上的对齐方式。
flex: 1表示的含义是等分剩余空间。
css选择器有哪些以及优先级?
-
选择器
- id选择器(#myid)
- 类选择器(.myclass)
- 属性选择器(a[rel="external"])
- 伪类选择器(a:hover, li:nth-child)
- 标签选择器(div, h1, p)
- 伪元素选择器(p::first-line)
- 相邻选择器(h1 + p)
- 子选择器(ul > li)
- 后代选择器(li a)
- 通配符选择器(*)
-
优先级
!important- 内联样式(1000)
- ID选择器(0100)
- 类选择器 / 属性选择器 / 伪类选择器(0010)
- 标签选择器 / 伪元素选择器(0001)
- 关系选择器 / 通配符选择器(0000)
带 !important 标记的样式属性优先级最高;样式表的来源相同时:!important > 行内样式> ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
css盒模型?
-
标准盒模型,width 指 content 部分的宽度,总宽度 = width + border(左右) + padding(左右)+ margin(左右);高度同理。(box-sizing: content-box) -
怪异盒模型(IE盒模型),width 指 content + border(左右) + padding(左右)三部分的宽度,因此,总宽度 = width + margin(左右);高度同理。(box-sizing: border-box)
js闭包
闭包就是能够读取其他函数内部变量的函数。 主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。
优点:延长局部变量的生命周期,可用来创建私有变量。 缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
作用域和作用域链?
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。作用域决定了代码区块中变量和其他资源的可见性。一般可分为:全局作用域、局部作用域(函数作用域)、块级作用域。
全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问。局部作用域:也叫做函数作用域,如果一个变量是在函数内部声明的,它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问。块级作用域:凡是代码块就可以划分变量的作用域,这种作用域的规则就叫做块级作用域。(let)
作用域链:当在 JS 中使用一个变量时,JS 引擎会尝试在当前作用域下寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推,直至找到该变量或是查找至全局作用域,如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错。
js继承
1.原型链继承(new实现,子类的原型指向父类的实例)
// 原型链的继承
SuperType.prototype.getSuperValue = function () {
return this.property;
}
function SuperType() {
this.property = true
}
Type.prototype = new SuperType(); //type的原型指向super的实例对象实现继承
function Type() {
this.typeproperty = false
}
console.log(Type.prototype); // SuperType
var instance = new Type()
console.log(instance.getSuperValue()); // true
优点:实现简单,父类共用。缺点:父类共用导致的父类引用类型属性的修改问题。
2.经典继承(使用call改变this指向)
// 经典继承
SuperType.prototype.name = '寒月十九'
function SuperType(age) {
this.color = ['red', 'green', 'blue'],
this.age = age
}
function Type(age) {
SuperType.call(this,age) //将super的指向绑定到type
}
var instance = new Type(18)
console.log(instance);
console.log(instance.color);
优点:解决原型链继承不能给父类传参和父类共用的问题。 缺点:子类继承不到父类原型上的方法。
3.组合式继承(原型链继承+经典继承)
// 组合继承 (伪经典继承)
SuperType.prototype.sayName =function() {
console.log(this.name);
}
function SuperType(name) {
this.name = name,
this.color = ['red', 'green', 'blue']
}
function Type(age,name) {
this.age = age
SuperType.call(this,name)
}
Type.prototype = new SuperType()
Type.prototype.constructor = Type
//Type.prototype被替换了,所以要补充一个constructor属性,指向自身,这样new Type得到的实例对象就有constructor属性
Type.prototype.sayAge = function() {
console.log(this.age)
}
var instance = new Type(20,'寒月十九');
instance.sayAge();
优点:解决原型链继承和经典继承的缺点 缺点:调用两次构造函数
js垃圾回收机制
现在大多数浏览器都是基于标记清除算法(例如V8)
整个标记清除算法大致过程就像下面这样
- 垃圾收集器在运行时会给内存中的所有变量都加上一个标记,假设内存中所有对象都是垃圾,全标记为0
- 然后从各个根对象开始遍历,把不是垃圾的节点改成1
- 清理所有标记为0的垃圾,销毁并回收它们所占用的内存空间
- 最后,把所有内存中对象标记修改为0,等待下一轮垃圾回收
优点:实现简单,一个字段标记位即可。 缺点:内存碎片化,分配速度慢。
事件队列
由于js是单线程运行的,会先执行同步任务,异步任务会被挂起放入任务队列中。异步任务被压入异步队列时又分为宏任务和微任务两个新的队列,宏任务包括script脚本执行,setTimeout,setInterval,微任务包括promise回调等。当同步任务执行完毕后,会优先执行所有已存在任务队列中的微任务,再去宏任务队列中取第一个执行,执行完成后检查微任务队列是否有任务,有就执行,完成后再去宏任务中取第二个执行,以此循环。
实例:
//第一个宏任务
setTimeout(() => {
console.log(1); //宏任务中的同步任务
Promise.resolve().then(() => { console.log(7) }) //宏任务中的微任务
}, 0); //异步任务 - 宏任务
console.log(2); //同步任务
Promise.resolve().then(() => { console.log(3) }) //异步任务 - 微任务
//第二个宏任务
setTimeout(() => {
console.log(8); //宏任务中的同步任务
setTimeout(() => { console.log(5) }, 0) //宏任务中的宏任务 第四个宏任务
}, 0);
//第三个宏任务
setTimeout(() => {
Promise.resolve().then(() => { console.log(4) }) //宏任务中的微任务
}, 0);
console.log(6); //同步任务
答案:2 6 3 1 7 8 4 5
vue父子组件通信方式
-
父子组件通信:
父向子传递数据是通过
props,子向父是通过$emit触发事件;通过父链/子链也可以通信($parent/$children);ref也可以访问组件实例;provide/inject;$attrs/$listeners。 -
兄弟组件通信:
全局事件总线
EventBus、Vuex。 -
跨层级组件通信:
全局事件总线
EventBus、Vuex、provide/inject。
vueX状态管理
Vuex 将全局状态放入state对象中,它本身是一颗状态树,组件中使用store实例的state访问这些状态;然后用配套的mutation方法修改这些状态,并且只能用mutation修改状态,在组件中调用commit方法提交mutation;如果应用中有异步操作或复杂逻辑组合,需要编写action,执行结束如果有状态修改仍需提交mutation,组件中通过dispatch派发action。最后是模块化,通过modules选项组织拆分出去的各个子模块,在访问状态(state)时需注意添加子模块的名称,如果子模块有设置namespace,那么提交mutation和派发action时还需要额外的命名空间前缀。
6.口述算法思路
1.计算字符串中字母出现次数并排序输出
var frequencySort = function(s) {
//用map计算次数,key是字母,value是次数
const map = new Map();
const length = s.length;
for (let i = 0; i < length; i++) {
const c = s[i];
const frequency = (map.get(c) || 0) + 1;
map.set(c, frequency);
}
//次数降序排序
const list = [...map.keys()];
list.sort((a, b) => map.get(b) - map.get(a));
//结果遍历拼接
const sb = [];
const size = list.length;
for (let i = 0; i < size; i++) {
const c = list[i];
const frequency = map.get(c);
for (let j = 0; j < frequency; j++) {
sb.push(c);
}
}
return sb.join('');
};
2.5位数以下前置补0转字符串
/**
* 自定义函数名:PrefixZero
* @param num: 被操作数
* @param n: 固定的总位数
*/
function PrefixZero(num, n) {
return (Array(n).join(0) + num).slice(-n);
}
//先字符串拼接后再从后往前截取
3月2号 思迪信息(泛悦城) 500-999人 3-5年 金融 14-18k
一面 视频面试 腾讯会议 半小时 ## 1.自我介绍
2.项目介绍(重点),项目职责,业务介绍,技术实现,项目重点难点,项目可优化的点。
3. 网页项目与中后台管理系统优化方向
优化指标:首屏加载时间,打包后的体积。
网站优化: 1.使用performance查看表现,使用lighthouse进行分析
2.开启浏览器缓存(nginx配置etag和expires)
3.资源打包压缩(使用webpack插件压缩HTML,css,js)
4.图片体积优化 小图转base64,使用字体图标,使用雪碧图,使用图片懒加载
中后台管理系统优化:
1.使用webpack-bundle-analyzer插件进行分析
2.生产环境去掉sourcemap,console
3.图片和css进行压缩或者使用CDN静态资源
4.第三方包打包时添加到externals,使用时按需引入(require)
** 4. 场景题,页面图表数据较多,等待时间长并且卡顿,怎么优化。**
** 5.vue组件通信方式 vue2与vue3的区别 怎样把vue2项目迁移到vue3 vite常见配置项**
vue2是选项式api将data和methods包括后面的watch,computed等分开管理,vue3是组合式api将相关逻辑放到了一起(类似于原生js开发)
Vue3中的生命周期相对于Vue2做了一些调整,命名上发生了一些变化并且移除了beforeCreate和created,因为setup是围绕beforeCreate和created生命周期钩子运行的,所以不再需要它们。生命周期采用hook函数引入。
vue2通过Object.definePropert()对数据进⾏劫持结合发布订阅模式的⽅式来实现双向绑定。vue3中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。这样更高效也能监听数组变化。
3月6日 二面 视频面试 腾讯会议 40分钟
1.自我介绍,简历项目介绍
2.语义化的理解
-
语义化,指对文本内容的结构化(内容语义化),选择合乎语义的标签(代码语义化)。
-
语义化标签:
header、nav、main、article、section、aside、footer等。 -
优点:
- 代码结构清晰,易于阅读,有利于维护
- 方便其他设备解析(如:屏幕阅读器)
- 有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重
3.H5兼容方案
媒体查询,百分比,rem,vh,vm
4.js数组常用方法 转换方法:toLocaleString()、toString()、valueOf()方法。其中toString()方法会返回由数组中每个值的字符串拼接而成的一个以逗号分隔的字符串,而调用valueOf()返回的还是数组。
类似栈和队列的方法:push,pop,shift,unshift
重排序: reverse,sort
操作方法: 拼接concat,截取slice,插入删除替换splice
查找方法: find,indexof,lastIndexOf,includes
迭代方法:every,filter,forEach,map,some,flatMap
5.es6常用特性,map,set的使用场景
- 块作用域let
- 类class
- 箭头函数,定义和写法简单,不绑定this与arguments,不能作为构造函数
- 模板字符串
- 加强的对象字面
- 对象解构
- Promise,异步编程的解决方案
- 模块
- Symbol,作为对象属性保证独一无二
- 代理(proxy)Set
- 函数默认参数
- 展开
Set它类似于数组,但是成员的值都是唯一的,没有重复的值。可用于数组去重,实现交集,并集,差集。
Map它类似于对象,但是健名可以不仅仅是字符串,可以是数字,对象等。
6.尾递归了解吗
6.脚手架与打包工具 webpack分包 vite的使用
7.vue-router的钩子函数有哪些
vue-router 的 钩子函数 ,其实说的就是 导航守卫 。路由守卫包括:全局守卫、路由守卫、组件守卫
beforeEach
全局前置守卫,在路由跳转前触发,它在 每次导航 时都会触发。
通过 router.beforeEach 注册一个全局前置守卫。
router.beforeEach((to, from, next) => {
console.log('🚀🚀~ to:', to);
console.log('🚀🚀~ from:', from);
next();
})
beforeResolve
全局解析守卫,在路由跳转前,所有 组件内守卫 和 异步路由组件 被解析之后触发,它同样在 每次导航 时都会触发。
通过 router.beforeResolve 注册一个全局解析守卫。
router.beforeResolve((to, from, next) => {
next();
})
复制代码
回调参数,返回值和 beforeEach 一样。也可以定义多个全局解析守卫。
afterEach
全局后置钩子,它发生在路由跳转完成后,beforeEach 和 beforeResolve 之后,beforeRouteEnter(组件内守卫)之前。它同样在 每次导航 时都会触发。
通过 router.afterEach 注册一个全局后置钩子。
router.afterEach((to, from) => {
console.log('🚀🚀~ afterEach:');
})
复制代码
这个钩子的两个参数和 beforeEach 中的 to 和 from 一样。然而和其它全局钩子不同的是,这些钩子不会接受 next 函数,也不会改变导航本身。
beforeEnter(路由守卫)
需要在路由配置上定义 beforeEnter 守卫,此守卫只在进入路由时触发,在 beforeEach 之后紧随执行,不会在 params、query 或 hash 改变时触发。
//index.js
{
path: '/a',
component: () => import('../components/A.vue'),
beforeEnter: (to, from) => {
console.log('🚀🚀~ beforeEnter ');
},
},
复制代码
beforeEnter 路由守卫的参数是 to、from、next ,同 beforeEach 一样。
组件守卫顾名思义,是定义在路由组件内部的守卫。
beforeRouteEnter
//A.vue
beforeRouteEnter(to, from,next) {
console.log('🚀🚀~ beforeRouteEnter');
},
复制代码
路由进入组件之前调用,该钩子在全局守卫 beforeEach 和路由守卫 beforeEnter 之后,全局 beforeResolve 和全局 afterEach 之前调用。
参数包括 to,from,next。
该守卫内访问不到组件的实例,也就是 this 为 undefined,也就是他在 beforeCreate 生命周期前触发。
beforeRouteUpdate
//A.vue
beforeRouteUpdate(to, from) {
console.log('🚀🚀~ beforeRouteUpdate');
},
复制代码
对于 beforeRouteUpdate 来说,this 已经可用了,所以给 next 传递回调就没有必要了。
beforeRouteLeave
//A.vue
beforeRouteLeave(to, from) {
console.log('🚀🚀~ beforeRouteLeave');
},
复制代码
对于 beforeRouteLeave 来说,this 已经可用了,所以给 next 传递回调就没有必要了。
8.js事件队列的理解
由于js是单线程运行的,会先执行同步任务,异步任务会被挂起放入任务队列中。异步任务被压入异步队列时又分为宏任务和微任务两个新的队列,宏任务包括script脚本执行,setTimeout,setInterval,微任务包括promise回调等。当同步任务执行完毕后,会优先执行所有已存在任务队列中的微任务,再去宏任务队列中取第一个执行,执行完成后检查微任务队列是否有任务,有就执行,完成后再去宏任务中取第二个执行,以此循环。
实例:
//第一个宏任务
setTimeout(() => {
console.log(1); //宏任务中的同步任务
Promise.resolve().then(() => { console.log(7) }) //宏任务中的微任务
}, 0); //异步任务 - 宏任务
console.log(2); //同步任务
Promise.resolve().then(() => { console.log(3) }) //异步任务 - 微任务
//第二个宏任务
setTimeout(() => {
console.log(8); //宏任务中的同步任务
setTimeout(() => { console.log(5) }, 0) //宏任务中的宏任务 第四个宏任务
}, 0);
//第三个宏任务
setTimeout(() => {
Promise.resolve().then(() => { console.log(4) }) //宏任务中的微任务
}, 0);
console.log(6); //同步任务
答案:2 6 3 1 7 8 4 5
9.js垃圾回收机制
10.有做过跨端应用吗 js与原生APP的交互
11.vue3使用多长时间了,封装了哪些组件与方法
12.最近有学新东西吗 学新技术倾向于边看边用还是系统性学习
13.项目优化
3月3号 新迪数字(金融港) 500-999人 3-5年 工业3D 12-20k
1.自我介绍 2,项目中的重难点。
3. 对MVVM的理解
MVVM,是Model-View-ViewModel的简写,其本质是MVC模型的升级版。其中 Model 代表数据模型,View 代表看到的页面,ViewModel是View和Model之间的桥梁,数据会绑定到ViewModel层并自动将数据渲染到页面中,视图变化的时候会通知ViewModel层更新数据。以前是通过操作DOM来更新视图,现在是数据驱动视图。
4. vue2与vue3的区别
vue2是选项式api将data和methods包括后面的watch,computed等分开管理,vue3是组合式api将相关逻辑放到了一起(类似于原生js开发)
Vue3中的生命周期相对于Vue2做了一些调整,命名上发生了一些变化并且移除了beforeCreate和created,因为setup是围绕beforeCreate和created生命周期钩子运行的,所以不再需要它们。生命周期采用hook函数引入。
vue2通过Object.definePropert()对数据进⾏劫持结合发布订阅模式的⽅式来实现双向绑定。vue3中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。这样更高效也能监听数组变化。
vue3增加了typescript的支持,优化了打包后的体积。
-
场景题 登录模块 角色模块和节点模块的增删改查 如何评估时间安排时间数据结构
-
对加班看法 职业规划
3月14日 一零跃动 技术面 3月15日 项目面+HR面 3-5年 13k-17k
1.js基础数据类型
number string boolean null undefined symbol bigint 引用类型:object array function math等
数据类型的校验instanceof可能出现的问题
基本类型用typeof null会返回object 可用===null判断 引用类型instanceof,问题:原型可被修改 比较全的,object.prototype.toString.call()
原型链
js是面对对象的,每个对象实例都有一个_proto_属性,指向它的原型对象。当访问对象属性时,就会沿着_proto_向上查找一直到object。object的原型指向null。
js事件队列与代码输出题
由于js是单线程的,会先执行同步任务,异步任务会被挂起放入异步队列中。异步任务被压入异步队列时又分为宏任务和微任务两个队列,宏任务包括script脚本加载,setTimeout,setInterval,微任务包括promise回调等。当同步任务完成后,会先执行所有的微任务队列中的任务,再去宏任务队列中取一个执行,再检查微任务队列中是否有新的任务,有就执行,执行完微任务再去宏任务队列中取下一个宏任务执行,一次循环。
实例:
//第一个宏任务
setTimeout(() => {
console.log(1); //宏任务中的同步任务
Promise.resolve().then(() => { console.log(7) }) //宏任务中的微任务
}, 0); //异步任务 - 宏任务
console.log(2); //同步任务
Promise.resolve().then(() => { console.log(3) }) //异步任务 - 微任务
//第二个宏任务
setTimeout(() => {
console.log(8); //宏任务中的同步任务
setTimeout(() => { console.log(5) }, 0) //宏任务中的宏任务 第四个宏任务
}, 0);
//第三个宏任务
setTimeout(() => {
Promise.resolve().then(() => { console.log(4) }) //宏任务中的微任务
}, 0);
console.log(6); //同步任务
答案:2 6 3 1 7 8 4 5
说说Map和WeakMap
传统js对象只能用字符串作为键名,为解决这个问题es6提供了Map,它类似于对象,但是各种类型的值包括对象都可以作为键。Weakmap与map类似,但只接受对象作为键名字。使用是场景是键名所对应的对象可能在将来消失,有利于防止内存泄漏,比如dom节点作为键名。
Set的使用场景
Set
它类似于数组,但是成员的值是唯一的,没有重复的值。可用于数组去重或者字符串去重。WeakSet类似于Set,但是它的值只能是对象。
foreach和map的区别
foreach是遍历返回值是undefined,map是映射,会返回一个新的数组。
promise async await实现原理
promise是异步编程的一种解决方案,它是一个构造函数,接收一个函数作为参数,返回一个Promise实例,创建promise实例后它会立即执行。Promise实例有三种状态:pending(进行中),fulfilled(已成功),rejected(已失败)。可在异步操作结束后调用resolve()变为fufilled状态,调用reject()变为rejected状态。亦可在promise原型上的then方法注册回调函数。
实例:
let p = new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(function(){
var num = Math.ceil(Math.random()*10); //生成1-10的随机数
if(num<=5){
resolve(num);
}
else{
reject('数字太大了');
}
}, 2000);
});
//then接收两个参数,第一个作为resolve的回调,第二个作为reject的回调
p.then((data) => {
console.log('resolved',data);
},(err) => {
console.log('rejected',err);
}
);
vue2响应式原理
如果是对象,通过Object.defineProperty(obj,key,descriptor)拦截对象属性访问 ,当数据变化时感知并作出反应。
当是数组时,覆盖数组原型的7个方法:push,pop,shift,unshift,splice,sort,reverse 使这些方法作出通知与响应。
虚拟dom
通过js对象来模拟dom,通过不同的属性来描述视图结构,一般包括tag(标签,组件,函数),props(标签上的属性或方法),children(内容或者子节点)。
$set
set是vue2提供的一个全局api,当直接修改对象的属性或者数组的值不会更新。是因为object.defineProperty()的局限性,监听不到变化,这种场景可用this.$set(数组或对象,下标或属性值,更新后的值)去手动刷新值。
$nextick与使用场景
nextick是vue提供的一个全局api,在下次dom更新结束之后执行延迟回调。
使用场景:1.在created生命周期中进行dom操作 2.更改数据后立即使用js操作新的视图。
v-for和v-if不能共用原因
vue2中v-for的优先级比v-if高,意味着每个循环都要判断v-if如果遍历的数组大展示的少,会造成性能浪费。
组件通信方式 inject和provide eventbus实现方式
provide/ inject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据
eventBus 又称为事件总线,在vue中可以使用它来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以通知其他组件。
使用:首先需要创建一个事件总线并将其导出, 以便其他模块可以使用或者监听它.
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
路由的钩子函数 vue3原理
3月20 和悦科技
vue指令
vue修饰符 表单修饰符:lazy,number,trim 事件修饰符:stop,prevent,self,once 鼠标修饰符:left,right,middle 键盘修饰符:keydown,keyup,enter,ctrl等
inject和provide用法
provide/ inject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。
注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据
数组的解构赋值场景 1.提取属性 2.分配默认值
如何遍历对象的属性
1.Object.keys():遍历自身可枚举的属性(可枚举,非继承属性)。该方法返回一个由给定对象的自身可枚举属性组成的数组。
2.Object.getOwnPropertyNames():遍历自身的所有属性(可枚举,不可枚举,非继承)。该方法返回指定对象的所有自身属性返回的数组。
3.for...in...遍历可枚举的自身属性和继承属性。
说一说promise
promise是异步编程的一种解决方案,它是一个构造函数,接收一个函数作为参数,返回一个promise实例,创建promise实例后它会立即执行。promise有三种实例状态:pending(进行中),resolved(已成功),rejected(已失败)。可在异步操作结束后调用resolve()变为resolved状态,调用reject()变为已失败状态。也可以使用promise原型上的then方法来注册回调函数。
实例:
let p = new Promise((resolve,reject)=>{
//做一些异步操作
setTimeout(function(){
let num = Math.ceil(Math.random()*10); //生成1到10的随机数
if(num<=5){
resolve(num)
}else{
reject('数字太大了!')
}
},1000);
})
//then接收两个参数,第一个作为resolve的回调,第二个作为reject的回调
p.then((data)=>{
console.log('resolved',num);
},(err)=>{
console.log('rejected',err);
})
mixin的使用
mixin混入,它提供一种灵活的方式来分发vue组件中的可复用功能。 使用场景:不同组件中会经常用到一些相同或者相似的代码,这些代码的功能相对独立。可通过mixin将相同或者相似的代码提出来。
3月29 趣米科技 技术面+主管面+Hr面
技术面
移动端布局
Css3 rgba和透明度,background-image,background-size,background-repeat,text-shadow,border-radius,border-image,媒体查询
rgba与opacity透明度的区别 opacity作用于元素及其所有内容,rgba只针对其对应的颜色或者背景色
Es6
- 块作用域let
- 箭头函数,定义和写法简单,不绑定this与arguments,不能作为构造函数
- 模板字符串
- 对象解构
- Promise,异步编程的解决方案
- Symbol,作为对象属性保证独一无二,bigint
- Set类似于数组,值独一无二,map类似于对象,键名可以不仅仅是字符串
- 函数默认参数
- ...扩展运算符,将数组转化为逗号分割的参数序列
vue2响应式原理
如果是对象,通过 Object.defineProperty 来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
当是数组时,覆盖数组原型的7个方法:push,pop,shift,unshift,splice,sort,reverse 使这些方法作出通知与响应。
vue生命周期
创建前后,挂载前后,更新前后,销毁前后
$nextick
nextick是vue提供的一个全局api,在下次dom更新结束之后执行延迟回调。
使用场景:1.在created生命周期中进行dom操作 2.更改数据后立即使用js操作新的视图。
$set
set是vue2提供的一个全局api,当直接修改对象的属性或者数组的值不会更新。是因为object.defineProperty()的局限性,监听不到变化,这种场景可用this.$set(数组或对象,下标或属性值,更新后的值)去手动刷新值。
vuex 刷新会丢失吗
vuex的 store 中的数据是保存在运行内存中的,当页面刷新时,页面会重新加载 vue 实例,vuex 里面的数据就会被重新赋值,这样就会出现页面刷新vuex中的数据丢失的问题。
强缓存与协商缓存
强缓存和协商缓存是浏览器优化加载速度的两种策略,核心区别在于:强缓存直接复用本地资源,完全不请求服务器;协商缓存则会先向服务器验证资源是否过期,再决定使用本地副本还是下载新内容。
强缓存
- 原理:服务器响应头设置
Cache-Control或Expires字段,浏览器据此在资源有效期内直接使用本地副本,不发送任何请求。 - 优点:零网络延迟,加载极快。
- 缺点:资源过期后可能无法及时更新。
协商缓存
- 原理:强缓存失效后,浏览器向服务器发送请求,携带
If-None-Match或If-Modified-Since头验证资源。服务器返回304 Not Modified则使用本地缓存,否则返回新资源。 - 优点:节省带宽,仅传输响应头。
- 缺点:需一次网络往返验证。
关键区别
| 特性 | 强缓存 | 协商缓存 |
|---|---|---|
| 请求服务器 | 否 | 是(验证资源) |
| 网络延迟 | 无 | 有(一次往返) |
| 资源更新 | 可能延迟 | 及时 |
简单说,强缓存是“直接用”,协商缓存是“先问再用”。
主管面
了解flutter吗
混合APP,js与原生开发之间的通信机制
职位匹配度
3月30日 猫眼视觉 HR一面+技术一面(线上视频面试)
最近一家公司的技术栈
css布局方式 static默认定位,relative相对定位,absolute绝对定位,fixed固定定位
flex布局 弹性盒子布局,通常可用作水平垂直居中,两栏三栏布局
H5 canvas,video,audio,localStorage,sessionStorage,websocket
js数组常用方法和reduce 返回新数组,不改变原数组:
join(分割成字符串)concat(拼接数组)slice(截取)
map(给每个参数执行回调,返回新数组)
foreach(给每个参数执行回调,返回undefined)
every(所有元素满足条件返回true)some(有一个满足就返回true)
filter(筛选出符合条件的数组)
reduce
接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。若是空数组是不会执行回调函数的;
// 0.0.2/reduce.js
const arr = [1, 2, 3, 4];
console.log(arr.reduce((prev, cur) => prev + cur, 0)); // 10
console.log('=>');
console.log(arr); // [ 1, 2, 3, 4 ]
返回新数组,改变原数组:
push,pop,shift,unshift
reverse,sort
splice(删除)
vue的生命周期 创建前后beforeCreate,created,挂载前后beforeMount,mounted,更新前后beforeUpdate,updated,销毁前后:beforeDestroy,destroyed
vue父子组件传参
-
父子组件通信:
父向子传递数据是通过
props,子向父是通过$emit触发事件;通过父链/子链也可以通信($parent/$children);ref也可以访问组件实例;provide/inject;$attrs/$listeners。 -
兄弟组件通信:
全局事件总线
EventBus、Vuex。 -
跨层级组件通信:
全局事件总线
EventBus、Vuex、provide/inject。
尽管存在prop和事件,有的时候你仍需要在JavaScript里直接访问一个子组件。
首先给子组件上添加一个ref属性
<base-alert ref="baseAlert"></base-alert>
现在可以使用
this.$refs.baseAlert
来访问子组件 base-alert的方法, 比如点击父组件的按钮,调用子组件的方法。
子组件能直接修改父组件的值吗
-
所有的
prop都遵循着单项绑定原则,props因父组件的更新而变化,自然地将新状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
另外,每次父组件更新后,所有的子组件中的props都会被更新为最新值,这就意味着不应该子组件中去修改一个prop,若这么做了,Vue 会在控制台上抛出警告。 -
实际开发过程中通常有两个场景导致要修改
prop:prop被用于传入初始值,而子组件想在之后将其作为一个局部数据属性。这种情况下,最好是新定义一个局部数据属性,从props获取初始值即可。- 需要对传入的
prop值做进一步转换。最好是基于该prop值定义一个计算属性。
-
实践中,如果确实要更改父组件属性,应
emit一个事件让父组件变更。当对象或数组作为props被传入时,虽然子组件无法更改props绑定,但仍然可以更改对象或数组内部的值。这是因为JS的对象和数组是按引用传递,而对于 Vue 来说,禁止这样的改动虽然可能,但是有很大的性能损耗,比较得不偿失。
computed与watch的区别
omputed计算属性,依赖其它属性计算值,内部任一依赖项的变化都会重新执行该函数,计算属性有缓存,多次重复使用计算属性时会从缓存中获取返回值,计算属性必须要有return关键词。watch侦听到某一数据的变化从而触发函数。当数据为对象类型时,对象中的属性值变化时需要使用深度侦听deep属性,也可在页面第一次加载时使用立即侦听immdiate属性。
运用场景:
计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
3月31日 高德智感科技 技术电话一面
css3有哪些新特性: rgba和透明度,background-image,background-size,background-repeat,text-shadow,border-radius,border-image,媒体查询
px rem em区别和使用
flex布局
如何画0.5px的线
综上讨论了像素和viewport的一些概念,并介绍和比较了在高清屏上画0.5px的几种方法——可以通过直接设置宽高border为0.5px、设置box-shadow的垂直方向的偏移量为0.5px、借助线性渐变linear-gradient、使用transform: scaleY(0.5)的方法,使用SVG的方法。最后发现transfrom scale/svg的方法兼容性和效果都是最好的,svg可以支持复杂的图形,所以在viewport是1的情况下,可以使用transform/SVG画0.5px,而如果viewport的缩放比例不是1的话,那么直接画1px即可。
js原生事件 mouseup mousedown
canvas的使用
websocket的api
open
- 一旦服务器响应了webscoket连接,open事件触发并且建立一个连接,对应的回调函数是
onopen。 - open事件触发后,就可以确定webscoket服务器成功处理了连接请求,并且同意进行通信。
message
message事件在接受到消息时触发,对应的回调函数是onmessage。- 除了文本信息,websocket还可以处理二进制数据,这种数据作为
Blob消息或者ArrayBuffer消息
error
-error事件在响应意外故障的时候触发。对应的回调事件是onerror。如果你接收到一个error事件,可以预期很快就会触发close事件。
close
-
close事件在websocket连接关闭时触发。对应的回调函数时onclose,一旦关闭连接,客户端和服务器不再能接收或者发送消息。 -
close事件中有3个有用的属性,可以通过这三个属性来分析断开的原因。
- wasclean:是一个布尔值,表示连接是否顺利关闭。如果是对来自服务器的一个close帧,则返回true。异常关闭则返回false。
- code 断开的识别码
- reason 断开的原因 字符串类型
-
其中code和reason跟websocket.close(code,reason)中传入的code和reason一致。
websocket的两个方法
send()
- 在监听websocket的open事件完成后,就可以调用
send()方法。
// 错误
const ws = new Websocket('ws://test.com')
ws.send(‘hello’)
// 正确
ws.onopen = ()=>{
ws.send('hello')
}
复制代码
-
如果在其他地方使用
send()方法,可以检查Websocket.readyState属性,并选择只在Websocket.readyState===1 -
readyState:记录连接过程中的状态值
- 0:CONNECTING -- 连接尚未建立
- 1:OPEN -- 连接已建立
- 2:CLOSING -- 连接正在关闭
- 3:CLOSED -- 连接已关闭或者不可用
close()
- 使用close方法,可以关闭websocket连接或连接尝试。在调用close之后,就不能发送数据了。
- close方式接收两个参数,
code状态码和reason关闭原因的字符串。
foreach和map的区别 foreach是遍历,返回值是undefined,map是映射,会返回一个新的数组。
vue父子组件通信
-
父子组件通信:
父向子传递数据是通过
props,子向父是通过$emit触发事件;通过父链/子链也可以通信($parent/$children);ref也可以访问组件实例;provide/inject;$attrs/$listeners。 -
兄弟组件通信:
全局事件总线
EventBus、Vuex。 -
跨层级组件通信:
全局事件总线
EventBus、Vuex、provide/inject。
父组件访问子组件的值
尽管存在prop和事件,有的时候你仍需要在JavaScript里直接访问一个子组件。
首先给子组件上添加一个ref属性
<base-alert ref="baseAlert"></base-alert>
现在可以使用
this.$refs.baseAlert
来访问子组件 base-alert的方法, 比如点击父组件的按钮,调用子组件的方法。
computed与watch的区别
omputed计算属性,依赖其它属性计算值,内部任一依赖项的变化都会重新执行该函数,计算属性有缓存,多次重复使用计算属性时会从缓存中获取返回值,计算属性必须要有return关键词。watch侦听到某一数据的变化从而触发函数。当数据为对象类型时,对象中的属性值变化时需要使用深度侦听deep属性,也可在页面第一次加载时使用立即侦听immdiate属性。
运用场景:
计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
js快排思路
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1) 首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2) 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都 小于分界值,而右边部分中各元素都大于或等于分界值。
(3) 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4) 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
var arr = [9, 4, 3, 1, 6, 3, 8, 7]
/**
* 快速排序
* @param {array} - arr 需要排序的数组
* @returns {array}
*/
function quickSort (arr) {
if (arr.length <= 1) return arr
var arr1 = [], arr2 = []
for (var i = 1; i < arr.length; i++) {
if (arr[i] < arr[0]) {
arr1.push(arr[i])
} else {
arr2.push(arr[i])
}
}
arr1 = quickSort(arr1)
arr2 = quickSort(arr2)
arr1.push(arr[0])
return arr1.concat(arr2)
}
console.log(quickSort(arr)) // [1, 3, 3, 4, 6, 7, 8, 9]
是否做过项目优化
4月4日 电话面试 幕库科技
vue2和vue3的区别
vue2是选项式api将data和methods包括后面的watch,computed等分开管理,vue3是组合式api将相关逻辑放到了一起(类似于原生js开发)
Vue3中的生命周期相对于Vue2做了一些调整,命名上发生了一些变化并且移除了beforeCreate和created,因为setup是围绕beforeCreate和created生命周期钩子运行的,所以不再需要它们。生命周期采用hook函数引入。
vue2通过Object.definePropert()对数据进⾏劫持结合发布订阅模式的⽅式来实现双向绑定。vue3中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。这样更高效也能监听数组变化。
vue3增加了typescript的支持,优化了打包后的体积。
promise all race方法
vue原理 虚拟dom diff 响应式原理
项目中印象深刻的点
技术广度与深度的平衡点
平时怎么学习新技术
职业规划
反问
2025 12月10号 民本集团 13+ HR面+技术线上面
HR面: 离职原因,婚姻状况,期望薪资
1.const let var区别
2.vue中key的作用
key是vue中给虚拟dom节点提供的唯一标识,帮助vue更高效的更新页面。
webpack作用
webpack是一个静态模块打包工具,主要作用是通过模块化方式管理和优化前端资源,包括代码打包,依赖分析,文件转换,以提高开发效率和项目性能。
vue的生命周期
创建前后beforeCreate,created,挂载前后beforeMount,mounted,更新前后beforeUpdate,updated,销毁前后:beforeDestroy,destroyed
vue父子组件传参
-
父子组件通信:
父向子传递数据是通过
props,子向父是通过$emit触发事件;通过父链/子链也可以通信($parent/$children);ref也可以访问组件实例;provide/inject;$attrs/$listeners。 -
兄弟组件通信:
全局事件总线
EventBus、Vuex。 -
跨层级组件通信:
全局事件总线
EventBus、Vuex、provide/inject。
尽管存在prop和事件,有的时候你仍需要在JavaScript里直接访问一个子组件。
首先给子组件上添加一个ref属性
<base-alert ref="baseAlert"></base-alert>
现在可以使用
this.$refs.baseAlert
来访问子组件 base-alert的方法, 比如点击父组件的按钮,调用子组件的方法
vueX状态管理
Vuex 将全局状态放入state对象中,它本身是一颗状态树,组件中使用store实例的state访问这些状态;然后用配套的mutation方法修改这些状态,并且只能用mutation修改状态,在组件中调用commit方法提交mutation;如果应用中有异步操作或复杂逻辑组合,需要编写action,执行结束如果有状态修改仍需提交mutation,组件中通过dispatch派发action。最后是模块化,通过modules选项组织拆分出去的各个子模块,在访问状态(state)时需注意添加子模块的名称,如果子模块有设置namespace,那么提交mutation和派发action时还需要额外的命名空间前缀。
js 0.1+0.2精度问题处理
1.知道小数位数可以先乘再除
const result = (0.1 * 10 + 0.2 * 10) / 10; console.log(result); // 输出 0.3
2.使用第三方库,如big.js
简单算法:给定一个数字数组,返回数字与下标相等的最小下标
function minIndex(nums){
let result = -1
for(let i=0; i<nums.length;i++){
if(nums[i] === i){
result = i;
break;
}
}
return result;
}
console.log(minIndex(num)) //3`
12月15 腾讯云智(腾讯会议)
webpack的作用,做了哪些项目优化
webpack是一个静态模块打包工具,主要作用是通过模块化方式管理和优化前端资源,包括代码打包,依赖分析,文件转换,以提高开发效率和项目性能。webpack做的就是分析代码,转换代码,编译代码,输出代码。
webpack 默认只能处理 js 文件,如果想处理图片等其他文件,则需要用到相应的 loader。比如 file-loader 、 url-loader 、 css-loader 、 style-loader ,如果用 sass 的话会用到 sass-loader 。
其他几个重要的概念是:
- mode: 指定打包的模式,development 或 production。
- devtool:指定生成 sourceMap 的方式。
- entry:配置入口文件,多文件打包的话要打包几个文件,就在 entry 中写几个入口,output 的 filename 用占位符
[name]表示。 - output: 出口。
- loader:辅助打包的各种工具。
- plugins:插件,loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。如 HtmlWebpackPlugin,CleanWebpackPlugin。
webpack的构建流程?
webpack的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译确定入口:根据配置中的 entry 找出所有的入口文件编译模块:从入口文件出发,调用所有配置的 loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理完成模块编译:在经过上一步使用 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用webpack提供的 API 改变webpack的运行结果。
简单说:
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
- 编译:从 entry 出发,针对每个 Module 串行调用对应的 loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
项目角色和人员职责
输入URL的访问全流程
-
url解析:首先会判断输入的是一个合法 url还是关键词,并根据输入的内容进行相应的操作。 -
查找缓存:浏览器会判断所请求的资源是否在浏览器缓存中,以及是否失效。如果没有失效就直接使用;如果没有缓存或失效了,就继续下一步。 -
DNS解析:此时需要获取url中域名对应的IP地址。浏览器会依次查看浏览器缓存、操作系统缓存中是否有ip地址,如果缓存中没有就会向本地域名服务器发起请求,获取ip地址。本地域名服务器也会先检查缓存,有则直接返回;如果也没有,则采用迭代查询方式,向上级域名服务器查询。先向根域名服务器发起请求,获取顶级域名服务器的地址;再向顶级域名服务器发起请求以获取权限域名服务器地址;然后向权限域名服务器发起请求并得到url中域名对应的IP地址。 -
建立TCP连接:根据ip地址,三次握手与服务器建立TCP连接。 -
发起请求:浏览器向服务器发起HTTP请求。 -
响应请求:服务器响应HTTP请求,将相应的HTML文件返回给浏览器。 -
关闭TCP连接:四次挥手关闭TCP连接。 -
渲染页面:浏览器解析HTML内容,并开始渲染。浏览器渲染过程如下:构建DOM树:词法分析然后解析成DOM树,DOM树是由DOM元素及属性节点组成,树的根是document对象。构建CSS规则树:生成CSS 规则树。构建渲染树:将DOM树和CSS规则树结合,构建出渲染树。布局:计算每个节点的位置。绘制:使用浏览器的UI接口进行绘制。
ngnix配置了解吗
算法: 最长子串
/** * @param {string} s * @return {number} */
var lengthOfLongestSubstring = function(s) {
// 滑动窗口问题
// 1.创建存放当前的不重复子串
// 2.指针i跟着循环往后走,指针j指向字符串的开头
// 3.遍历s,不重复就往set中添加s[i]
// 4.重复就遍历set,删除s[j],直到set中没有s[i]
let i=0,j=0,max=0;
const set = new Set();
for(;i<s.length;i++){
if(set.has(s[i])){
while(set.has(s[i])){
set.delete(s[j]); j++;
}
set.add(s[i]);
}else{
set.add(s[i]);
max = Math.max(max,set.size);
}
}
return max;
};
12月16日 京东酒旅
webpack作用,做了哪些优化(项目亮点)
webpack是一个静态模块打包工具,主要作用是通过模块化方式管理和优化前端资源,包括代码打包,依赖分析,文件转换,以提高开发效率和项目性能。webpack做的就是分析代码,转换代码,编译代码,输出代码。
不刷新问题处理
- 文件名哈希策略
通过在文件名中添加哈希值(如 [name].[contenthash].js),确保每次代码变更生成新文件名,避免缓存问题。
-
项目级别哈希:
[hash](全局哈希) -
文件级别哈希:
[contenthash](仅内容变化时更新) -
代码示例:
javascriptCopy Code // webpack.config.js output: { filename: '[name].[contenthash].js', chunkFilename: '[name].[contenthash].js' }配置服务器(如 Nginx)禁止缓存
index.html,确保每次请求都能获取最新版本。 -
Nginx 配置:
nginxCopy Code location / { add_header Cache-Control no-store; add_header Pragma no-cache; }
打包优化: 1.生产环境去掉sourcemap,console
2.图片和css进行压缩或者使用CDN静态资源
3.第三方包打包时添加到externals,使用时按需引入(require)
4.使用plugins压缩js,css
开启gzip压缩
以vue-cli为例配置Gzip如下:
- vue.config.js配置Gzip压缩
体验AI代码助手
代码解读
复制代码
const CompressionWebpackPlugin = require('compression-webpack-plugin')
module.exports = {
......
configureWebpack: config => {
config.plugins.push(new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test:/.js$|.html$|.\css/, // 匹配文件名
threshold: 10240, // 对超过10k的数据压缩
minRatio: 0.8, // 只有压缩好这个比率的资产才能被处理
deleteOriginalAssets: true // 删除源文件
}));
}
}
- 配置Nginx
将nginx配置开启gzip压缩,nginx会根据配置情况对指定的类型文件进行压缩。主要针对js与css。如果文件路径中存在与原文件同名(加了个.gz),nginx会获取gz文件,如果找不到,会主动进行gzip压缩。
nginx配置如下:
体验AI代码助手
代码解读
复制代码
gzip on; #开启或关闭gzip on off
gzip_disable "msie6"; #不使用gzip IE6
gzip_min_length 100k; #gzip压缩最小文件大小,超出进行压缩(自行调节)
gzip_buffers 4 16k; #buffer 不用修改
gzip_comp_level 8; #压缩级别:1-10,数字越大压缩的越好,时间也越长
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; # 压缩文件类型
gzip_vary off;
vue2和vue3的区别
ue2是选项式api将data和methods包括后面的watch,computed等分开管理,vue3是组合式api将相关逻辑放到了一起(类似于原生js开发)
Vue3中的生命周期相对于Vue2做了一些调整,命名上发生了一些变化并且移除了beforeCreate和created,因为setup是围绕beforeCreate和created生命周期钩子运行的,所以不再需要它们。生命周期采用hook函数引入。
vue2通过Object.definePropert()对数据进⾏劫持结合发布订阅模式的⽅式来实现双向绑定。vue3中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。这样更高效也能监听数组变化。
vue3增加了typescript的支持,优化了打包后的体积。
vue3相比于vue2快在哪儿
Vue 3 相比于 Vue 2 的性能提升主要体现在响应式系统、编译优化、虚拟 DOM 算法以及打包体积等多个方面。
- 响应式系统优化:Vue 3 采用 Proxy 代理整个对象,替代 Vue 2 的 Object.defineProperty,仅在属性访问时建立依赖,避免了递归遍历的开销。这使得初始化速度提升 40%~60%,内存占用降低 30%,并原生支持动态属性的添加和删除。12
- 编译时优化:Vue 3 引入静态提升(Static Hoisting),将模板中的静态节点提升至渲染函数外部,避免重复创建虚拟节点,首屏渲染速度提升约 30%。同时,Patch Flag 标记动态节点的更新类型(如文本或类名),减少 diff 计算量,更新效率提升 20%~50%。1
- 虚拟 DOM 重写:Vue 3 重写了虚拟 DOM 的 Block Tree 结构,将动态节点收集为数组,跳过静态子树的对比,更新性能提升约 30%。事件监听器缓存机制也减少了内存分配。1
- 打包体积与加载优化:通过 Tree-shaking 机制,未使用的模块不会被打包,生产环境体积减少 41%(Vue 2 runtime 约 23KB,Vue 3 约 14KB)。结合 Vite 等工具,首屏加载速度比 Vue 2 快 55%,SSR 水合速度提升 2~3 倍。12
- 实际场景收益:在大型表格渲染(如 1000 行数据)中,Vue 3 渲染时间从 Vue 2 的约 1.2 秒降至 0.65 秒;高频状态更新场景下,ref 批量更新机制比 Vue 2 的 watcher 队列效率提升 35%。1
这些优化使得 Vue 3 在典型应用中实现 40%~70% 的性能提升,尤其适合大型、交互频繁的项目。
实现v-lazy指令
以下是实现v-lazy指令的代码:
使用IntersectionObserver实现懒加载,兼容性好 指令挂载时创建观察器,监听元素进入可视区域 元素进入可视区后替换src属性,触发图片加载 加载后自动停止观察,避免重复触发 可通过插件形式全局注册,易于集成到Vue项目
const lazyPlugin = {
install(app, options) {
app.directive('lazy', {
mounted(el, binding) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = binding.value;
observer.unobserve(el);
}
});
});
observer.observe(el);
}
});
}
}
export default lazyPlugin;
实现一个类 N个请求按顺序执行
1.使用队列结构存储请求函数,通过addRequest方法添加请求 2.runNext方法递归执行队列中的请求,确保顺序执行 3.使用async/await处理异步请求,自动等待前一个请求完成 4.支持错误处理,失败请求会打印错误信息但不影响后续请求 5.通过isRunning标志避免并发执行,确保单线程顺序执行 6.可直接在项目中实例化使用,调用addRequest添加请求即可
class RequestQueue {
constructor() {
this.queue = [];
this.isRunning = false;
}
addRequest(requestFn) {
this.queue.push(requestFn);
this.runNext();
}
async runNext() {
if (this.isRunning || this.queue.length === 0) return;
this.isRunning = true;
const requestFn = this.queue.shift();
try {
await requestFn();
} catch (error) {
console.error('Request failed:', error);
}
this.isRunning = false;
this.runNext();
}
}
12月17 加速进化
项目中的重难点
webpack作用与使用
算法:对象数组转树结构
支持自定义id、parentId和children字段名
使用对象映射加速查找,时间复杂度O(n)
递归构建树结构,自动处理多层级嵌套
返回根节点数组,支持多棵树并列
处理无父节点项为顶级节点
保留原始数据结构,避免修改输入数据
function arrayToTree(data, idField = 'id', parentIdField = 'parentId', childrenField = 'children') {
const map = {};
const tree = [];
data.forEach(item => {
map[item[idField]] = { ...item, [childrenField]: [] };
});
data.forEach(item => {
const parentId = item[parentIdField];
if (parentId === null || parentId === undefined) {
tree.push(map[item[idField]]);
} else {
map[parentId][childrenField].push(map[item[idField]]);
}
});
return tree;
}
场景题
26年1月7号 高途
H5和后台管理项目优化思路
场景题:promise场景题目 实现一个函数,返回一个promise 缓存基础数据,第一次请求成功就返回结果,第一次失败可以继续请求
vue2响应式原理
如果是对象,通过 Object.defineProperty 来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
当是数组时,覆盖数组原型的7个方法:push,pop,shift,unshift,splice,sort,reverse 使这些方法作出通知与响应。
$nextick
nextick是vue提供的一个全局api,在下次dom更新结束之后执行延迟回调。
使用场景:1.在created生命周期中进行dom操作 2.更改数据后立即使用js操作新的视图。
$set
set是vue2提供的一个全局api,当直接修改对象的属性或者数组的值不会更新。是因为object.defineProperty()的局限性,监听不到变化,这种场景可用this.$set(数组或对象,下标或属性值,更新后的值)去手动刷新值
vite相比于webpack快在哪儿
-
原生 ESM 绕过打包:开发阶段不打包,浏览器直接请求模块,服务器只转换但不打包。
-
Esbuild 替代 Babel/TS:使用 Go 编写的 Esbuild 处理 TS/JSX,比 JavaScript 工具快几个数量级。
-
智能缓存:
- 依赖模块用
node_modules/.vite缓存。 - 源码模块用
Cache-Control: max-age=31536000强缓存,通过304 Not Modified协商更新。
- 依赖模块用
vue3 tree shakeing快的原因
- 架构重构:从单体到模块化设计
- API 设计:Composition API 天然支持按需使用
- 编译器优化:编译时静态分析和标记
- 构建优化:ES Module 原生支持 + 特性标志
- 生态配合:现代打包器(Vite/Rollup)深度优化
这使得 Vue 3 应用最小可至 6KB,相比 Vue 2 减少了 60-70% 的必须代码体积,特别适合移动端和性能敏感场景。
js typeof instanceof 区别
基本类型用typeof null会返回object 可用===null判断 引用类型instanceof,问题:原型可被修改 比较全的,object.prototype.toString.call()
js事件冒泡和事件捕获场景
何时使用捕获?
- 需要最早处理事件时(全局拦截、安全监控)
- 防止事件被阻止冒泡时(确保事件被处理)
- 性能关键的委托场景(比冒泡委托更快)
- 框架/库底层实现(需要控制事件流)
何时使用冒泡?
- 事件委托(95% 的场景)
- 组件通信(自定义事件系统)
- 用户行为分析(收集所有交互)
- 默认行为(大部分业务逻辑)
// 1. 小心 stopPropagation 的影响
element.addEventListener('click', (e) => {
e.stopPropagation(); // 会影响所有父级监听器!
// 只在确实需要时使用
});
// 2. 事件顺序:捕获 → 目标 → 冒泡
document.addEventListener('click', handler1, true); // 1. 最先执行
target.addEventListener('click', handler2); // 2. 目标阶段
document.addEventListener('click', handler3, false); // 3. 最后执行
// 3. 事件委托的性能优化
// ❌ 差的委托:每次事件都遍历
container.addEventListener('click', (e) => {
const buttons = container.querySelectorAll('button');
buttons.forEach(btn => {
if (btn === e.target) { /* ... */ }
});
});
// ✅ 好的委托:利用事件冒泡
container.addEventListener('click', (e) => {
if (e.target.matches('button')) { /* ... */ }
});
// 4. 现代 API:once 和 passive 选项
element.addEventListener('click', handler, {
capture: true, // 捕获阶段
once: true, // 只执行一次
passive: true // 不调用 preventDefault()
});
总结
- 事件捕获:适合底层框架、全局控制、性能优化场景
- 事件冒泡:适合业务逻辑、事件委托、组件通信场景
- 实际开发中:80% 用冒泡(事件委托),15% 用默认(不指定),5% 用捕获(特殊需求)
- 现代框架:通常封装了事件系统,但了解原理有助于优化和调试
css 画三角形 使用边框 相邻的边透明减半,斜边正常
.up-triangle { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid #3498db; /* 或合并写法:border: 50px solid transparent; border-bottom: 100px solid #3498db; */ }
浏览器输入网址全过程
强缓存和协商缓存
强缓存和协商缓存是浏览器优化加载速度的两种策略,核心区别在于:强缓存直接复用本地资源,完全不请求服务器;协商缓存则会先向服务器验证资源是否过期,再决定使用本地副本还是下载新内容。
强缓存
- 原理:服务器响应头设置
Cache-Control或Expires字段,浏览器据此在资源有效期内直接使用本地副本,不发送任何请求。 - 优点:零网络延迟,加载极快。
- 缺点:资源过期后可能无法及时更新。
协商缓存
- 原理:强缓存失效后,浏览器向服务器发送请求,携带
If-None-Match或If-Modified-Since头验证资源。服务器返回304 Not Modified则使用本地缓存,否则返回新资源。 - 优点:节省带宽,仅传输响应头。
- 缺点:需一次网络往返验证。
关键区别
| 特性 | 强缓存 | 协商缓存 |
|---|---|---|
| 请求服务器 | 否 | 是(验证资源) |
| 网络延迟 | 无 | 有(一次往返) |
| 资源更新 | 可能延迟 | 及时 |
简单说,强缓存是“直接用”,协商缓存是“先问再用”。
cdn原理
CDN的核心原理是通过智能DNS解析 + 边缘节点缓存 + 负载均衡,将用户请求路由到最近的缓存节点。其优势在于:
- 减少延迟:物理距离缩短
- 降低负载:缓存减少源站压力
- 提高可用性:多节点容灾
- 节省带宽:边缘缓存减少重复传输
- 增强安全:DDoS防护、WAF等
现代CDN已从简单的缓存服务器,发展成为集内容分发、安全防护、边缘计算于一体的综合性平台,成为现代互联网基础设施的关键组成部分。
H5长页面卡顿优化思路
1.7 1.8泰康保险外包
项目经历和流程
vue2和3的区别
响应式原理
TS的使用 interface和type的区别 总结对比表
| 特性 | Interface | Type | 推荐场景 |
|---|---|---|---|
| 声明合并 | ✅ 支持 | ❌ 不支持 | 扩展第三方类型定义 |
| 扩展方式 | extends 关键字 | & 交叉类型 | 根据个人/团队偏好 |
| 实现类 | ✅ implements | ❌ 不能直接实现 | 面向对象编程 |
| 元组类型 | ❌ 需要间接实现 | ✅ 直接支持 | 定义固定长度数组 |
| 联合类型 | ❌ 不能直接定义 | ✅ 直接支持 | 状态机、选项集合 |
| 映射类型 | ❌ 不支持 | ✅ 支持 | 工具类型、类型变换 |
| 条件类型 | ❌ 不支持 | ✅ 支持 | 高级类型操作 |
| 性能 | 通常更好 | 复杂时可能稍差 | 大型项目优先 Interface |
| 错误信息 | 相对简单 | 有时更详细 | 根据调试需求选择 |
| 可读性 | 更面向对象 | 更函数式 | 根据团队习惯选择 |
最终建议
- 默认使用 Interface:用于定义对象形状、类实现、API 响应
- 需要时使用 Type:联合类型、元组、工具类型、条件类型
- 保持一致性:团队内部统一规范
- 实用为主:不要过度设计,选择最适合当前场景的方式
- 渐进采用:新项目可以更激进使用 Type,老项目保持现有风格
记住:Interface 和 Type 在大多数情况下可以互换,选择的关键在于代码的可读性、可维护性和团队协作效率。
vue3的hooks
浏览器输入网址
vue3 为什么弃用minxin
minxin存在命名冲突来源模糊等问题
1.9 招行外包
线上笔试选择题
vue2 3区别与响应式原理
打包配置了哪些优化 打包层面和代码层面 按需加载和图片懒加载
v-model原理
v-model 本质上是 :value + @input 的语法糖。
Vue 会根据不同的表单元素,智能适配对应的属性和事件:
| 元素 | 对应的属性 & 事件 |
|---|---|
<input type="text"> | value + input 事件 |
<textarea> | value + input 事件 |
<input type="checkbox"> | checked + change 事件 |
<input type="radio"> | checked + change 事件 |
<select> | value + change 事件 |
在自定义组件上使用 v-model 时,默认对应 modelValue 属性和 update:modelValue 事件(Vue 3)。
浏览器重绘与回流详解
回流(Reflow/Layout)
- 定义:计算元素在页面中的位置和几何信息的过程
- 触发条件:影响布局的样式改变
- 代价:昂贵,需要重新计算所有受影响元素的几何属性
重绘(Repaint)
- 定义:将元素的外观属性绘制到屏幕的过程
- 触发条件:不改变布局,只改变外观(颜色、背景等)
- 代价:相对较轻,但依然有性能开销
1月15 海洋无线
vue2/3的区别
js基础数据类型
number string boolean null undefined symbol bigint 引用类型:object array function math等
css居中方式
强缓存与协商缓存
强缓存和协商缓存是浏览器优化加载速度的两种策略,核心区别在于:强缓存直接复用本地资源,完全不请求服务器;协商缓存则会先向服务器验证资源是否过期,再决定使用本地副本还是下载新内容。
强缓存
- 原理:服务器响应头设置
Cache-Control或Expires字段,浏览器据此在资源有效期内直接使用本地副本,不发送任何请求。 - 优点:零网络延迟,加载极快。
- 缺点:资源过期后可能无法及时更新。
协商缓存
- 原理:强缓存失效后,浏览器向服务器发送请求,携带
If-None-Match或If-Modified-Since头验证资源。服务器返回304 Not Modified则使用本地缓存,否则返回新资源。 - 优点:节省带宽,仅传输响应头。
- 缺点:需一次网络往返验证。
关键区别
| 特性 | 强缓存 | 协商缓存 |
|---|---|---|
| 请求服务器 | 否 | 是(验证资源) |
| 网络延迟 | 无 | 有(一次往返) |
| 资源更新 | 可能延迟 | 及时 |
简单说,强缓存是“直接用”,协商缓存是“先问再用”。 node
跨端 桌面端
TS常见数据类型
TypeScript 的常见数据类型包括基本类型、数组、元组、枚举、any、void、null、undefined、never 和object 等。12
基本数据类型:TypeScript 支持与 JavaScript 类似的布尔值、数字和字符串等基本类型。布尔值类型为 boolean,表示 true 或 false;数字类型为 number,包括整数和浮点数;字符串类型为 string,使用单引号或双引号表示,支持模板字符串。12
数组与元组:数组类型可通过元素类型后接 [] 或使用数组泛型 Array<元素类型> 定义,例如 number[] 或 Array<string>。元组类型用于表示已知元素数量和类型的数组,例如 [string, number]。12
枚举与高级类型:枚举类型(enum)用于定义一组命名常量,例如 enum Color { Red, Green, Blue }。any类型允许存储任意值,禁用类型检查;void 类型表示无类型,通常用于无返回值的函数;null 和 undefined 类型分别表示空值和未定义值;never 类型表示永远不存在的值,常用于抛出异常的函数;object 类型表示非原始类型的数据。12
类型断言与特殊处理:类型断言允许手动指定类型,例如使用 as 关键字将值断言为特定类型。此外,TypeScript 支持联合类型和交叉类型等高级类型操作。
1月16 卓尔数科
vue2/3区别 3为什么更快 vite为什么更快
中后台管理系统白屏时间过长优化思路
单页面卡顿优化思路
微信小程序测试发布流程
vue3和小程序写过多久
1月23 科大讯飞-教育bg
作用域 var let const
深拷贝,浅拷贝
判断数据类型
闭包
vue通信方式
nextick
vue3生命周期
vue3 ref reactive使用
vuex he pinia区别
富文本编辑器
读写
sse
websocket