面试常考分类
javascript
原型/构造函数/实例/原型链
关系图如下:
注意:
原型链/继承
比如要创建一个Happy对象,要继承Person,关系图如下:
Function.prototype.extend = function(superClass){
this.prototype = Object.create(superClass,this.prototype);
this.prototype.constructor = this;
}
Happy.extend(Person);
this
方法的作用有以下五种用途:
function x(){console.log(this)}
- 函数
x();//this指向的就是global
2. 方法
var o = {x:x};
o.x();//this指向的就是o
3. call apply bind
x.call(this)//this传入什么就是什么
4. 构造函数
var z = new x();//this指向z
5. 箭头函数
this指向块级作用域指向的this
以上知识点相关笔试题
function Foo(){
getName = function(){
alert(1);
}
return this;
}
Foo.getName = function(){
alert(2)
}
Foo.prototype.getName = function(){
alert(3);
}
var getName = function(){
alert(4);
}
function getName(){//变量提升到上面,所以会被alert(4)覆盖
alert(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
function executor(handler){
handler();//this指向的是window
}
var counter = {
count:0,
inc:function(){
this.count++;
}
};
executor(counter.inc);
console.log(counter.count)//0
new操作符的实现
const命令
bind的实现
instanceOf实现
类数组
- Array.prototype.slice.call(arguments);
深拷贝、浅拷贝
防抖、节流
for in、for of、Object.keys()区别
函数柯里化
fetch取消
ajax原理
正则表达式
- 获取url params
- 切分千分位(10000 => 10,000)
- 切分银行卡卡号(像实体卡一样四位一个空格)
//根据参数name获取参数的value
function QueryString(item) {
var sValue = location.search.match(new RegExp("[\?\&]" + item + "=([^\&]*)(\&?)", "i"));
return sValue ? sValue[1] : sValue;
}
//正则切分千分位
str.replace(/\B(?=(?:\d{3})+(?!\d))/g,',');
//银行卡分割
'6216697125451236548'.replace(/\B(?=(?:\d{4})+(?!\d))/g,' ')
数组原理
- 快数组(动态扩容)---速度快
- 慢数组(hashTable)---慢,但是节约内存空间
- 数据操作返回的结果都是原数组的一个浅拷贝:slice splice filter 已知如下数组:var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]; 编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
uuid生成
```
//上面的代码等效为下面的
function guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0;//这里其实还有一个作用就是把r变成了整数
var v = (c == 'x') ? r : (r&0x3|0x8);// 其实就是说x直接替换,y另外的用经过特殊处理的,这里的特殊处理就是 r&0x3|0x8 ,因为位运算有顺序,这样的值就限定在一个范围了,其范围就是二进制 1000-1011这样4个数字了,然后输出为8,9,A,B这样4个字符了。
return v.toString(16);
});
}
```
JS Object和JS Array原理
try catch的使用
- 能被 try catch 捕捉到的异常,必须是在报错的时候,线程执行已经进入 try catch 代码块,且处在 try catch 里面,这个时候才能被捕捉到
- try catch 无法捕捉 Promise 的异常,是因为 Promise 的异常没有往上抛,Promise 的异常都是由 reject 和 Promise.prototype.catch 来捕获,不管是同步还是异步
undefined与null的区别
www.ruanyifeng.com/blog/2014/0…
函数参数的非空处理
两个数交换数值,不能使用第三个变量
toString.call和typeof的区别
注意:null的表现不同
其他
- 模块化 作用域/闭包 原型和类的区别
- 在 JavaScript 中如何实现对象的私有属性
- symbol用途
- 实现xss-filter
- 实现jsonp
- 纯函数的应用场景
ES6
es6.ruanyifeng.com/#docs/itera…
箭头函数
箭头函数是普通函数的简写,可以更优雅的定义一个函数,和普通函数相比,有以下几点差异:
- 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象;
- 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
- 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数;
- 不可以使用 new 命令,因为没有自己的 this,无法调用 call,apply;没有 prototype 属性 ,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 __proto__;
Promise相关
解决的问题
- 解决地狱式回调的问题;
- 让异步编程语法变成和同步编程一样;
笔试题
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
reject()
console.log(2);
})
promise.then(() => {
console.log(3);
},() => {
console.log("失败的状态")
})
console.log(4);
//输出结果为1 2 4 3
Promise.all、Promise.allSettled、Promise.race、Promise.any的区别
all、race的实现,allsettled和any可以按照这个思路实现
其他
- ArrayBuffer
- const的值可改变吗
- 对象的属性是可以改变的
- 如何解决ES6的兼容问题
typescript
- 谈下对typescript的理解
Vue
使用经验
- $ref只能在mounted生命周期钩子函数被调用之后才能使用;
- root在各个生命周期钩子函数中都可以使用;
- 通过v-bind="$attrs"来传递父组件上的prop class和style;
- 通过v-on="$listeners"来传递父组件上的事件监听器和事件修饰符;
- v-for和v-if不要一起使用;
- 列表渲染设置属性key;
- 在v-if/v-if-else/v-else中使用key;
vue-cli修改默认的webpack配置文件
动态创建的watcher会自动的销毁吗
vuex过大的问题
- 模块动态加载;
- 模块异步加载; segmentfault.com/a/119000001…
优化实践
keep alive
缓存组件实例,通过vm.$el获得先前DOM元素
长列表优化
什么是发布/订阅模式、观察者模式,以及二者区别
数据响应式
路由理解
- 路由钩子执行顺序
当点击切换路由时:
beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回调
路由组件加载方式
-
同步加载
-
异步加载
-
按需加载
axios、ajax、request区别
vue3.0
v-model原理
- 用于在表单元素input、textarea、select上创建双向数据绑定的语法糖;
- select使用value属性和change事件,而input和textarea使用value和input事件;
- 如果input和textarea想使用change而非input时,采用v-modl.lazy修饰;
- input对应的checkbox和radio使用checked属性和change事件;
- 注意自定义组件中,父组件中用v-model传值,子组件中用model接收的方式实现双向绑定;
生命周期
其他
- 虚拟DOM原理实践、优势 组件更新,父与子的更新先后关系
- Vue router、store原理
- Proxy相比于defineProperty的优势
- diff算法
- 组件的动态引入(webpack提供的import())
- 权限验证
- Vue.extend、Vue.util.extend、Vue.mixin的区别
- Vue.mixin({})是全局混入vue实例,主要用于生命周期的注入;
- Vue.util.extend(to,_from) 将from的值全部拷贝到to上,是浅拷贝;
- Vue.extend(HellowWord) 返回的是一个Constructor,然后vm = new Constructor();获取到helloworld这个组件的实例,常用于单元测试;
- axios的跨域请求
- 多次修改state只渲染一次页面
- vue.nexTick(callback)的作用
- mutation和action的区别
- history和hash区别
- export default和export区别
- 权限控制
- 自定义皮肤设置
- 前端监控(用户轨迹埋点、错误监控) 自动化页面埋点
- 实现InputNumber
- keep-alive的理解
- vue是如何对数组方法进行变异的?例如push、pop、slice等方法;
- Vue的diff时间复杂度从O(n^3)优化到O(n),那么O(n^3)和O(n)是如何计算出来的?
- Vue的响应式原理中Object.defineProperty有什么缺陷?
- 谈谈你对virtual DOM的理解
- vue首页白屏是什么问题引起的?如何解决?
- Vue中的computed和watch的区别在哪里
- Vue中的computed是如何实现的
- 谈一谈nextTick的原理 set实现原理 数组响应式为什么要单独处理
- beforecreate和create的区别
- 怎么计算组件在视口内出现了几次?IntersectionObserver怎么使用的?怎么知道一个DOM节点出现在视口内
- 同构,nuxt.js
- axios
- 手势库实现介绍
- 动态组件
css
滚动条宽度影响布局
解决方案,容器设置样式margin-right: calc(100% - (设计稿宽度,也就是没有滚动条时的宽度) ); 100%代表元素目前的实际宽度(设计稿宽度-滚动条宽度)
单行文本和多行文本截断
效果图:
其他
- less的使用
- background-color与background-img问题
- background-color一定要写在前面,不然显示不出背景图片;
- 绝对定位和浮动元素的区别
BFC
- 用途
- BFC 的结界特性最重要的用途其实不是去 margin 重叠或者是清除 float 影响,而是实现更健壮、更智能的自适应布局
- BFC形成条件
-
<html>根元素
-
float 的值不为 none
-
overflow 的值为 auto、scroll 或 hidden
-
display 的值为 table-cell、table-caption 和 inline-block 中的任何一个
-
position 的值不为 relative 和 static
-
css3新特性
+ 伪元素::selection
7. margin越界和重叠的问题
+ 相邻块级元素margin重叠
+ 父子块级元素margin越界
8. 对话框上的小三角
9. 用了flex后,子元素哪些属性会失效
+ float 、 vertical-align 、 clear
+ 屏幕总宽度不够的时候,flex-warp:nowarp的时候。元素的width也会失效
10. canvas碰撞检测
+ canvas的一切动画效果,都是数据在渲染
+ js改变数据,然后canvas根据数据重新渲染
11. 目前的响应式和自适应方案
+ 响应式:
+ 如果pc和移动端差距大:打开一个js,判断屏幕大小-wap.baidu.com wwww.baidu.com
+ 如果pc和移动端差距不大:媒体查询,js判断都可以,然后引用不同的css
+ 自适应:
+ 如果不是特别要求适应,使用百分比
+ 如果要求特别高,用rem,配合js
12. CSS世界层叠顺序规则
- line-height与height的区别
- line-height 是指每行的高度, 假如定义li标签的行高为line-heigth:20px; 文字在浏览器中显示为一行时,这个li标签的高度会为20px,如果为两行,则li标签的高度为40px; line-height是20px不变, 只是height变了
ul li{
width: 30px;
line-height: 20px;
word-break: break-all;
background: yellow;
margin-bottom: 10px;
}
- 我们定义li的样式为height:20px,那么这个元素的高度并不会因为内容的多少而改变,如果显示为2行,文字的总高度超出了,这个li标签的高也不会随着文本而改变
ul li{
width: 30px;
height:20px;
word-break: break-all;
background: yellow;
margin-bottom: 10px;
}
13. line-height和height相等时可以让文字垂直剧中的原理
- css脱离文档流float和定位absolute的区别
+使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围。 而对于使用absolute 脱离文档流的元素,其他盒子与其他盒子内的文本都会无视它。
.parent{
width: 150px;
}
.first{
float:left;
background-color: pink;
}
.second{
background-color:palegreen;
}
.parent{ width: 150px; } .first{ position: absolute; background-color: pink; } .second{ background-color:palegreen; }
- window.requestAnimationFrame()的理解
#dialog {
width: 100px;
height: 100px;
border: 1px solid gray;
position: relative;
}
#dialog::before {
position: absolute;
right: -20px;
top: 2px;
border: 10px solid gray;
content: '';
border-color: transparent transparent transparent gray;
}
#dialog::after {
position: absolute;
right: -19px;
top: 2px;
border: 10px solid gray;
content: '';
border-color: transparent transparent transparent #fff;
}
px rem em vh vw 百分比的区别是什么
通常对font-size使用rem,对border使用px,对其他的度量方式如padding、margin、border-radius等使用em。然而在必要时,需要声明容器的宽度的话,建议使用百分比。
rem
```
//rem是相对于根元素(html)字体大小的
(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
setPro = clientWidth / 960;
docEl.style.fontSize = 10 * (clientWidth / 960) + 'px';
};
recalc();
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
```
em
em是最常见的相对长度单位,这是排版中使用的一种度量方式,基准值是当前元素的字号大小。 在CSS中,1em表示当前元素的字号大小,实际值取决于在哪个元素上应用。
vh vw
- vh —— 视口高度的1/100
- vw —— 视口宽度的1/100
- vmin —— 视区宽度或高度较小值的1/100(IE9支持的是vm)
- vmax —— 视区宽度或高度较大值的1/100(在写本书时,IE或者Edge都不支持)
:root {
font-size: calc(0.5em + 1vw);
}
17. 18. zoom和scale的区别 www.zhangxinxu.com/wordpress/2… 19. margin-top为负值 20. 移动端适配有了解吗?rem布局 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38.
html
- html5设计的目的,是在移动设备上支持多媒体。为了支持这一点
引入新的多媒体元素:video audio;
引进图形绘制:canvas
引进新的语义结构元素:footer article aside nav等
引进新的表单控件:calendar date time email url search等
2. html meta
http、网络安全
- http2解决了什么问题
- 判断一个ipv4地址是否存在已有的1000万条ipv4地址中(bitmap)
- https原理(握手过程)
- http1和http2有什么区别,http2优势(多路复用,头部压缩的原理)
- http常见返回码及其含义
- tcp和udp区别,udp的应用,dns用到的协议
- 什么是cors?为什么要用cors?
- xss是什么?如何防范?具体例子,jsonp如何防止xss?
- cookie有什么用?存在什么问题?如何解决?crsf如何防范?
- dns寻址过程?简述cdn原理
- options怎么做预检(跨域是否允许的检查)
- Keep-Alive 连接的限制和规则
- 报文有哪些关键字段
- POST请求支持query吗
- 301 vs 308
- 301 ,永久移动,将请求重定向get请求
- 308 ,永久重定向,请求和所有将来的请求应该使用另一个URI重复。 307和308重复302和301的行为,但不允许HTTP方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。
- 200 vs 201 vs 204
- 200 使用惯例是,在 PUT 请求中进行资源更新,但是不需要改变当前展示给用户的页面,那么返回 204 No Content。如果创建了资源,则返回 201 Created 。如果应将页面更改为新更新的页面,则应改用 200 。
- 201 Created表示一个资源首次被创建成功,一般用于post请求
- 204 No Content 成功状态响应码,表示该请求已经成功了,但是客户端客户不需要离开当前页面。默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中。 一般用于put,delte请求
http优化
控制并发请求数
应对不稳定的网络环境 -- 指数补偿
按照指数的时间倍数重复发送请求(0ms 200ms 400ms 800ms 1600ms 3200ms fail)
/**
* 应对不稳定的网络环境 -- 指数补偿
* @param {*} url
*/
function request(url) {
let resolved = false;
let t = 1;
return new Promise((resolve) => {
function doFetch() {
if (resolved || t > 16) {
return
}
fetch(url).then(res => {
return res.text();
}).then(data => {
console.log(t);
if (!resolved) {
resolve(data);
resolved = true;
}
})
setTimeout(() => {
doFetch();
t *= 2;
}, t * 100)
}
doFetch();
})
}
并发处理和时间窗口
- 多个资源并发请求 Promise.all
- 基于时间窗口过滤重复请求
const fetch = require('node-fetch');
const { text } = require('express');
/**
* 多个资源并发请求 Promise.all
* 基于时间窗口过滤重复请求
*/
function hash(...args) {
return args.join(',');
}
function window_it(f, time = 50) {
let w = {};
let flag = false;
return (...args) => {
return new Promise(resolve => {
if (!w[hash(args)]) {
w[hash(args)] = {
func: f,
args,
resolvers: []
}
}
if (!flag) {
flag = true;
setTimeout(() => {
Object.keys(w).forEach(key => {
const { func, args, resolvers } = w[key];
const promise = func(...args).then(resp => resp.text()).then(text => {
resolvers.forEach(r => {
r(text);
})
flag = true;
w = {};
});
});
}, time);
}
w[hash(args)].resolvers.push(resolve);
})
}
}
那种格式的图片压缩率最高
浏览器
cookie传递规则
-
浏览器工作原理
-
在浏览器输入 URL 回车之后发生了什么
-
前端适配方案
-
如何定位内存泄露
webpack
打包优化
配置跨域请求
proxy配置的跨域只在开发模式下生效,原理就是用node做的中间层
gzip压缩
对 tree-shaking 的了解
import 怎么省略文件后缀的
按需引入原理
webpack是怎么处理模块循环引用的情况的
webpack原理及生命周期
wepack-dev-server 热更新功能实现原理
webpack按照模块打包缓存
node
浏览器和 Node.js 的事件循环机制有什么区别?
blog.fundebug.com/2019/01/15/…
自己的写一个脚手架
设计模式
- 原型设计模式、享元模式
- 策略模式、命令模式
- 可以优化多层if判断的问题 switch判断问题
- juejin.im/post/684490…
- 观察者模式
- 订阅发布模式
- 工厂模式
- 适配器模式
- 中介这模式
严格模式
- 严格模式下默认this指向
'use strict';
var a = 1;
var obj = {
a:2,
b:function(){
this.a = 3;
},
print:function(){
console.log(this.a);
}
};
obj.print(); // 2
var print = obj.print;
print(); // 报错,严格模式下this默认是undefined
2. 3. 4. 5. 6. 7. 8. 9. 10.
移动开发
- iphone x刘海适配;
- 如何解决移动端 click300ms 延迟
移动端1px边框处理
rem + devicePixelRatio + meta方案
/**
*移动端1px处理
* rem + devicePixelRatio + meta方案
*/
function dealWithMobile1Px(){
var docEl = document.documentElement;
var fontsize = 12*window.devicePixelRatio + 'px';
docEl.style.fontSize = fontsize;
var viewport = document.querySelector("meta[name=viewport]");
//下面是根据设备像素设置viewport
if (window.devicePixelRatio == 1) {
viewport.setAttribute('content', 'width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no');
}
if (window.devicePixelRatio == 2) {
viewport.setAttribute('content', 'width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no');
}
if (window.devicePixelRatio == 3) {
viewport.setAttribute('content', 'width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no');
}
}
dealWithMobile1Px();
伪元素方案
//伪元素方案
.container2{
position:relative;
}
.container2:after{
position:absolute;
top:10px;
left:0;
border-top: 1px solid gray;
width:200%;
height: 1px;
transform:scale(0.5);
transform-origin: left top;
content: '';
}
微信小程序
数据结构
- 红黑树解决的问题
- B树解决的问题,B树B+树的应用
- B树的各种操作能使B树保持较低的高度,从而有效避免磁盘过于频繁的查找存取操作,达到有效提高查找效率的目的
算法
动态规划、分治法、贪心算法的区别
最长公共子序列
其他
- 合并n个有序链表
- 渲染一个超长的list,实现dom节点的复用
- random7实现random10
- 判断一个ipv4地址是否存在已有的1000万条ipv4地址中(bitmap)
- 一次可以走一步或者两步,n个阶梯的楼梯有多少种走法
- 实现扫雷(二维数组,随机分布地雷坐标)
- 计算累进税率
- 求一个数组中比左边和右边的元素都大的元素(On)
- 协同,如腾讯文档
- 字典树的应用
- diff算法联想到的最长公共子序列
- Git比较两个文件不同的算法--最长公共子串
洗牌算法
var arr = [1, 5, 6, 9, 10, 15];
/**
*
* @param {*} arr 源数组
* @param {*} n 从数组中随机选取n个数
* 思路:随机的调换0-n序列号位置的值
*/
function sample(arr, n) {
if (!(arr instanceof Array)) {
throw new Error('请输入数组类型');
}
let len = arr.length;
if (isNaN(n) || n > arr.length) {
throw new Error('请输入合理的选择多少个随机数的值');
}
//浅拷贝,避免对源数组造成污染
//以下两种方式都可以
var shadowArr = [];
// shadowArr = arr.slice(0);
Object.assign(shadowArr, arr);
for (let i = 0; i < n; i++) {
let randomIndex = Math.floor(Math.random() * len);
let tmp = shadowArr[i];
shadowArr[i] = shadowArr[randomIndex];
shadowArr[randomIndex] = tmp;
}
return shadowArr.slice(0, n);
}
var result = sample(arr, 3);
console.log(result);
console.log(arr);
11. DFS和BFS的算法实现; 12. 如何判断一个图有环的算法实现;
全排列
/**
* 全排列
*/
var arr = [1, 2, 3, 4];
function calAll(arr, from) {
if (from == arr.length - 1) {
console.log(arr);
}
for (let i = from; i < arr.length; i++) {
swap(arr, i, from);
calAll(arr, from + 1);
swap(arr, i, from);
}
}
function swap(arr, i, from) {
let temp = arr[i];
arr[i] = arr[from];
arr[from] = temp;
}
calAll(arr, 0);
冒泡排序
//冒泡排序
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
console.log(arr);
}
冒泡排序优化:
function bubbleSort(arr) {
for (let i = arr.length-1; i >0; i--) {
var isSort = true;
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j+1]) {
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
isSort = false;
}
}
if(isSort){
console.log(arr);
return;
}
}
console.log(arr);
}
bubbleSort([3,2,8,7,9]);
选择排序
/**
* 选择排序
*/
var arr = [2, 7, 9, 4, 6, 3];
function selectSort(arr) {
for (let i = 0; i < arr.length; i++) {
var minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
let temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
selectSort(arr);
归并排序
快速排序
//快速排序
let arr = [3, 5, 6, 7, 2, 4, 7, 3];
function partion(arr, low, high) {
let privot = arr[low];
while (low < high) {
while (low < high && arr[high] > privot) {
high--;
}
arr[low] = arr[high];
while (low < high && arr[low] <= privot) {
low++;
}
arr[high] = arr[low];
}
arr[low] = privot;
return low;
}
function quickSort(arr, low, high) {
if (low < high) {
let index = partion(arr, low, high);
quickSort(arr, 0, index - 1);
quickSort(arr, index + 1, high);
}
}
quickSort(arr, 0, arr.length - 1);
插入排序
/**
* 插入排序
*/
var arr = [2, 7, 9, 4, 6, 3];
function insertSort(arr) {
for (let i = 1; i < arr.length; i++) {
var preIndex = i - 1;
var current = arr[i];
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
}
insertSort(arr);
计数排序
//计数排序
var arr = [2, 5, 3, 0, 2, 3, 0, 3];
function countSort(arr, maxValue) {
var bucketLen = maxValue + 1;
var sortIndex = 0;
var bucket = new Array(bucketLen);
for (let j = 0; j < arr.length; j++) {
if (!bucket[arr[j]]) {
bucket[arr[j]] = 0;
}
bucket[arr[j]]++;
}
for (let i = 0; i < bucketLen; i++) {
while (bucket[i] > 0) {
arr[sortIndex++] = i;
bucket[i]--;
}
}
return arr;
}
countSort(arr, 5);
字符串旋转和回文判断
var str = 'abcdef';
function reverseString(strArr, from, to) {
while (from < to) {
let temp = strArr[from];
strArr[from++] = strArr[to];
strArr[to--] = temp;
}
}
//旋转字符串的前n个字符
function rotateStr(str, num) {
var strArr = str.split('');
let to = strArr.length - 1;
reverseString(strArr, 0, num - 1);
reverseString(strArr, num, to);
reverseString(strArr, 0, to);
console.log(strArr.join(''));
}
rotateStr(str, 2);
//判断是否回文
var str2 = 'abmmba';
function huiWen(str) {
var strArr = str.split('');
reverseString(strArr, 0, strArr.length - 1);
if (str == (strArr.join(''))) {
console.log('回文');
} else {
console.log('没有回文');
}
}
huiWen(str2);
缓存淘汰算法
LRU
//最近最少使用
class LRU{
constructor(maxCapacity){
this.maxCapacity = maxCapacity;
this.cache = new Map();
}
get(key){
if(!this.cache.has(key)){
return -1;
}
let value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key,value);
return value;
}
set(key,value){
if(this.cache.has(key)){
this.cache.delete(key);
}else{
if(this.cache.size === this.maxCapacity){
let firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}
this.cache.set(key,value);
}
}
LFU
FIFO
写一个方法生成随机色值,例如#c1c1c1
/**
* 随机生成一个十进制的颜色
* 核心:生成一个[0,255]的随机数
*/
function randomNum(minNum, maxNum) {
switch (arguments.length) {
case 1:
return parseInt(Math.random() * minNum + 1, 10);
break;
case 2:
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
break;
default:
return 0;
break;
}
}
console.log('random',randomNum(0,255))
写一个方法,把16进制颜色值转成10进制
/**
* 颜色由十六进制转换为十进制
*/
String.prototype.colorRgb = function() {
let hexColor = this,
rgbColor;
let regex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
if (!hexColor || !regex.test(hexColor)) {
throw '参数不符合规范';
}
let newHexColor = '#';
if (hexColor.length === 4) {
for (var i = 1; i < 4; i++) {
newHexColor = newHexColor + hexColor.slice(i, i + 1) + hexColor.slice(i, i + 1);
}
}
let resultArr = [];
for (var i = 1; i < 7; i += 2) {
let str = newHexColor.slice(i, i + 2);
resultArr.push(parseInt('0x' + str));
}
rgbColor = 'RGB(' + resultArr.join(',') + ')';
return rgbColor;
}
console.log('#fff'.colorRgb());//RGB(255,255,255)
console.log('#000'.colorRgb());//RGB(0,0,0)
写一个方法,把10进制颜色转成16进制
/**
* 颜色由十进制转换为十六进制
*/
String.prototype.colorHex = function() {
let rgbColor = this,
hexColor = '#';
let regex = /(?:\(|\)|rgb|RGB)*/g;
if (!rgbColor || !regex.test(rgbColor)) {
throw '参数不符合规范';
}
rgbColor = rgbColor.replace(regex, '');
var rgbArr = rgbColor.split(',');
rgbArr.forEach(element => {
let num = parseInt(element).toString(16);
if(num.length<2){
num = '0'+num;
}
hexColor = hexColor + num;
});
return hexColor;
}
console.log('rgb(255,255,255)'.colorHex());//#ffffff
console.log('rgb(255,0,0)'.colorHex());//#ff0000
21. 22. 23. 24. 25. 26. 27.
图形化echarts
- 地图
性能相关
- 怎么实现无限滚动列表;
- 性能监控
const per = window.performance;
function getSec(time) {
return time / 1000 + 's';
}
function getMB(size) {
return Math.round(size / 1024 / 1024, 4) + 'MB';
}
console.log('内存占用:' + getMB(per.memory.usedJSHeapSize));
console.log('tcp连接时间:' + getSec(per.timing.connectEnd - per.timing.connectStart));
console.log('响应时间:' + getSec(per.timing.responseEnd - per.timing.responseStart));
window.onload = function() {
console.log('dom渲染耗时:' + getSec(per.timing.domComplete - per.timing.domLoading));
}
3. 图片懒加载解决方案 load.js 4. 使用一个let和多个let的区别 * 使用一个let性能更高
工程化相关
- 同构、app端适配、移动端解决方案;
- 组件库、架构;
- 如何管理keep-alive、如何去分模块管理各个业务,如何去缓存数据;
- 模块化、单向数据流;
- 谈下对前端微服务的理解
- 谈下对serverless架构的理解
- vscode插件是怎么实现的,自己写一个vscode插件
适配相关问题
- 两个按钮大屏幕上一行显示,小屏幕上两行显示;
<div id="group">
<div id="groupItem">
<button>按钮1</button>
</div>
<div id="groupItem">
<button>按钮2</button>
</div>
</div>
@media (min-width: 500px) {
#group {
display: flex;
}
#groupItem {
width: 50%;
}
}
2. 3. 4. 5. 6.
一些公司的面试题整理
性能问题
- 长列表处理
1、长列表的处理除了监听onscroll外,还可以根据是否进入可视区域的监听?最优dom数据
2、可视区域判断:juejin.im/post/684490…
原理:el.getBoundingClientReact().top <= viewPortHeight el.getBoundingClientReact().top = el.offsetTop - document.documentElement.scrollTop - 图片的优化 + base64处理小图片 + 雪碧图
- 请求的优化 + 减少请求:首页请求的合并、不用提前请求的先不发、能在模板中处理的就不用请求、请求异步化 + 按需加载 + 缓存处理
安全性问题(登录用户的cookie)
防火墙拦截问题
防火墙会对请求中的关键字如select、in等进行拦截,采用base64单纯的加密防火墙会进行解密拦截,所以采用更复杂的算法如RAS,对post请求的内容进行加密。
兼容性问题
- document.body和document.documentElement
- 样式的浏览器兼容
交互优化
- 列表始终在可视区域
- 下拉框向上还是向下的动态判断
跨域处理
跨域处理方式及原理
jsonp原理(怎么模拟发请求和接收数据的)
canvas能够截取跨域的图片吗
ngix配置跨域
后台3行代码解决
浏览器缓存
浏览器缓存from desk和from memory原理
- from desk:常缓存一些非脚本文件,如css;
- from memory: 缓存脚本,js 图片,字体图标等;
强缓存和协商缓存的理解
算法相关
-
0.1+0.2 ?=0.3 处理方式,实现一个计算器
-
深层对象扁平化的方法
-
二分查找的前提条件及时间复杂度、空间复杂度
-
查找每个li标签的index
- 0
- 1
- 2
- 3
- 4
- 5
- 6
</body> -
递归的最大次数?比如如果2000次以后会发生什么?
框架相关
-
vue原理调用哪些方法
-
单向数据流
- react和vue的单向数据流:
- juejin.im/entry/68449…
-
封装组件应该注意什么
-
开闭原则,方法私有化,钩子函数的挂载(避免在组件中写业务逻辑,污染数据)
- 开闭原则:对扩展开放,对修改关闭
- 方法私有化处理方法:proxy 中throw new Error('Attempt to access private property');
-
高性能,低耦合;
-
对输入值进行验证、对输入值进行深拷贝
- $.extends(true,{},{})
-
留一个slot
-
-
tree的实现原理
-
虚拟dom节约时间的原理
笔试题
var a={a:1},b={b:2};
!function foo(arg1,arg2){
arg1 = arg2;
arg2['c'] = 3;
}(a,b);
console.log( JSON.stringify(a) , JSON.stringify(b) );
//答案是:{"a":1} {"b":2,"c":3}
var a = {n:1};
var b = a;
a.x = a = {n:2}
内存:#1000 {n:1}
a: #1000
b: #1000
由于.的优先级高于等于好,所以#1000 变为{n:1,x:}
#2000 {n:2} a指向#2000,再将x指向{n:2}
所以a: {n:2} b:{n:1,x:{n:2}}
//找出a数组中在b数组中不包含的元素
var arr1 = [1,2,3,6,9];
var arr2 = [1,3,6,8];
var result = [];
result = arr1.filter(function(item){
return arr2.indexOf(item)<0
});
//result:[2, 9]
//arr1:[1, 2, 3, 6, 9]
// 字符串由六个字符'{'、'}'、'['、']'、'('、')'随机组成,通过一个方法判断该字符串能否全部配对。如'{[()]}'、'[{}]()'能够配对,'[{})'、'{( })'无法配对。提示:字符串先转成数组
function isMatch(string) {
var tagArr = [];
var strArr = string.split('');
for (let s of strArr) {
if (s === '{') {
tagArr.push('}');
} else if (s === '[') {
tagArr.push(']');
} else if (s === '(') {
tagArr.push(')');
} else if (tagArr.pop() !== s) {
return false;
}
}
return true;
}
isMatch('{([])}'); //true
isMatch('[{]}'); //false
项目相关
- 项目中遇到的疑难点,并且怎么解决的