【面试题】2024-04,05面试集合,搞钱要紧 【抓紧面试】,腾讯前端面试题

47 阅读39分钟

// em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

// rem是CSS3新增的一个相对单位(root em,根em), // 这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。 // 除了IE8及更早版本外,所有浏览器均已支持rem.

// rpx 是微信小程序解决自适应屏幕尺寸的尺寸单位。微信小程序规定屏幕的宽度为750rpx. // 无论是在iPhone6上面还是其他机型上面都是750rpx的屏幕宽度,拿iPhone6来讲,屏幕宽度为375px,把它分为750rpx后, 1rpx = 0.5px。

// 微信小程序同时也支持rem尺寸单位, rem 规定屏幕的宽度为20rem, 所以 1rem = (750/20)rpx = 37.5 rpx


### [广州 0月租卡是什么?0月租能注册各大平台账号吗?]( )


### 2. javascript相关


* 1.js的数据类型:


	+ 基本数据类型:string,number,布尔值,null(空),undefined(未定义),symobol,BigInt(是指安全存储、操作大整数)
		- ES6 中新增了一种 **Symbol** 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记。
	+ 引用数据类型(对象类型):object(对象是个大类:包含数组,函数,正则,日期对象等)
		- NaN是一个特殊的number,与其他所有值都不相等,包括它自身。
		- 基本数据类型由于占据的空间大小固定且较小,会被存储在**栈**中。
		- 引用数据类型存储在**堆**当中,变量访问的其实是一个指针,`指向存储对象的内存地址`
* 2.箭头函数和普通函数的区别?


	+ 箭头函数:箭头函数不会创建自己的this,没有自己的this,`只会从自己的作用域链的上一层继承this。`.
	
	
		- 会捕获自己在**定义时**所处的**外层执行环境的`this`**,并继承这个`this`值。
		- 箭头函数中`this`的指向在它被定义的时候就已经确定了,之后永远不会改变。**箭头函数继承而来的this指向永远不变**
		- 箭头函数中的`this`**永远指向**它`定义时`所处的全局执行环境中的`this`,即便这个函数是作为对象`obj`的方法调用,它的`this`依旧指向`Window`对象。
		- **箭头函数不能作为构造函数使用**否则用`new`调用时会报错!
		- **箭头函数没有自己的arguments**
		- **箭头函数没有原型prototype**
	+ 普通函数:作为对象的方法调用时,`this`指向它所属的对象。
	+ **.call()/.apply()/.bind()无法改变箭头函数中this的指向**
	
	
		- 这三个函数用来动态修改函数执行时`this`的指向,但由于箭头函数的`this`定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数`this`的指向,虽然这么做代码不会报错。
	+ 构造函数的new都做了些什么?简单来说,分为四步:
	
	
		- ① JS内部首先会先生成一个对象;
		- ② 再把函数中的this指向该对象;
		- ③ 然后执行构造函数中的语句;
		- ④ 最终返回该对象实例。
* 3.this指向问题:


	+ 1.在全局作用域中
	+ 在普通函数中:this取决于谁调用,谁调用我,this就指向谁,跟如何定义无关。
	+ 箭头函数没有自己的this,箭头函数的this就是上下文中定义的this。
	+ 事件绑定函数中的thisthis -> 事件源。
	+ 定时器中的this,因为定时器中采用回调函数作为处理函数,而回调函数的this->window。
	+ 构造函数中的this,构造函数配合new使用, 而new关键字会将构造函数中的this指向实例化对象。
* ### 4.谈谈原型和原型链:
* ### 5.什么是闭包?谈谈理解
* ### 6.js数组的方法:常用的哪些?
* 6.0数组的常用方法:



// 1.#### 原数组不改变的 join():数组转字符串。 //将数组用 - 符号连接起来 let arr = [1,2,3,4,5]; let str = arr.join('-'); console.log(str)//str = 1-2-3-4-5;

split()字符传数组 // 过指定的分隔符,将[字符串分割成数组]。 let str = wqz-ttj; let arr = str.split('-'); console.log(arr);// arr=['wqz','ttj'];

数组的拼接与截取(原数组不受影响)

concat()把两个数组里的元素拼接成一个新的数组。 返回值: 返回拼接后的新数组 let arr1 = [1,2,3]; let arr2 = [4,5,6]; let arr = arr1.concat(arr2);//arr = [1,2,3,4,5,6]; arr1.push(arr2);//arr1 = [1,2,3,[4,5,6]];

slice()截取 - 传两个参数.arr.slice(start,end) ;从start下标开始截取,一直到end结束,不包括end。 let arr = [0,1,2,3,4,5,6,7]; let newArr = arr.slice(0,3)//newArr = [0,1,2];

-传一个参数.arr.slice(start) ;从start下标开始截取,一直到最后。
let arr = [0,1,2,3,4,5,6,7];
let newArr = arr.slice(2)//newArr = [234567];

-不传参数.arr.slice( ) ;全部截取
let arr = [0,1,2,3,4,5,6,7];
let newArr = arr.slice()//newArr = [0,1,2,3,4,5,6,7];


// 2.#### 原数组改变的 push()数组的最后面,添加一个或者多个元素。 结构: arr.push(值)
返回值:返回的是添加元素后数组的长度.

pop()删除数组最后一个元素。 结构: arr.pop()
返回值:返回的是刚才删除的元素.

unshift()在数组的最前面添加一个或者是多个元素。 结构: arr.unshift(值)
返回值: 返回的是添加元素后数组的长度

shift()删除数组最前面的一个元素。 结构: arr.shift()
返回值: 返回的是刚才删除的元素.

splice()两个参数是删除/三个是替换。

结构1: arr.splice(start,deletedCount) 纯删除
从start下标开始,删除几个

