2020年高级前端社招之路 | 掘金技术征文

1,326 阅读20分钟

面试常考分类

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)}
  1. 函数
	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实现

类数组
  1. Array.prototype.slice.call(arguments);
深拷贝、浅拷贝

juejin.im/post/684490…

防抖、节流

juejin.im/post/684490…

for in、for of、Object.keys()区别

juejin.im/post/684490…

函数柯里化

juejin.im/post/684490…

fetch取消

利用AbortController

ajax原理

zhuanlan.zhihu.com/p/38067984

正则表达式
  1. 获取url params
  2. 切分千分位(10000 => 10,000)
  3. 切分银行卡卡号(像实体卡一样四位一个空格)
//根据参数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,' ')
数组原理
  1. 快数组(动态扩容)---速度快
  2. 慢数组(hashTable)---慢,但是节约内存空间
  3. 数据操作返回的结果都是原数组的一个浅拷贝: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原理

zhuanlan.zhihu.com/p/26388217

try catch的使用
  1. 能被 try catch 捕捉到的异常,必须是在报错的时候,线程执行已经进入 try catch 代码块,且处在 try catch 里面,这个时候才能被捕捉到
  2. try catch 无法捕捉 Promise 的异常,是因为 Promise 的异常没有往上抛,Promise 的异常都是由 reject 和 Promise.prototype.catch 来捕获,不管是同步还是异步
undefined与null的区别

www.ruanyifeng.com/blog/2014/0…

函数参数的非空处理

两个数交换数值,不能使用第三个变量

toString.call和typeof的区别

注意:null的表现不同

其他
  1. 模块化 作用域/闭包 原型和类的区别
  2. 在 JavaScript 中如何实现对象的私有属性
  3. symbol用途
  4. 实现xss-filter
  5. 实现jsonp
  6. 纯函数的应用场景

ES6

es6.ruanyifeng.com/#docs/itera…

箭头函数

箭头函数是普通函数的简写,可以更优雅的定义一个函数,和普通函数相比,有以下几点差异:

  1. 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象;
  2. 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
  3. 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数;
  4. 不可以使用 new 命令,因为没有自己的 this,无法调用 call,apply;没有 prototype 属性 ,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 __proto__;
Promise相关
解决的问题
  1. 解决地狱式回调的问题;
  2. 让异步编程语法变成和同步编程一样;
笔试题
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可以按照这个思路实现

其他
  1. ArrayBuffer
  2. const的值可改变吗
    • 对象的属性是可以改变的
  3. 如何解决ES6的兼容问题

typescript

  1. 谈下对typescript的理解

Vue

使用经验
  1. $ref只能在mounted生命周期钩子函数被调用之后才能使用;
  2. parentparent和root在各个生命周期钩子函数中都可以使用;
  3. 通过v-bind="$attrs"来传递父组件上的prop class和style;
  4. 通过v-on="$listeners"来传递父组件上的事件监听器和事件修饰符;
  5. v-for和v-if不要一起使用;
  6. 列表渲染设置属性key;
  7. 在v-if/v-if-else/v-else中使用key;
vue-cli修改默认的webpack配置文件

blog.csdn.net/Run_youngma…

动态创建的watcher会自动的销毁吗
vuex过大的问题
  1. 模块动态加载;
  2. 模块异步加载; segmentfault.com/a/119000001…
优化实践
keep alive

缓存组件实例,通过vm.$el获得先前DOM元素

长列表优化
什么是发布/订阅模式、观察者模式,以及二者区别

数据响应式

juejin.im/post/684490…

路由理解
  1. 路由钩子执行顺序

当点击切换路由时:

beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回调

juejin.im/post/684490…

路由组件加载方式
  1. 同步加载

  2. 异步加载

  3. 按需加载

axios、ajax、request区别
vue3.0
v-model原理
  1. 用于在表单元素input、textarea、select上创建双向数据绑定的语法糖;
  2. select使用value属性和change事件,而input和textarea使用value和input事件;
  3. 如果input和textarea想使用change而非input时,采用v-modl.lazy修饰;
  4. input对应的checkbox和radio使用checked属性和change事件;
  5. 注意自定义组件中,父组件中用v-model传值,子组件中用model接收的方式实现双向绑定;

v-model原理

生命周期

github.com/jingzhiMo/j…

