一 第一家,23.9.20外包
岗位要求会前端工程化,微前端,环境部署。
1. inset代表什么属性的缩写?
用于定位,可以用px或百分比等设置定位的4个偏移量。可应用于任何writing-mode属性。
用法:inset:length|percentage|auto|inherit继承|initial默认|unset;
.child{
position:absolute;
inset:10px 40px 30px 0px;
}
inset:0; 代表top right bottom left都是0,也就是铺满relative。
2. flex:1;代表哪几个属性的缩写?
等于:
flex-grow:1; 放大比例
flex-shrink:1; 缩小比例
flex-basis:0%;平分剩余空间%,
3. css优先级排序?伪类排哪里 ?
类、伪类、属性相等。元素、伪元素相等。
4. 数组的方法有哪些?增删改查、循环等
伪数组:有数组的结构,没有push、pop等属性 伪数组->数组:Array.from(arr)
- 改变原数组有9个: pop, push, shift, unshift, reverse, splice, sort, copywithin, fill
- 不改变原数组有8个: join, toLowcaleString, toString, slice, cancat, indexOf, lastIndexOf, includs
- 遍历12个: forEach遍历, map操作数组每一个元素并返回新数组, every是否都符合, some判断有无符合的, filter过滤符合的,find查询符合条件的元素, reduce累加, reduceRight, 查询符合条件的元素的下标:findIndex, keys, values, entries
// 创建:
[];
new Array()
Array.of(1,2) == [1,2]
Array.from()转伪数组
//类数组转数组:
// 1. Array.from
const pseudoArray = {0: "a", 1: "b", 2: "c", length: 3};
const array = Array.from(pseudoArray);
console.log(array); // ["a", "b", "c"]
//2. 使用Array.prototype.slice.call()方法:
const array = Array.prototype.slice.call(pseudoArray);
console.log(array); // ["a", "b", "c"]
//3. 扩展运算符
const array = [...pseudoArray];
console.log(array); // ["a", "b", "c"]
//4. 使用Array.prototype.map().call方法:
const array = Array.prototype.map.call(pseudoArray, function(value) {
return value;
});
console.log(array); // ["a", "b", "c"]
```js
增&删&改
push增尾 --- pop删尾
unshift增头 --- shift删头
splice(index, length, item)删除并返回删除元素,可删可改
slice() 返回选中的新数组,不改变原数组。
myArr.copyWithin(targetIndex, start, end): (修改原数组内容,length不变)
targetIndex:复制后放到哪个位置
start & end:复制开始和结束的下标
Array.fill(value, [start, end]) 修改数组,用value替换原数组内容
start和end默认0,也就是每一个元素都替换。注意:value是对象时,只是引用关系。
reverse() 颠倒顺序
sort(function(a, b) {
return a - b
}) //数组排序
sort(function(a, b) {
return b - a
}) //数组排序
5. this指针?严格模式下呢?
this跟执行环境、声明环境、class有关。
- 对象内,this指向方法所在对象的name属性。
- function函数无调用者,指向window
- new构造函数--new的对象,class同。
- call,apply指向调用对象
- 普通函数内指向调用者,如obj.fuc,fuc的this指向obj。
- 箭头函数,外层函数的this就是内层函数的this==自身没有this,从外层找到后继承,如果就一层指向window,
严格模式,指向undefined
箭头函数没有自己的this,它的this是继承来的。默认指向定义时的宿主,
6. 高阶函数有什么?
如果函数的参数,或者返回值,也是函数,那就是高阶函数。
举例:promise, 计时器, map, filter, reduce等
7. call,apply,bind
这3种是function的prototype上的方法,所以谁都可以用。作用都一样:改变this的指向,说白了就是用一个obj调用一个函数,补足函数没有值的参数。
不同:apply第二个参数是数组形式;bind需要再调用()一次。
greet.apply(null, [names]);
const boundGreet = greet.bind(obj);
console.log(boundGreet()); //再调用一次
适用场景:
- Object.prototype.toString.call(obj)实现类型检测。
首先,我们知道js全员皆对象,都是从Object继承而来,而Object原型上的toString是可以输出对象类型的,这个toString方法也被继承给了每一个类,但是他们在继承时都做了改写。所以,使用Object最原始的也就是prototype上的toString方法是可以判断类型的,只要把this指向需要判断的元素,就可以直接输出类型了。 - Math.max.call(Math, arr)计算数组最大值
效果等同于Math.max(...arr)解构数组 - 实现继承
function peaple(name) {
this.name = name;
this.showName = function () {
console.log(this.name);
}
}
function student(name) {
peaple.call(this, name);
}
var xiaoming = new student('xiaoming');
xiaoming.showName();
call把原本people的this指向了student,所以student继承了原来的所有。
用现有的函数去处理call的值。
- 数组追加
var array1 = [1 , 2 , 3, 5];
var array2 = ["xie" , "li" , "qun" , "tsrot"];
Array.prototype.push.apply(array1, array2);
console.log(array1);
类似于 let c = array1.concat(array2)
- 保存this变量
var foo = {
bar : 1,
eventBind: function(){
var _this = this ;
$('.someClass').on('click',function(event) {
console.log(_this.bar);
});
}
}
var foo = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
console.log(this.bar);
}.bind(this));
}
}
8. 说说对原型的理解?什么是原型链
代码中创建一个function,浏览器会对应生成一个object(js全员皆对象),每个对象都初始化一个prototype内部属性,就是该对象的原型。除了Object.prototype对象以外的对象都是通过其他对象的原型创建的。
访问一个对象的属性或方法时,如果没找到就会向上继续找,去对象的Prototype里找,这个prototype又有自己的prototype,这样一直找下去就形成了原型链。这种查找机制就是原型链。
js的继承常见的原型链继承,构造函数继承,原型+构造,寄生,寄生组合。
9.说一下防抖和节流
在resize、onscroll、input内容校验onkeydown,类似这样的操作如果无限制触发调用函数,js-css-layout-paint-composite,会加重浏览器负担,debounce防抖和throttle节流就应运而生了。 不同:
- 防抖--抖动是没有必要的,只要最后一次就行。在delay之前触发会重新计时,最终只执行一次。(多次执行变最后一次执行)
- 节流--类似王者技能的触发,有CD时间,不能无限制发动技能。实时更新用这个,在1分钟内只触发一次,多次触发无效。1分钟后重新计时再执行下一次。(多次执行变每隔一段时间触发一次)
工作中,可以原生js实现,lodash插件有提供现成的方法。
10.介绍async和await
- async是声明function是异步的,awaite是等待一个异步执行完。
- 规则:
- awaite只能在async里使用,不可单独使用。
- async返回的是一个promise对象,awaite就是等待这个promise的结果,再继续执行。
- awaite等待的是一个promise,后面必须跟一个promise对象,但是不必写then(),直接得到返回值。
- async/awaite的特点
- async放在函数前,函数变为异步函数。
- 在函数前加async,打印函数调用,是一个Promise对象,而不是函数体内容。
- async配合awai使用。
- 调用依次发生
- Promis.then是链式调用,一直...,符合书写代码习惯。
只有async没有await时,函数返回什么:一个Promise
11.浏览器关闭前,怎么确保发出请求
方法1:
使用 Fetch 的keepalive标志
方法2:
使用Navigator.sendBeacon()
方法:
PC端有用,Vue项目中。
mounted() {
window.addEventListener("beforeunload", () => this.beforeunloadHandler());
window.addEventListener("unload", () => this.unloadHandler());
},
beforeDestroy() {
// 假如你需要在销毁之前去做一些操作,可以在这里进行,比如:
clearTimeout(this.NItimeout);
clearTimeout(this.timeout);
},
destroyed() {
window.removeEventListener("beforeunload", () =>this.beforeunloadHandler());
window.removeEventListener("unload", () => this.unloadHandler());
},
methods:{
beforeunloadHandler() {
this.beforeUnloadTime = new Date().getTime();
},
async unloadHandler() {
this.gapTime = new Date().getTime() - this.beforeUnloadTime;
if (this.gapTime <= 5) { //判断是窗口关闭还是刷新,小于5代表关闭,否则就是刷新。
// 重要提示:此处的的请求一定是要同步的,axios在此处不可用,已经踩过坑了。直接使用原生js发请求。
// 根据你的实际情况写请求地址,为了防止跨域此处使用了拼串,请你根据你的情况自定义。
let url = window.location.origin + "/cgi-bin/qcmap_auth";
// 新建一个请求。
var xhr = new XMLHttpRequest();
// 参数1:请求方式,参数2:请求地址,参数3:false代表同步,true代表异步,一定要写false同步
xhr.open("post", url, false);
// 设置请求头
xhr.setRequestHeader(
"Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8"
);
// 请求发送的数据,数据太多可以放在变量中。请你根据你的情况自定义
xhr.send("id=111&type=close");
}
}
},
12.axios和ajax的区别,axios怎么发同步请求
ajax
ajax基于XMLHttpRequest。
axios
- axios是基于Promise的HTTP客户端,用于浏览器和node.js,内部判断环境是前端还是后台,选择用XMLHttpRequest还是Http对象。它提供了一个简洁的 API 来发送 HTTP 请求,并支持拦截请求和响应、转换请求和响应数据、取消请求、自动转换 JSON 数据等功能。
- axios有个拦截器叫intercepters,它有2对象分别是request和response,俩对象都有.use方法,每次调用都向callback里push{res1,rej1,res2,rej2}。
- 所有的回调都要储存起来吧,那么就有一个chain,用来存储所有回调的数组,它是给Promise用的,有2个初始值为dispatchRequest和undefined,再继续存储所有回调,存储顺序是什么样呢?Request的{res1,rej1,res2,rej2...}按顺序逐个unshift插入到chain最前面(注意:所以intercapters的request顺序看起来是前后颠倒了),Response的{r1,j1,r2,j2...}按顺序逐个push到chain最后面,所以chain完整列表就是{rej2, res2, rej1, res1, dispatchRequest, undefined,r1,j1,r2,j2 }
- dispatchRequest,是用来执行axios的request,dispatchRequest里有个adapter,可以判断当前是前端还是后台,如果是后台就用HTTP对象,前端就用XMLHttpRequest,调用后adapter会对返回值进行处理,就是我们看到的response响应对象。
- 那么,Promise开始用chain了,Promise.resolve(config).then(fn1, fn2)。当config里结果是fullfilled(成功),就把config里的值传给fn1执行;如果config里结果是reject(失败),就把错误结果传给fn2执行。也就是说,前面的等同于Promise.resolve(config).then(chain[0],chain[1])。chain[0]是成功回调,chain[1]是失败回调。config里配置项很多,可能是一个string或者方法等。
axios怎么发送同步请求?
axios默认发送异步请求,这是因为它基于promise。如果需要发送同步请求,可以使用async/await和者Promise.resolve来模拟同步。
async function fetchData() {
try {
const response = await axios.get('/api/data');
// 处理响应数据
console.log(response.data);
} catch (error) {
// 处理错误
console.error(error);
}
}
13.父子组件加载时的生命顺序,传值时的呢?
- 父创建,子创建,子挂载,父挂载==》
父beforeCreated--父created--父beforeMounted--子beforeCreated--子created--子beforeMounted--子mounted--父mounted。
销毁过程类似:父beforedestroyed--子beforeDestroyed--子destroyed--父destroyed
更新更过类似:父beforeUpdate--子beforeUpdate--子update--父update - 因为子mounted在前,所以,组件数据回显时,在父组件mounted里获取值,子组件的mounted是拿不到的,所以无法直接回显。按道理可以在父created里取值,但是因为请求是异步的,所以这样也不保险。项目中怎么解决呢?
- 子组件加v-if="data",这样请求到数据后再加载子组件。
- 子组件watch,监听props值。
14.nextick是什么原理
利用js的时间循环机制来实现异步执行。一个组件中多个nextTick会合并处理,协调宏任务和微任务放到合适的地方。Vue数据修改后并非马上立刻修改DOM,而是经过策略计算后修改,所以要在nextTick里执行。
15.keep-alive是做什么的,原理呢?
- keep-alive实现了组件的缓存,当组件切换时不会销毁,常用2属性:include缓存&exclude不缓存,max。相关的2个生命周期:activated,deactivated. 多层菜单下的孙子菜单怎么缓存?
- 原理:
keep-alive是一个组件,有3个常用属性值:include,exclude,max。在created中创建缓存列表和缓存组件key的列表,销毁的时候循环销毁清空缓存和key,当mounted时会监控include和exclude,进行组件缓存。变化时会动态的add和delete。渲染的时候会取默认插槽,只缓存第一个组件,拿到组件名,判断是否在缓存中,在列表中就缓存,不在就return掉。这里的原理用到了LRU算法。缓存和key列表是对应关系,key一直不停的取,现在用的就push,最前面的就是最旧的,超出就删除最旧的。
16.webpack介绍一下
1. 是什么
是一个打包、模块化js的工具。在webpack里一切文件都是模块,通过loader转换文件,plugin注入钩子,最后输出由多个模块合成的文件。像是模块打包机,它做的事:分析我的项目结构,找到js模块,以及其他浏览器无法直接运行的拓展语言(ts,Scss),把这些文件转换成合适的格式,打包起来供浏览器使用。
2. 构建流程,从读取配置到输出文件?
- 串行,依次执行以下过程。
- 初始化参数:从配置文件到shell语句,读取合并参数,得出最终参数。
- 开始编译:用最终参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法,开始执行编译。
- 确定入口:根据配置中的entry找到所有的入口文件。
- 编译模块:从入口文件触发,调用所有配置的loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤,直到所有入口依赖的文件都经过了这步的处理。
- 完成模块编译:在上一步loader翻译完所有模块后,得到了每个模块被翻译后的最终内容,以及她们之间的依赖关系。
- 输出资源:根据入口和模块之间的依赖关系,组成一个个包含多个模块的Chunk,再把每个Chunk转换成一个单独文件加入到输出列表中,这步是可以修改输出内容的最后机会。
- 输出完成:确定输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统,在以上过程中,webpack会在特定时间点广播特定事件,插件在监听到感兴趣的事件后会执行特定逻辑,并且插件可以调用webpack提供的API改变webpack的运行结果。
3. webpack中有很多常用loader加载器,用来处理不同类型的文件,将其处理成webpack可理解和打包的模块。
1.样式loader
- css-loader: 解析css文件,使其插入到js模块中
- Sass-loader:转换成css文件
- less-loader:同上
- style-loader:使样式插入到DOM中,适用于内联样式
2.图片loader
file和url loader同样可以处理字体文件
- svg-loader:把svg文件转换成js模块
- file-loader:把图片打包到指定目录,并返回图片url路径
- url-loader:类似file-loader,且可以对图片压缩和转换。
3.其他loader
- babel-loader:把ES6+的js语法转换成向后兼容的ES5的语法,以便在旧版本浏览器上执行。
- vue-loader:把vue组价转换成js
- ts-loader:把ts转成js
17.一键换肤怎么实现
除了css还怎么实现
18.有什么封装的组件?
19.项目中的技术难点?
20.vue的data为什么必须是function
原因主要与组件的复用性和独立性有关。
在 Vue.js 中,每个组件都是可复用的。当你创建一个 Vue 实例或组件时,data 对象用于存储组件的响应式状态。如果这个 data 是一个对象,那么它在多个组件实例之间将是共享的,因为 JavaScript 中的对象是通过引用传递的。这意味着,如果你直接在组件的 data 属性中定义一个对象,那么所有的组件实例将共享这个对象的同一个引用。
然而,通过使 data 成为一个函数,每个组件实例都可以调用这个函数并返回一个新的对象实例。这样,每个组件实例都会拥有自己独立的 data 对象,它们之间不会相互干扰。这确保了组件的独立性和状态隔离。
21.vuex有哪些属性,怎么同步和异步修改数据
- 属性有:
- state
- getters返回计算好的值
- mutation同步修改state
- actions异步,(要commit调用mutation)
- modules模块化vuex
- 同步修改数据:
state的数据只能通过mutation来修改,而且mutation是同步修改的方法,所以不能执行异步。 - 异步修改数据
actions可以执行异步操作,比如延时或者axios异步请求,但是actions不能修改state,所以它异步请求后得通过调用commit(mutationsName)来修改state数据。
那么,在vuex文件外部,也就是vue组件中该怎么异步修改呢?vuex提供了this.$store.dispatch('incrementAsync');
22.全局路由守卫的before通常会做什么事?
在 Vue 项目中,全局路由守卫的 beforeEach 通常用于执行一些在进入路由之前必须完成的逻辑。这些逻辑可能包括但不限于:
- 登录验证:检查用户是否已经登录,如果没有登录,则重定向到登录页面。这是最常见的全局路由守卫使用场景之一。
- 权限验证:验证用户是否有权限访问某个路由。这通常涉及到检查用户的角色或权限列表,并决定是否允许其访问该路由。
- 获取数据:在进入路由之前,可能需要从服务器获取一些数据。这可以是用户数据、配置数据或其他任何需要的数据。
- 设置全局变量或状态:根据路由的变化,可能需要设置或更新一些全局变量或状态。
- 错误处理:在路由切换过程中,如果发生错误,可以在全局路由守卫中进行捕获和处理。
- 标题或面包屑更新:根据当前路由的信息,更新页面的标题或面包屑导航。
- 滚动位置管理:控制页面在路由切换时的滚动位置,例如,每次进入新页面时滚动到顶部。
23.怎么动态添加和修改路由
- 动态添加:router.addRoutes([arr])
- 修改:$router.options.routes是数组,直接改数组,但是不推荐,可能导致不匹配等问题。
二 23.10.17外包到理想汽车,共2面,一面:
1. css设置100%,是相对什么?
是相对父元素的,浮动后也是相对自身的;如果有sablute定位就是相对第一个定位父级;fixed定位是相对窗口;margin是相对自身。
2. css实现一个容器,高度超出视窗就固定高度满屏,不超出视窗则500px固定高度
3. js数据类型
- 基本数据类型:number、string、undefined、null、boolean、symbol
- 引用数据类型:Object[array、object、function、dateRegExp]
- “undefined”X“not defined” undefined表示变量未赋值、对象的属性不存在,是js数据类型之一,合理存在。 not defined表示变量未声明就被使用了,属于报错信息。
4. 判断类型的方法有哪些?
- typeof,直接返回基础类型 可区分 null之外的原始类型,例:typeof null //object
- instanceof,返回布尔值 不能判断基础类型,(结果不可靠,因为symbol可以直接修改Symbol.hasInstance覆盖默认性能为)。例:
var num = new Number()
num innstanceof Number // true
- Object.prototype.toString.call()
- Array.isArray()判断是否数组
5. 实现图片懒加载的方法和原理
- 原理:src属性是获取图片的,给一个统一的替代图片地址或者设置src_代替src属性。在图片进入视图时,赋值正确的src去请求图片。
- 实现关键在于判断元素位置,确定其是否出现在视口,有3种方式:
- 滚动监听+scrollTop+offsetTop+innerHeight
- 滚动监听+getBoundingClientRect()
- intersetionObserve()
//object.getBoundingClientRect方法返回元素相对于视口的位置
getBoundingClientRect(ele).top >= 0 &&
getBoundingClientRect(ele).top <= offsetHeight
//intersetionObserve()非常好用
var io = new IntersectionObserver(callback, option);
// 开始观察 ,可观察多个
io.observe(document.getElementById('example'));
io.observe(el2)
// 停止观察 io.unobserve(element);
// 关闭观察器 io.disconnect();
6. svg和canvas的区别
都是H5支持的2种可视化技术,都可以在画布上绘制和放入图片。
- canvas是h5标签,可用number设置标签的宽高,用js的getContext('2d')作为画笔进行绘制。
- svg可以缩放矢量图,做标签用时stroke可修改颜色。
| canvas | SVG | |
|---|---|---|
| 绘制格式 | getContext绘制依赖分辨率,能以.png和.jpg保存为图片,可以说是位图 | h5中直接绘制矢量图 |
| 事件处理器 | 不支持,图像是canvas的一部分,不能用js获取图形 | 支持 |
| 工作机制围 | 逐像素渲染,绘制完就结束 | svg通过DOM操作显示 |
| 适用范围 | 有许多对象要被频繁重绘的图形密集型游戏 | 有大型渲染区域的,如地图 |
7. Vue2和Vue3的区别
8. 数据双向绑定的原理
9. SSR
10. next-tick
11. 2个数组,对比后返回去重数组
let arr1 = [
{
key:1,
value: a
},
{
key:2,
value: b
}
]
let arr2 = [
{
key:3,
value: c
},
{
key:2,
value: b
}
]
12. diff算法
三 23.10.18外包到理想汽车,共2面,二面:
1. HTML标签语义化的理解,并举例
2. css盒模型
3. 伪类、伪元素举例
4. 媒体查询
5. flex布局常用属性?
6. grid布局
7. 重绘和回流的理解,什么时候触发
8. elementUI现存bug,开发时遇到的bug?
9.Vue3的理解,使用
10. ts的理解,使用
11. css预处理用的什么,有什么高级用法
12. es6的方法举例
13. Vue.$set用法,为什么可以修改视图
14. new Set方法用过吗
15. 迭代器edit
16. 数组常用方法,20多个列举
17. webpack和vite的区别,为什么bite快
18. 微前端实现原理
19. axios封装做什么了
20. 跨域怎么实现的,还有什么方法
21. 本地存储方法列举。
四 23.10.19外包到国企中科科界,一面
1. 项目权限控制怎么做的
2. 按钮的权限怎么做的
3. Vue组件传值方法列举
4. 父怎么监听子的生命周期
5. v-if和v-for为什么不能同时用
6. axios封装做了什么
7. Vue 修饰符有哪些
8. Vue过滤器理解和使用
9. 跨域实现方式?CORS怎么实现的
10. rem适配,比例怎么计算的
11. scss预处理的高级用法?
12. 页面首次渲染,什么情况会回流
13. 原生js实现一个class有哪些方式?
14. 计时器在切除页面时怎么处理时间偏差?
五 联通base雄安,23.11.29
1. 怎么判断array和json
2. call、apply、bind的区别
3. =>箭头函数的this指针介绍一下
4. map X forEach
5. for in X of
object: key in;
array: value of
6. 数组去重方法列举
- set,Array.from(new Set(arr1))
- 结合拓展运算符,[...new Set(arr1)]
- filter过滤,结合indexof(el,0) == i,重复的话index不相等
- map.has+循环:1.new Map, arr, str;2.typeof == object 时 toString;map.has(str)
- es5常见的for双层循环,结合findIndex
- sort排序后,对比i+1和前一个值是否相等
- 把值挨个写入obj,作为属性,不能重复,结合toString
- obj.hasOwnproperty(),类似上一个obj的属性,这个属性值=type+key,查询是否包含这个属性值
- includes,类似indexof,查询是否包含
- 函数递归,先排序,然后判断index == indnex-1,递归调用fn(index-1);fn(len-1)
- for循环+Map.has,new Map,循环后,has=false则map.set(el,1)
- 数组的reduce,起循环的作用
7. 虚拟列表怎么实现的
8. 文本超出有什么处理方式
// 单行超出...
.text1{
text-over: ellipsis;
overflow: hidden;
white-space: nowrap;
}
//多行超出
.text2{
display: -webkit-box;
-weblit-line-clamp: 3;
-webkit-box-origin: verticle;
overflow: hidden;
}
// 格子内滚动
.text3{
whitspace: nowrap;
overflow: hidden;
animation: textqueue 5s linear infinite;
}
@keyframes textqueue{
100% {
transform: translateX(-100%);
}
}
9. webpack打包,移除console、注释等内容,用什么?
uglifyjs
10. cookie默认过期时间是什么
不设置时间就是临时cookie,浏览器关闭就删除。
11. git reverse?cherry-pick
回滚,并新增一条commit。reset连commit也回滚回去了。
cherry pick命令是挑选一个合适的commit移植过来,cherry pick [commit-id]
12. package.lock.json是做什么
锁定版本号,大家install时的版本号是一样的。
13. js值传递是怎么理解的
传递的并不是值,简单类型是值的副本,复杂类型是引用传递。
14. node_module里的.bin文件是做什么的
node_module里有不可见文件夹.bin,是二进制binary的缩写,里边放可执行的二进制文件。.bin下有两个同名脚本文件,一个适用unix系统,一个适用Windows系统,作用是用node执行一个js文件。
我们在npm或yarn安装一个包时,如果包内有.bin文件,会在node_module的.bin文件里生成一个指向它的文件。