结构2: arr.splice(start,deletedCount,item) 替换
从start下标开始,删除几个,并在该位置添加item

结构3: arr.splice(start,0,item) 纯添加
从start下标开始,删除0个,并在该位置添加item,start开始全部往后移动



// ### 数组的翻转和排序(改变数组) reverse() 翻转数组 结构:arr.reserse()

sort()排序 let arr = [1,3,5,2,4,23,122,34]; //没有参数:时按照首字符的先后排序 arr.sort()//arr=[1,122,2,23,3,34,4,5]; //有参数 arr.sort(function(a,b){ return a-b;//从小到大排序 return b-a;//从大到小排序 })

filter()过滤,有返回值, 过滤出符合条件的元素。 let arr = [1, 3, 5, 2, 4, 6]; let res3 = arr.filter(function(item, index) { return item % 2 === 0; }); console.log(res3);


find()查找符合条件的项,并且返回第一项。 findIndex()查找符合条件的下标,并且返回第一项。

lastIndexOf()查找元素最后一次在数组中出现的位置。

indexOf()查找符合条件的元素,找到就返回该元素,找不到就返回-1. includes()判断一个数组中是否包含某一个元素,并返回true 或者false。

some()判断数组中有没有符合条件的项,有就返回true,一个都没有惨返回false。 every()判断数组中的所有项是否的满足条件,全部满足才返回true,否则false。 reduce() - 1.求和计算 -2.扁平化数组,拼接数组 - 计算数组中每个元素出现的次数。


* 7.js字符串的方法?
* 8.防抖和节流
* **节流:限制执行频率,有节奏的执行**
* **防抖:限制执行次数,多次密集触发只执行一次**


	+ 防抖(Debounce):指在一段时间内触发的多次事件只执行最后一次,以防止事件重复执行。
		- 例如,在输入框中连续输入时,前几次的输入并不需要实时处理,而只需要等在一定时间内不再输入时再执行一次即可。防抖的实现方式是使用  setTimeout  或者  setTimeOut  和  clearTimeout,通过一定的延迟等待实现选择最后一次执行。
	+ 节流:指在指定时间间隔内只执行一次事件,以防止高频率重复执行。
		- 例如,在用户频繁触发页面滚动事件时,需要等待一定时间后才执行一次函数,以减少执行次数。节流的实现方式有两种:时间戳和定时器方式。
* 1.深浅拷贝,理解,常用的有哪些,会有什么问题?


	+ 浅拷贝:
	+ object.assion()合并对象
	+ 扩展运算符,
	+ slice(0)截取 返回值:返回截取出来的字段,放到新的数组中,不改变原数组。
* 2.浏览器从输入url到页面显示发生了什么事情?
* 重绘回流?日常中的场景?
* webpack了解吗?怎么做优化?大概说一下
* 模块化开发和组件开发


	+ 都可以将大型复杂的系统分解成更小、更简单的可重用部件,从而提高开发效率和维护性。
	+ 个模块通常是指一组相关联的功能或资源,可以独立地进行开发和测试。模块化开发的一个典型案例是Node.js,它将应用程序拆分成多个模块,每个模块都有自己的作用域和依赖关系。这使得开发者可以更加轻松地管理代码库,减少了代码耦合度,并且可以更容易地测试和维护各个模块。
	+ 组件开发是指将页面或应用程序拆分成多个可重用的组件,每个组件都具有明确定义的接口和功能。组件化开发的一个典型案例是React.js,它可以将UI界面拆分成多个组件,并将它们组合在一起来构建复杂的应用程序。这使得开发人员可以更加轻松地管理UI界面,增强了代码的可重用性,并且可以更容易地实现前端功能和交互。
	+ + 总之,模块化和组件化开发都是现代软件开发中不可或缺的技术,它们能够帮助开发人员更高效地开发和维护软件,减少了代码的复杂性和耦合度。
* http和https的区别?常见状态码


	+ HTTP和HTTPS都是常用的协议,用于客户端(如浏览器)与服务器之间的通信。HTTP代表“超文本传输协议”,而HTTPS代表“安全的超文本传输协议”。
	+ `HTTP是一种无状态协议,使用明文传输数据。`
	+ `HTTPS通常用于传输敏感信息,加密通信。例如登录凭据、信用卡号码等.`



HTTP是一种无状态协议,它使用明文传输数据。 这意味着HTTP请求和响应中的所有内容都以纯文本形式进行传输,因此可能会被攻击者窃听和篡改。HTTP通常用于传输非敏感信息,例如公共网站上的静态页面。

HTTPS通常用于传输敏感信息,加密通信。例如登录凭据、信用卡号码等。 HTTPS则提供了更高的安全性,它通过使用SSL或TLS加密机制来保护传输的数据,从而实现加密通信。 HTTPS可以保护数据在传输过程中不被黑客窃取或篡改,并且还能验证服务器的身份。

以下是一些关于HTTP和HTTPS的常见面试问题:

  1. HTTP和HTTPS有什么区别? 答:HTTP是一个无状态协议,数据以明文形式传输,而HTTPS使用SSL/TLS加密机制将数据加密并保护其完整性和机密性。
  2. HTTPS是如何保证数据的安全性的? 答:HTTPS使用SSL/TLS协议来加密数据,同时还使用公钥和私钥来验证服务器的身份,并确保数据在传输过程中不被篡改。
  3. HTTPS比HTTP更安全,但它是否完全无懈可击? 答:虽然HTTPS可以大大提高安全性,但攻击者仍可能通过某些方式攻击HTTPS连接。例如,攻击者可能会使用伪造的数字证书来欺骗用户,或使用中间人攻击窃听和篡改HTTPS通信。
  4. HTTP/2是什么?它如何改进HTTP协议? 答:HTTP/2是一种新的HTTP协议版本,旨在提供更快的加载速度,减少延迟和增加安全性。它引入了多路复用、头部压缩和服务器推送等新功能,并支持加密通信。

