2月21日 上海昊仓系统(光谷总部时代) 100-499人 3-5年 智慧水务 10-15k
1.测试题 30min css js vue 大部分选择题 自我介绍 5min
3.css
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;代表什么意思
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)
4.js
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
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的支持,优化了打包后的体积。
5. 场景题 登录模块 角色模块和节点模块的增删改查 如何评估时间安排时间数据结构
6. 对加班看法 职业规划
一零跃动 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
2 Es6
说说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);
}
);
3.vue相关
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 使这些方法作出通知与响应。
生命周期
创建前后,挂载前后,更新前后,销毁前后
$nextick
nextick是vue提供的一个全局api,在下次dom更新结束之后执行延迟回调。
使用场景:1.在created生命周期中进行dom操作 2.更改数据后立即使用js操作新的视图。
$set
set是vue2提供的一个全局api,当直接修改对象的属性或者数组的值不会更新。是因为object.defineProperty()的局限性,监听不到变化,这种场景可用this.$set(数组或对象,下标或属性值,更新后的值)去手动刷新值。
vuex 刷新会丢失吗
vuex的 store 中的数据是保存在运行内存中的,当页面刷新时,页面会重新加载 vue 实例,vuex 里面的数据就会被重新赋值,这样就会出现页面刷新vuex中的数据丢失的问题。
强缓存与协商缓存
强缓存: 当一个浏览器第一次访问一个网站的时候,向该网站的服务器发送请求。如果服务端觉得浏览器请求的资源应该被缓存下来时 比如图片,CSS文件等不常更改的资源,没有必要在 HTTP 响应中频繁携带,就会在 HTTP 响应里面添加一个响应头 Cache-Control:max-age=1200(即缓存有效时间为1200s) 。这会让浏览器自动将该请求的资源缓存到本地。
下一次请求该资源时,浏览器先看本地缓存的资源有没有过期,没过期的话直接使用该资源,不发送请求,且返回 Status Code:200 OK,但是会添加上(from memory cache 或 from disk memory)的标识,表示该文件是从缓存中拿到的,没有向服务端发送请求。
如果过期了且没有协商缓存(可以先跳过这个协商缓存,下面会讲)就向服务端发送请求索要该资源,服务端依然是根据该资源的特性判断要不要缓存,即要不要加 Cache-Control 响应头。
整个过程都是由 服务端控制
,浏览器要不要缓存取决于 HTTP 响应头有没有设置 Cache-Control,且取值不为 no-store(no-store 表示不缓存)。
协商缓存: 当一个浏览器第一次访问一个网站的时候,向该网站的服务器发送请求。服务器返回资源和资源的标识。浏览器会把该资源和该标识缓存到本地。
下一次请求该资源时,浏览器会把该资源标识带上,服务器就会对该标识对应的资源进行判断:
(1)如果该资源发生了修改,已不是原来的版本,那么服务器就会返回最新的资源和新的资源标识,状态码为200,表示请求成功。
(2)如果该资源距离上一次请求并没有发生改变,则返回304,告诉浏览器可以直接使用本地缓存的资源,响应时就无需携带资源。
主管面
了解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 响应式原理
项目中印象深刻的点
技术广度与深度的平衡点
平时怎么学习新技术
职业规划
反问