其他
  1. 虚拟DOM原理实践、优势 组件更新,父与子的更新先后关系
  2. Vue router、store原理
  3. Proxy相比于defineProperty的优势
  4. diff算法
  5. 组件的动态引入(webpack提供的import())
  6. 权限验证
  7. 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这个组件的实例,常用于单元测试;
  8. axios的跨域请求
  9. 多次修改state只渲染一次页面
  10. vue.nexTick(callback)的作用
  11. mutation和action的区别
  12. history和hash区别
  13. export default和export区别
  14. 权限控制
  15. 自定义皮肤设置
  16. 前端监控(用户轨迹埋点、错误监控) 自动化页面埋点
  17. 实现InputNumber
  18. keep-alive的理解
  19. vue是如何对数组方法进行变异的?例如push、pop、slice等方法;
  20. Vue的diff时间复杂度从O(n^3)优化到O(n),那么O(n^3)和O(n)是如何计算出来的?
  21. Vue的响应式原理中Object.defineProperty有什么缺陷?
  22. 谈谈你对virtual DOM的理解
  23. vue首页白屏是什么问题引起的?如何解决?
  24. Vue中的computed和watch的区别在哪里
  25. Vue中的computed是如何实现的
  26. 谈一谈nextTick的原理 nextticknexttick set实现原理 数组响应式为什么要单独处理
  27. beforecreate和create的区别
  28. 怎么计算组件在视口内出现了几次?IntersectionObserver怎么使用的?怎么知道一个DOM节点出现在视口内
  29. 同构,nuxt.js
  30. axios
  31. 手势库实现介绍
  32. 动态组件

css

滚动条宽度影响布局

解决方案,容器设置样式margin-right: calc(100% - (设计稿宽度,也就是没有滚动条时的宽度) ); 100%代表元素目前的实际宽度(设计稿宽度-滚动条宽度)

image.png

image.png

image.png

单行文本和多行文本截断

效果图:

多行文本截断

其他
  1. less的使用
  2. background-color与background-img问题
    • background-color一定要写在前面,不然显示不出背景图片;
  3. 绝对定位和浮动元素的区别
BFC

juejin.im/post/688810…

  1. 用途
    • BFC 的结界特性最重要的用途其实不是去 margin 重叠或者是清除 float 影响,而是实现更健壮、更智能的自适应布局
  2. 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世界层叠顺序规则

  1. line-height与height的区别
    1. 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;
    }

  1. 我们定义li的样式为height:20px,那么这个元素的高度并不会因为内容的多少而改变,如果显示为2行,文字的总高度超出了,这个li标签的高也不会随着文本而改变
ul li{
    width: 30px;
    height:20px;
    word-break: break-all;
    background: yellow;
    margin-bottom: 10px;
}

13. line-height和height相等时可以让文字垂直剧中的原理

  1. 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; }
  2. 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,对其他的度量方式如paddingmarginborder-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
  1. vh —— 视口高度的1/100
  2. vw —— 视口宽度的1/100
  3. vmin —— 视区宽度或高度较小值的1/100(IE9支持的是vm)
  4. 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

  1. html5设计的目的,是在移动设备上支持多媒体。为了支持这一点
引入新的多媒体元素:video audio;
引进图形绘制:canvas
引进新的语义结构元素:footer article  aside nav等
引进新的表单控件:calendar date time email url search等

2. html meta

http、网络安全

  1. http2解决了什么问题
  2. 判断一个ipv4地址是否存在已有的1000万条ipv4地址中(bitmap)
  3. https原理(握手过程)
  4. http1和http2有什么区别,http2优势(多路复用,头部压缩的原理)
  5. http常见返回码及其含义
  6. tcp和udp区别,udp的应用,dns用到的协议
  7. 什么是cors?为什么要用cors?
  8. xss是什么?如何防范?具体例子,jsonp如何防止xss?
  9. cookie有什么用?存在什么问题?如何解决?crsf如何防范?
  10. dns寻址过程?简述cdn原理
  11. options怎么做预检(跨域是否允许的检查)
  12. Keep-Alive 连接的限制和规则
  13. 报文有哪些关键字段
  14. POST请求支持query吗
  15. 301 vs 308
    • 301 ,永久移动,将请求重定向get请求
    • 308 ,永久重定向,请求和所有将来的请求应该使用另一个URI重复。 307和308重复302和301的行为,但不允许HTTP方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。
  16. 200 vs 201 vs 204
    • 200 使用惯例是,在 PUT 请求中进行资源更新,但是不需要改变当前展示给用户的页面,那么返回 204 No Content。如果创建了资源,则返回 201 Created 。如果应将页面更改为新更新的页面,则应改用 200 。
    • 201 Created表示一个资源首次被创建成功,一般用于post请求
    • 204 No Content 成功状态响应码,表示该请求已经成功了,但是客户端客户不需要离开当前页面。默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中。 一般用于put,delte请求
http优化
控制并发请求数

Promise实现

应对不稳定的网络环境 -- 指数补偿

按照指数的时间倍数重复发送请求(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();
      })
  }
并发处理和时间窗口
  1. 多个资源并发请求 Promise.all
  2. 基于时间窗口过滤重复请求
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传递规则
  1. 浏览器工作原理

    html.spec.whatwg.org/multipage/w…

  2. 在浏览器输入 URL 回车之后发生了什么

    zhuanlan.zhihu.com/p/80551769

  3. 前端适配方案

  4. 如何定位内存泄露

webpack

打包优化

juejin.im/post/688228…

配置跨域请求

proxy配置的跨域只在开发模式下生效,原理就是用node做的中间层