HTTP是一种用于在网络上传输超文本和其他资源的应用层协议。它基于客户端-服务端架构,通过请求-响应模式进行通信。

HTTP协议定义了以下常见的请求方法:

  1. GET:获取一份资源,不会对服务器上的资源产生任何影响。
  2. POST:向服务器提交数据,可能导致服务器上的资源状态发生变化。
  3. PUT:将数据存储到服务器上指定的位置。
  4. DELETE:删除服务器上指定的资源。

HTTP协议还定义了许多状态码,用于表示服务器处理请求时的结果。以下是常见的状态码及其含义:

  1. 200 OK:服务器成功处理了请求,并返回了所请求的数据。
  2. 201 Created:请求已经被实现,而且有一个新的资源已经依据请求的需要而建立。
  3. 204 No Content:服务器成功处理了请求,但没有返回任何内容。
  4. 400 Bad Request:服务器无法理解请求的格式,客户端应该检查请求是否正确。
  5. 401 Unauthorized:请求未授权,客户端应该提供身份验证信息。
  6. 403 Forbidden:服务器拒绝执行请求,客户端没有访问权限。
  7. 404 Not Found:服务器无法找到请求的资源,路径问题。
  8. 500 Internal Server Error:服务器遇到了意外的情况,无法完成请求


4-1.说说JS中的数据类型
4-2.JS中的 ==和===有什么区别?
4-3.JS中的深拷贝和浅拷贝**有什么区别?
4-4.如果让你实现一个深拷贝,有什么思路?
4-5.简述一下对原型,构造函数以及实例的理解
4-6.什么是闭包?闭包解决了什么问题?闭包会导致什么问题呢?
4-7.如何理解JS中的this关键词?
4-8.之前有没有解决过跨域问题?在你们项目里。当时是怎么解决的?


#### 浏览器缓存原理


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4100409419164cf19bd93fa4885a153b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=x%2BGhPwXIjqY4nqQOvBVmbdPnE3s%3D)


 // 理解:  // 协商缓存 


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/62ecb8ce398c4e28b1234bde34827038~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=Cab8xqRLB2yAoM8lDZ4S%2FkrY67o%3D)


### 3. vue2相关


说说对vue的理解?



vue是一套用于构建用户界面的渐进式框架,与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层(viewmodel),不仅易于上手,还便于与第三方库或既有项目整合。


* 1.v2的生命周期,并且可以做什么事情?
* 2.路由 如何监听hash变化?


	+ 1.hash路由:监听 url 中 hash 的变化,然后渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;
	+ 2.history路由:1. 监听 url 中的路径变化,需要客户端和服务端共同的支持;
	+ 利用H5的 history中新增的两个API pushState() 和 replaceState() 和一个事件onpopstate监听URL变化history模式。
	+ hash 就是指 url 尾巴后的 # 号以及后面的字符,history没有底带#,外观上比hash 模好看些hash回车刷新会加载到地址栏对应的页面,history一般就是404掉了。hash 能兼容到IE8, history 只能兼容到 IE10;
* hash 模式的优缺点:


	+ 优点:浏览器兼容性较好,连 IE8 都支持
	+ 缺点:路径在井号 # 的后面,比较丑
* 总结一下 history 模式的优缺点:


	+ 优点:路径比较正规,没有井号 #
	+ 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了
	+ history API 是 H5 提供的新特性,**允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求**	
	 ![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2e70a08ea5a34be89352cd355b7a8d57~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=6MrYG%2B1uXEpi6Io1%2BN747a93chA%3D)
	+ **history 路由**
	
	
		- 在 history 路由中,我们一定会使用`window.history`中的方法,常见的操作有:
	+ back():后退到上一个路由;
	+ forward():前进到下一个路由,如果有的话;
	+ go(number):进入到任意一个路由,正数为前进,负数为后退;
	+ pushState(obj, title, url):前进到指定的 URL,不刷新页面;
	+ replaceState(obj, title, url):用 url 替换当前的路由,不刷新页面;
* 注意:调用这几种方式时,都会只是修改了当前页面的 URL,页面的内容没有任何的变化。
* 3.路由传参数


	+ query
	+ params  ![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/dea49ccf9acc441686e7b355705189be~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=r%2FuuJjsJ5fjNL%2BhjUfKiqo3gCnQ%3D)
* 4.# vue中route和router有什么区别?


	+ route
		- 通过 this.$route 访问的是当前路由,获取和当前路由有关的信息。只读属性。
	+ this.$ router是 router 实例
		- 通过 this.������访问路由器,相当于获取了整个路由文件,在router访问路由器,相当于获取了整个路由文件,在router.option.routes中,或查看到当前项目的整个路由结构 具有实例方法。如:this.$router.query.id
* 5.vue2组件通信:


	+ 常见可以分为三类:
		- 父子通信
			* 父传子:父组件先引用子组件,并且绑定需要传的数据(如:),子组件用 `props:{ list:{type:Array, default:null}}接收使用`			* 子传父:子组件自定义事件,并且调用这个事件函数,this.$emit('事件函数名称',this.要传的数据)。在父组件中(引用子组件的时候要绑定,如:<child @add=“add” />)监听这个事件函数,vlaue值就是子组件给父组件的值。



// 父组件给子组件传值用:props ·在父组件中定义要传给子组件,调用子组件并且把 要传的值绑定在子组件上 ·在子组件中用props:{ list:{ type:Array,default:null }}接收,使用