gzip压缩
对 tree-shaking 的了解
import 怎么省略文件后缀的
按需引入原理
webpack是怎么处理模块循环引用的情况的
webpack原理及生命周期
wepack-dev-server 热更新功能实现原理
webpack按照模块打包缓存

juejin.im/post/684490…

node

浏览器和 Node.js 的事件循环机制有什么区别?

blog.fundebug.com/2019/01/15/…

自己的写一个脚手架

设计模式

  1. 原型设计模式、享元模式
  2. 策略模式、命令模式
  3. 观察者模式
  4. 订阅发布模式
  5. 工厂模式
  6. 适配器模式
  7. 中介这模式

严格模式

  1. 严格模式下默认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.

移动开发

  1. iphone x刘海适配;
  2. 如何解决移动端 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: '';
        } 

微信小程序

数据结构

  1. 红黑树解决的问题
  2. B树解决的问题,B树B+树的应用
    • B树的各种操作能使B树保持较低的高度,从而有效避免磁盘过于频繁的查找存取操作,达到有效提高查找效率的目的

算法

动态规划、分治法、贪心算法的区别

zhuanlan.zhihu.com/p/33048876

最长公共子序列
  1. 动态规划求解
其他
  1. 合并n个有序链表
  2. 渲染一个超长的list,实现dom节点的复用
  3. random7实现random10
  4. 判断一个ipv4地址是否存在已有的1000万条ipv4地址中(bitmap)
  5. 一次可以走一步或者两步,n个阶梯的楼梯有多少种走法
  6. 实现扫雷(二维数组,随机分布地雷坐标)
  7. 计算累进税率
  8. 求一个数组中比左边和右边的元素都大的元素(On)
  9. 协同,如腾讯文档
  10. 字典树的应用
  11. diff算法联想到的最长公共子序列
  12. 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);

归并排序

www.runoob.com/w3cnote/mer…

快速排序
//快速排序
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

  1. 地图

性能相关

  1. 怎么实现无限滚动列表;
  2. 性能监控
        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性能更高

工程化相关

  1. 同构、app端适配、移动端解决方案;
  2. 组件库、架构;
  3. 如何管理keep-alive、如何去分模块管理各个业务,如何去缓存数据;
  4. 模块化、单向数据流;
  5. 谈下对前端微服务的理解
  6. 谈下对serverless架构的理解
  7. vscode插件是怎么实现的,自己写一个vscode插件

适配相关问题

  1. 两个按钮大屏幕上一行显示,小屏幕上两行显示;
<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. 长列表处理 1、长列表的处理除了监听onscroll外,还可以根据是否进入可视区域的监听?最优dom数据 2、可视区域判断:juejin.im/post/684490…
    原理:el.getBoundingClientReact().top <= viewPortHeight el.getBoundingClientReact().top = el.offsetTop - document.documentElement.scrollTop
  2. 图片的优化 + base64处理小图片 + 雪碧图
  3. 请求的优化 + 减少请求:首页请求的合并、不用提前请求的先不发、能在模板中处理的就不用请求、请求异步化 + 按需加载 + 缓存处理

安全性问题(登录用户的cookie)

防火墙拦截问题

防火墙会对请求中的关键字如select、in等进行拦截,采用base64单纯的加密防火墙会进行解密拦截,所以采用更复杂的算法如RAS,对post请求的内容进行加密。

兼容性问题

  1. document.body和document.documentElement
  2. 样式的浏览器兼容

交互优化

  1. 列表始终在可视区域
  2. 下拉框向上还是向下的动态判断

跨域处理

跨域处理方式及原理

jsonp原理(怎么模拟发请求和接收数据的)

jsonp实现思路

canvas能够截取跨域的图片吗
ngix配置跨域
后台3行代码解决

浏览器缓存

浏览器缓存from desk和from memory原理
  1. from desk:常缓存一些非脚本文件,如css;
  2. from memory: 缓存脚本,js 图片,字体图标等;
强缓存和协商缓存的理解

算法相关

  1. 0.1+0.2 ?=0.3 处理方式,实现一个计算器

  2. 深层对象扁平化的方法

  3. 二分查找的前提条件及时间复杂度、空间复杂度

  4. 查找每个li标签的index

    • 0
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    </body>
    
  5. 递归的最大次数?比如如果2000次以后会发生什么?

框架相关

  1. vue原理调用哪些方法

  2. 单向数据流

  3. 封装组件应该注意什么

    1. 开闭原则,方法私有化,钩子函数的挂载(避免在组件中写业务逻辑,污染数据)

      • 开闭原则:对扩展开放,对修改关闭
      • 方法私有化处理方法:proxy 中throw new Error('Attempt to access private property');
    2. 高性能,低耦合;

    3. 对输入值进行验证、对输入值进行深拷贝

      • $.extends(true,{},{})
    4. 留一个slot

  4. tree的实现原理

  5. 虚拟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

项目相关

  1. 项目中遇到的疑难点,并且怎么解决的