// 子组件给父组件传值用:emit // 在子组件中自定义一个事件 <div @click="add"> < /div> methods:{ add(){ this.emit('方法名',this.要传的值) } } // 在父组件中监听子组件的这个方法 ·<child @add="add"/> methods:{ add(value){ console.log(value) // 子组件给父组件的值 } }


* 兄弟组件通信
* 跨级组件通信



3-4.vue.js中组件之间是如何通信的?

  • 父子组件 》父传子:用props接受,子传父:子组件触发事件函数this.$emit(‘key’,要传的数据)来传递。
  • 兄弟组件 》用eventbus来传,vuex
    • 1.创建一个eventbus.js文件
    • 2.传数据的组件用eventbus.$emit()
    • 3.接受数据的组件用eventbus.$on()
  • 祖孙组件(跨多极组件)vuex或者是依赖注入的方式
    • 祖先组件中使用:provide(‘唯一的key’,要传递的值)
    • 子孙组件中:inject(‘key’)接收。

#### map和foreach的区别:



foreach(){} arr.forEach(function(item,index,arr){ //里面的function是一个回调函数, //item: 数组中的每一项; //index:item 对应的下标索引值 //arr: 就是调用该方法的数组本身 })

该方法等同于for循环,没有返回值.

map(){} //里面的function是一个回调函数,
//item: 数组中的每一项;
//index:item 对应的下标索引值
//arr: 就是调用该方法的数组本身 有返回值,返回一个新数组,新数组的长度和原数组长度相等. let arr = [1,32,54,6,543]; let res = arr.map(function(item,index,arr){ return item*2; })



计算数组中每个元素出现的次数 var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; var countedNames = names.reduce(function (allNames, name) { // console.log(allNames, '| ' + name); if (name in allNames) { allNames[name]++; } else { allNames[name] = 1; } return allNames; }, {}); console.log(countedNames);




---



6.vue怎么检测数组变化的?说说了解



Vue  提供了一种名为“响应式”的机制,能够检测到数组中某个元素的变化,当某个数组元素发生变化时,Vue  会立即通知相关的组件进行更新.这些方法在使用的时候,会通知  Vue  数组的变化,并即时更新视图。 例如:

  • push() 尾部添加 返回新数组的长度 -  pop() 尾部删除 返回的是被删除的元素 -  shift() 头部删除 -  unshift()头部添加 -  splice() -- 增加 删除 修改;本质上是删除数组(从哪里开始的下标,删除的长度,要替换的值)

-  sort() 排序,返回排序后的数组。 -  reverse() 反转数组

如果我们使用了其它不被重写的数组方法,Vue  无法自动检测到数组的变化,会导致界面不刷新。可以使用  Vue.set()  或者  this.$set()  方法手动触发更新。

// this.$forceUpdate() // 手动触发更新 // Vue.set(this.items, this.items.length, 'qux')

理解:vue2是可以监听数组数据的变化的,但基本都是只能监听到数组方法对于数组的变化,也就是有没有改变原数组。(简单理解为数组的长度发生了变化并修改了原数组),不可以监听到数组某一元素内容的数据变化。在这种情况下才需要使用vue提供的set方法,而如果是说v-for对数组的监听的话应该就是diff算法的对比了,我个人是这么理解的。


* 7.this.$nextTick()
	+ 在我们开发项目的时候,总会碰到一些场景:当我们使用vue操作更新dom后,需要对新的dom做一些操作时,但是这个时候,我们往往会获取不到跟新后的DOM.因为这个时候,dom还没有重新渲染,所以我们就要使用vm.$nextTick方法。



// nextTick接受一个回调函数作为参数,它的作用将回调延迟到下次DOM跟新周期之后执行。 this.$nextTick(function(){ //dom现在跟新了 //可以获取新的dom数据,执行操作 this.doSomeThing() })


综合题


* 7.为什么要选择vue.js呢,它给你们解决了什么问题?
	+ Vue.js  是一个轻量级的  MVVM  框架,相比其它框架具有以下几个优点:
	+ 易上手:Vue.js  使用模板和组件的方式,让代码更加易懂易读。
	+ 响应式数据绑定:Vue.js  提供了依赖追踪和异步队列更新机制,能够实时追踪数据变化,并及时更新视图。这带来的好处是,数据和视图之间可以更加解耦,代码可读性更高,开发效率更高。
	+ 前端路由和动画:Vue.js  自带的  Vue  Router  和  Transition  组件,可以让前端路由和动画变得更加容易,同时也提高了代码的可维护性。
	+ 组件化开发:Vue.js  是一款面向组件的框架。通过组合不同的组件,可以构建出复杂的  UI  界面。组件可以很容易地进行组合、嵌套和复用,极大地提升了代码的重用性和可维护性。
	+ 需要大量复杂数据操作、可重用组件、动态路由或动画的应用。生态圈完善,社区活跃,能够大幅提高我们构建  Web  应用的开发效率。
* 8.数据改变,视图没有改变的情况有遇到吗?是为什么?怎么处理的?



3-1.为什么要选择vue.js呢,它给你们解决了什么问题? 3-2.谈谈对vue生命周期的理解?
- 3-3.v-if 和 v-show有什么区别?
- 3-4.vue.js中组件之间是如何通信的?
- 父子组件 》父传子:用props接受,子传父:子组件触发事件函数this.emit(‘key’,要传的数据)来传递。兄弟组件》用eventbus来传,vuex1.创建一个eventbus.js文件2.传数据的组件用eventbus.emit(‘key’,要传的数据)来传递。 - 兄弟组件 》用eventbus来传,vuex - 1.创建一个eventbus.js文件 - 2.传数据的组件用eventbus.emit() - 3.接受数据的组件用eventbus.$on() - 祖孙组件(跨多极组件)vuex或者是依赖注入的方式 - 祖先组件中使用:provide(‘唯一的key’,要传递的值) - 子孙组件中:inject(‘key’)接收。

3-5.vue中数据双向绑定原理了解吗?
3-6.如果让你实现一个基本的双向数据绑定,那你是什么思路呢?
3-7.MVVM和MVC有什么区别?
3-8.有没有用过其他的JS框架?
3-9.对前端代码的自动化测试有没有了解?有没有使用过前端代码自动测试框架呢?


### 4. vue3相关



  • 在另外一个文档里面,后面整理之后补发

### 5.综合能力



1.你在项目中遇到过哪些大坑,那当时是怎么解决的?
2.在你们团队中,你有没有一些突出的亮点可以在这分享一下
3.那你提到前端工程实践,那项目中的package.json有什么作用?它里面都有哪些内容?
6.对webpack比较熟是吧,那你对webpack的使用有哪些优化建议呢?


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9885d40d499b426faa0de9afc2b7a331~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=I%2F1vSBB1nrFm7NVldMOGj7uduic%3D)


#### 5.1 **常见web性能优化的方式?AAAa**\*\*



性能优化基本是我们开发都要面对的问题,但是怎么做合适?收益怎么样?都是我们要考虑的? // 在单页面应用中,一个路由对应一个页面,如果不做处理,打包的时候会把所有的页面打包成一个文件, // 当用户打开首页的时候就会一次性加载所有的资源,造成首页加载很慢,用户体验不好。

通用的方法: 1.路由懒加载(es中的箭头函数+import的方式),组件懒加载等(需要触发的组件,如弹窗组件) 2.引入骨架屏插件(移动端),提升用户体验 3.大数据列表:使用虚拟滚动技术,加载可视化区域的内容,或滚动加载但是要注意节流的问题(单位时间内多次点击只是触发一次) 4.无需滚动加载:要注意外层盒子加上overflow:auto,一定要限定高度。 5.更多的情况下图片优化**会带来很大的性能提升。

图片优化如下:

  • 1.使用 SVG 格式。webp等格式的图片(之前打包的时候发现好几张gif图片基本都是1m以上,png500多k),

  • 2.配置image-webpack-loader,处理并压缩图片,基本可以压缩到1/4或者1/5左右。

  • 3.图片列表使用七牛云提供的图片动态裁剪的功能。按文档配置即可****移动端完全没必要加载原图压缩图片可以更快的显示。

  • 4.使用 Webpack 配合compression-webpack-plugin插件,在前端工程的打包阶段,对静态资源进行“预压缩”,从而移除服务器端的压缩时间。

  • 5.缓存图片,将图片缓存在浏览器中可以减少页面加载时间。

  • 6.CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,以及引入的一些Js、css等文件。我们使用的是七牛云来存储讲台资源,

  • 使用cdn加速相当于你的图片资源不是放到你自己的服务器,而是放到七牛云的服务器上了,只是把你的域名解析到七牛云服务器上而已。


1.路由懒加载:把路由用import的方式引入


a) **C** **onst** ******home** **= ()=>** **import** **(** **“** **@/** **views/index** **”** **)******


2.**组件懒加载** **,** **比如弹窗组件** **,** **通过条件触发的组件** **,** **触发操作之后再加载该组件** **。**\*\*\*\*


3.**移动端可以使用骨架屏** **,** **锁定白屏时间** **,** **提升用户体验** **。** **可以引入插件** **。** **V** **ue** **-** **skeletion** **-** **webpack** **-** **plugin**\*\*\*\*


4.**长列表虚拟滚动加载** **,** **只是渲染可视区域的列表** **,** **引入插件配置** **。**\*\*\*\*


a) **计算出total数据列表总高度** **,** **并且在触发滚动事件的时候根据滚动的位置不断更新开始位置start和end的位置** **,** **然后从列表数据中截取对应的元素** **。**\*\*\*\*


5.**长列表使用触底加载** **,**\*\*\*\*


a) **第一次传** **20** **条数据** **,** **或者是其他** **,** **获取当前滚动时候位置** **,** **窗口的高度** **,** **整个网页的实际高度** **。** **设置一个加载的动画** **,** **如果当前滚动的位置** **+** **窗口的高度** **+** **距离底部的高度的时候就触发动画** **,** **增加的请求的数据量** **。**\*\*\*\*


6.**将小图转成base** **64** **格式的图片** **,** **减少http请求** **。**\*\*\*\*


7.尽可能的使用字体图标,而非图片


8.**图片懒加载** **。** **引入插件**\*\*\*\*


9.**图片优化**


* 1.技能超市列表**使用七牛云提供的图片动态裁剪的功能** **,** **按文档配置即可** **。** **移动端完全没必要加载原图** **,** **压缩图片可以更快的显示** **。**
* 2.使用 SVG 格式。webp等格式的图片(打包的时候发现好几张gif图片基本都是1m以上,png500多k),
* 3.配置image-webpack-loader,处理并压缩图片,基本可以压缩到1/4或者1/5左右。
* 4.使用 Webpack 配合`compression-webpack-plugin`插件,在前端工程的打包阶段,对静态资源进行“预压缩”,从而移除服务器端的压缩时间。
* 5.缓存图片,将图片缓存在浏览器中可以减少页面加载时间。
* 6.CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,以及引入的一些Js、css等文件。我们使用的是七牛云来存储讲台资源,
	+ 相当于你的图片资源不是放到你自己的服务器,而是放到七牛云的服务器上了,只是把你的域名解析到七牛云服务器上而已。


#### 5.2 前端该如何优化网站性能?



前端该如何优化网站性能?

前端性能优化大概分为七种
1、减少请求数量
1.1 图片处理:
1-1 Base64:
将图片的内容以 Base64 格式内嵌到 HTML 中,可以减少 http 请求数量,但是编码之后的大小比图片大了

 1-2 使用字体图标来代替图片
1.2 避免使用空的 src 和 href
1.3 不使用 css@import

2、减少资源大小 2.1 html 压缩 html 代码压缩就是压缩在文本文件中有意义,但是在 html 中不显示的字符,包括空格,制表符

2.2 css 压缩 css 压缩包括无效代码删除与 css 语义合并

2.3 js 压缩与混乱 js 压缩与混乱包括无效字符及注释的删除、代码语义的缩减和优化、降低代码的可读性、实现代码的保护

2.4 图片压缩 3、优化网络连接
3-1 使用 CDN

CDN 是内容分发网络,它能够实时地根据网络流量和各个节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上,其目的是使用户可以就近的取得所需内容,解决网络拥挤的状况,提高网站的响应速度

3-2 使用 DNS 预解析

4、优化资源加载
4.1 资源加载位置
通过优化资源加载位置,更改资源加载时机,使尽可能快地展示出页面内容,尽可能快地使用功能可用
1、css 文件放在 head 中,先外链,后本页
2、js 文件放在 body 底部,先外连,后本页
3、处理页面、处理页面布局的 js 文件放在 head 中,如 babel-polyfill.js 文件、flexible.js 文件
4、body 中尽量不写 style 标签和 script 标签


#### 5.3 前端seo优化


* 参考[blog.csdn.net/ww\_5211314/…]( )



// 搜索引擎优化,也就是需要被收录的网站.meta中的,description,keywords,以及一些简单的[语义化标签]. // 总结下来大概就是首页,商品详情页,分类页面,店铺页面,搜索页面保证商品被搜索引擎收录就可以在google中搜索到自己网站的产品了。

// 第一个问题:## 如何让您的网站出现在谷歌的搜索引擎中(seo)?

// # 如何做到seo优化的?

1.网站title的描述

-1.如果是网站首页则描述该网站的内容,  
-2.如果是商品详情页面则是针对该商品的描述,  
-3.如果是分类页则是对所有分类的描述。

2.在seo中,其实meta标签是很重要的一部分。填写:content="有关网站的关键词"。

3.代码层面需要优化的事项:

1,所有的img标签要加alt属性,产品列表要加产品列表索引.
2,所有跳转到商品详情,店铺页面,分类页面,搜索页面都要是用a标签跳转,这样爬虫才能沿着链接爬取下一个链式页面.
3,所有a标签要写完整的路径:例如: <a href="https://buydo.com/item/a18f4cf96bc041d4979ddca4c2fd1d78.html"></a>
4,当在网站中输入错误的链接以及产品id,网站必须有正确的404,500页面以用来引导爬虫走完整个流程,而不是弹出错误的选项卡来告诉用户没有该商品之类的.

第四步:Last-Modified 和 If-Modified-Since非常重要

所有页面都必须设置Last-Modified 和 If-Modified-Since标头,这个对于爬虫搜索的索引和检索索引页面的速度非常重要。




---


#### 5.4 在工作中有用到webpack吗?如何配置的?大概说一下:


1. `entry:指定入口文件,可以是单个文件或多个文件。`
2. output:指定`输出`文件的路径和文件名,可以使用占位符来生成动态文件名。
3. `module:配置模块`的加载方式,可以使用不同的loader来处理不同类型的文件,例如使用babel-loader来处理ES6代码,使用css-loader和style-loader来处理CSS文件。
4. `plugins:配置插件`,可以用于优化代码、生成HTML文件、提取公共代码等。
5. resolve:配置模块的解析方式,可以指定模块的搜索路径、别名等。
6. devServer:配置开发服务器,可以实现自动刷新、热替换等功能。


在配置webpack时需要注意以下几点:


1. 版本兼容性:不同版本的webpack可能存在差异,需要根据实际情况选择合适的版本。
2. 文件路径:需要注意文件路径的正确性,避免出现文件找不到的情况。
3. loader和plugin的顺序:需要按照正确的顺序配置loader和plugin,避免出现错误。


#### 5.5 说一下浏览器事件循环机制(一定会问,会现场给题目做),node事件循环机制(可能会问)


* 理解:
	+ 在js代码执行时,会将对象存在堆(heap)中,在栈(stack)中存放一些基础类型变量和对象的指针。在执行方法时,会根据当前方法的执行上下文,来进行一个执行。对于普通函数就是正常的入栈出栈即可,涉及到异步任务的时候,js执行会将对应的任务放到事件队列中(微任务队列、宏任务队列)。
	+


我们知道js是一门单线程非阻塞的脚本语言,在执行js代码时,只有一个主线程来处理所有任务。非阻塞是指当代码需要处理异步任务时,主线程会挂起(pending),当异步任务处理完毕,主线程根据一定的规则去执行回调。事实上,当任务执行完毕,js会将这个事件加入一个队列(事件队列)。`被放入队列中的事件不会立刻执行其回调,而是当前执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务。`异步任务有两种类型,微任务和宏任务。不同类型的任务会被分配到不同的任务队列中。  
 执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务,如果存在,依次执行所有队列中的回调,只到为空。然后再去宏任务队列中取出一个事件,把对应的回调加入当前执行栈,当前执行栈中所有任务都执行完毕,检查微任务队列是否有事件。无限循环此过程,叫做事件循环。



什么是浏览器事件循环机制?

我们知道js是一门单线程非阻塞的脚本语言,意思是执行js代码时,只有一个主线程来处理所有任务。非阻塞是指当代码需要处理异步任务时,主线程会挂起(pending),当异步任务处理完毕,主线程根据一定的规则去执行回调。事实上,当任务执行完毕,js会将这个事件加入一个队列(事件队列)。被放入队列中的事件不会立刻执行其回调,而是当前执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务。
异步任务有两种类型,微任务和宏任务。不同类型的任务会被分配到不同的任务队列中。
执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务,如果存在,依次执行所有队列中的回调,只到为空。然后再去宏任务队列中取出一个事件,把对应的回调加入当前执行栈,当前执行栈中所有任务都执行完毕,检查微任务队列是否有事件。无线循环此过程,叫做事件循环。


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e8e2a08b81ac480db0755b713ee0e125~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=tBTLh61kzfNcsMPLKjYWPPrlGIc%3D)


* 微任务:queueMicrotask、PromiseMutationObserve等
* 常见宏任务:ajax、setTimeoutsetInterval、script(js整体代码)、IO操作、UI交互、postMessage等



故事件循环可以理解为是一个桥梁,连接着应用程序的js和系统调用之间的通道。其过程为:

  1. 执行一个宏任务(一般为一段script),若没有可选的宏任务,就直接处理微任务。
  2. 执行中遇到微任务,就将其添加到微任务的任务队列中。
  3. 执行中遇到宏任务,就将其提交到宏任务队列中。
  4. 执行完当前执行的宏任务后,去查询当前有无需要执行的微任务,有就执行
  5. 检查渲染,若需要渲染,浏览器执行渲染任务
  6. 渲染完毕后,Js线程会去执行下一个宏任务。。。(如此循环)

console.log("script start");

const promiseA = new Promise((resolve, reject) => { console.log("init promiseA"); resolve("promiseA"); });

const promiseB = new Promise((resolve, reject) => { console.log("init promiseB"); resolve("promiseB"); });

setTimeout(() => { console.log("setTimeout run"); promiseB.then(res => { console.log("promiseB res :>> ", res); }); console.log("setTimeout end"); }, 500);

promiseA.then(res => { console.log("promiseA res :>> ", res); });

queueMicrotask(() => { console.log("queue Microtask run"); });

console.log("script end");

// script start // init promiseA // init promiseB // script end // promiseA res :>> promiseA // queue Microtask run // setTimeout run // setTimeout end // promiseB res :>> promiseB


微任务是指由  JavaScript  引擎自身发起的任务,比如  Promise  的回调函数、MutationObserver  的回调函数。`会在当前任务完成后、下一个宏任务开始前执行。`比如,在一个宏任务中,Promise  状态从等待变为完成(fulfilled)或拒绝(rejected)时,会将对应的回调函数放入一个微任务队列中,等待当前宏任务执行完毕后立即执行。


简单来说,`当一个宏任务执行完毕后,会检查是否有微任务需要执行,如果有,就立即执行所有微任务,执行完毕后再执行下一个宏任务。`



console.log('start'); setTimeout(() => { console.log('timeout'); }, 0); Promise.resolve().then(() => { console.log('promise'); }); console.log('end'); // 运行上述代码,会先输出  "start"、"end",然后才会输出  "promise"、"timeout", // 因为  Promise  的回调函数是微任务,比  setTimeout  回调的执行优先级更高, // 会在当前宏任务执行完毕后立即执行,而  setTimeout  回调则是一个新的宏任务,需要放到任务队列中等待执行。


`new Promise((resolve, reject) => {}),构造器函数中的代码是同步执行的。`



Promise运行机制
async/await 你用过吗?怎么用的,有返回对象吗?
组件传值,父子组件兄弟组件BUSvuex运行机制,如何通过 vuex 实现登录验证?
router和route区别
路由传参,获取参数
延时路由
如何提高页面的加载性能
跨域解决方式(jsonp,cros)你配置过没有
created 生命周期不可以干什么事情

作用域链
vue 实例化
computed 和 watch 的区别?什么时候使用 computed 什么时候使用 watch
vuex 怎么模块化
了解 vue3.0 吗?
数据拦截是发生在哪个生命周期的?什么情况下不会对属性数据拦截,要怎么解决?
对 Es6 掌握的怎么样,项目中用过 promise 吗?



1. 为什么选择前端?
2. 讲讲浏览器从输入网址到打开网页的整个过程,越细致越好。
3. 说一说你理解的JS 事件循环机制
4. es6都有哪些新内容?
5. 你提到了map,讲讲和object有什么区别?
6. 箭头函数和普通函数的区别?
7. 跨域,相关的几个请求头的含义。
8. 一个盒子从中间开始,碰到最左边的边界往右移动,碰到最右边的边界往左移动,如此循环,问怎么做?
9. 你提到了requestAnimationFrame,讲讲和setInterval的区别?
10. 用过canvas吗,如果要实现一个一笔一画写汉字的效果,应该怎么做?


### 5.6. 闭包三连,部分面试题


#### 闭包


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7b825e8d05434ea1af986a555216afdd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=YgJA0yYFI8hHWeQNCT0xgTAm2MY%3D)



5.6. 闭包三连?、为什么会出现闭包?闭包有什么作用?

- **闭包就是一个能够访问其他函数**是将函数内部和函数外部连接起来的一座桥梁**。
- **创建闭包最常见方式,就是在一个函数内部创建另一个函数**内部变量的函数。**
  • 1.为什么会出现闭包?
    • 函数的作用域及其所有变量都会在函数执行结束后被销毁。 但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止
  • 2.闭包的缺点 闭包长期占用内存,内存消耗很大,可能导致内存泄露
  • 3.闭包的作用:**** 1.访问其他函数内部变量**** 2.保护变量不被内存回收机制回收**** 3.避免全局变量被污染 方便调用上下文的局部变量 加强封装性

-4.如何避免闭包引起内存泄漏?****** 1,在退出函数之前,将不使用的局部变量全部删除。可以使变量赋值为null;**** 2,避免变量的循环赋值和引用。**** 利用Jquery释放自身指定的所有事件处理程序


2.说一下让一个盒子垂直水平居中都有啥方法 3.原型链是啥 4.promise 用过吧,可以说一下吗 5.Es6 有接触过吧,怎么去重呢 6.v-if 和 v-show 的区别是啥 7.数据双向绑定你是怎么理解的, 8.可以介绍一下自己的项目中参与的模块吗?

9.说一下深浅拷贝,

基本类型(保存在栈内存中)

引用类型(保存在堆内存中,引用数据类型的变量是一个指向堆内存中中实际对象的引用,存在栈中)

  • 浅拷贝:
    • 将对象p1赋值给p2,改变p2里面属性的值,p1里面对应的值也会被改变。
    • 因为赋值的时候,是直接拷贝对象栈里面的地址,p1和p2的地址相同,所以修改会将两个一起改变。 将一个对象的所有属性拷贝到另一个对象,一个对象属性改变,另外一个也会改变。 浅拷贝: 只能拷贝一层对象,或者一层数组。 浅拷贝的问题: 当原始对象里面的属性值是复杂数据类型的时候,
    • 1.扩展运算符
    • 2.Object.assign()合并对象。
    //注意:slice() concat()一维数组时候深拷贝,多维数组时候浅拷贝。都会返回新的数组。
    • 3.slice截取
    • 4.concat合并数组
  • 深拷贝:
    • **深拷贝开辟一个新的栈,两个对象属性完成相同,但是对应两个不同的地址。
    • 修改一个对象的属性,不会改变另一个对象的属性**。
      • 1.用for-in对象的属性进行遍历,递归实现。

      • 2.JSON.parse(JSON.stringify())。会忽略undefined、symbol和函数。

      • 3.通过嵌套扩展运算符实现深复制


10.数组去重 - 1.利用Array.from(new Set(arr))去重Set中的元素是唯一的。 - const res1 = Array.from(new Set(arr)); -2.利用includes+forEach去重用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。 -3.利用双层for循环去重 - 4.**利用Array.filter和map对象数组去重 (性能较高) -5.# 利用数组的[indexOf方法],思路:新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入。


### 6.无感登录


![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/520e8ae183764f798922bc9c2082b923~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=VCc4Wmp6vb8Cum%2BmDs4Uih1kh7g%3D)


#### 6.1说一下前端token的理解



前端token是一种用于身份验证和授权的令牌。 通常是通过用户使用用户名和密码进行登录后返回的。一旦用户被验证,服务器会生成一个token并将其发送回前端应用程序。 该token通常是一个长字符串,包含有关用户和他们的权限的信息。

前端应用程序通常将token存储在浏览器的本地存储或cookie中,以便在用户进行其他操作时进行验证和授权。 当用户进行受保护的操作时,前端应用程序会将token发送回服务器以进行验证和授权。

使用前端token可以提高应用程序的安全性和用户体验,因为它可以减少对服务器的请求次数并允许前端应用程序在没有网络连接的情况下继续访问受保护的资源。 此外,通过使用token,服务器可以轻松地管理用户和他们的权限,而无需在每个请求中重新验证用户身份。

token认证的流程: ** // 用户第一次登录服务端,服务器根据用户的私有信息,时间戳,签名算法,私钥 通过算法生成token并返回给客户端, // 之后客户端请求只需要带上这个token即可,服务端只需对这个token进行解析,即可得知那个用户进行了操作。**


#### 6.2权限



菜单权限,按钮权限,接口权限,数据权限四种

  • 所谓数据权限,就是根据不同角色的登录用户,查看不同的列表数据。
  • 若依的数据权限也是基于角色实现的。不同角色不同权限。

-1.### 菜单权限 设置了[导航守卫],每次路由发生变化的时候就会触发router.beforeEach的回调函数。 有token的时候,判断当前用户是否已拉取完user_info信息。根据roles权限生成可访问的路由表。 没有token的时候,判断在免登录白名单,直接进入。否则全部重定向到登录页。

  • 3.### 接口权限:接口权限和前端的按钮权限一一对应。为的是防止用户绕过按钮直接请求后端接口获取数据。

  • 4.### 数据权限

  • 2.### 按钮权限:v-hasPermi="['system:menu:edit']"

  • 5.###添加页面权限: v-if="checkPermi(['taxsource:merchant_edit:taxdetail'])"




### 最后

中年危机是真实存在的,即便有技术傍身,还是难免对自己的生存能力产生质疑和焦虑,这些年职业发展,一直在寻求消除焦虑的依靠。

*   技术要深入到什么程度?

*   做久了技术总要转型管理?

*   我能做什么,我想做什么?

*   **一技之长,就是深耕你的专业技能,你的专业技术。**(重点)

*   独立做事,当你的一技之长达到一定深度的时候,需要开始思考如何独立做事。(创业)

*   拥有事业,选择一份使命,带领团队实现它。(创业)

**一技之长分五个层次**

*   栈内技术 - 是指你的前端专业领域技术

*   栈外技术 - 是指栈内技术的上下游,领域外的相关专业知识

*   工程经验 - 是建设专业技术体系的“解决方案”

*   带人做事 - 是对团队协作能力的要求

*   业界发声 - 工作经验总结对外分享,与他人交流



> 永远不要放弃一技之长,它值得你长期`信仰持有`。



> 主要内容包括html,css,html5,css3,JavaScript,正则表达式,函数,BOM,DOM,jQuery,AJAX,vue 等等。

![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/86e124ee1467461682fb06d786c78364~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3NTc5MjMwMTY3MDI=:q75.awebp?rk3s=f64ab15b&x-expires=1770814208&x-signature=0Nih1yfSD8rSZ7WhFCPeU8JETmk%3D)

**开源分享:https://docs.qq.com/doc/DSmRnRGxvUkxTREhO**