前端面试题记录(更新中)

92 阅读18分钟

突然想把自己之前的面试题稍微整理一下,手机、电脑、ipad真的是哪个平台都有文档啥的,一点点整理整理吧,从自己博客copy出来的,在掘金也存个档吧~
博客

2AC963CF.png

问答题

1. 1.absolute与fixed的区别

absolute(绝对定位): 对象脱离文档流,使用top、left、bottom、right等进行绝对定位,相对于第一个非static的父元素进行定位,出现滚动条时随滚动条移动;

fixed(固定定位):对象脱离文档流,同样使用top、left、bottom、right等进行绝对定位,相对于浏览器窗口进行定位,出现滚动条时不随滚动条移动;

关于屏幕、浏览器窗口、可视窗口区别可参考: blog.csdn.net/qq_43327962…

2.z-index的原理及适用范围

概念:z-index表示元素在z轴上的堆叠顺序,值为整数,一般值越大当前盒子就越显示在上层(越贴近屏幕);

适用范围:该属性仅适用于定位元素,eg:relative、fixed、absolute定位的position元素中有效,float及static无效;

image.png 如果未指定z-index属性,则元素堆叠顺序默认基于当前所在文档树;

同一个堆叠上下文:层叠级别大的元素显示在上层;

不同堆叠上下文:元素的显示顺序与自身层叠级别无关,由祖先元素的层叠级别决定;

eg:

<body>
    <div class="container1">
        <ul class="box1">box1</ul>
        <ul class="box2">box2</ul>
    </div>
    <div class="container2">
        <ul class="box3">box3</ul>
    </div>
</body>

box1、box2均没有单独指定z-index属性,也就是说没有产生新的堆叠上下文,此时它俩属于同一个堆叠上下文;如果box1、box2设置了position及z-index,谁的值大谁显示在屏幕上方;(默认规则)

如果container1的z-index小于container2,那么container1的子元素无论z-index设置的值有多大,box3也总是显示在上层;(从父规则); 3.http1.x与http2的区别

可参考:www.cnblogs.com/yll156/p/16…

4.http与https区别?TLS连接过程?

http协议默认端口号80,https默认端口号443;

https相比http多了一层TLS/SSL加密协议,更加安全可靠,但也因此响应速度小于http;

TLS/SSL通信过程:

客户端:

  1. 发送http协议版本号;

  2. 生成一个随机数,用于后续生成对话密钥;

  3. 发送加密算法、压缩算法;

服务器端:

  1. 拿到客户端发送的数据,先判断浏览器是否支持该协议版本号,若不支持则直接关闭加密通道;

  2. 浏览器器若支持,服务器端也生成一个随机数,用于生成对话密钥;

  3. 根据加密算法生成SSL证书;

客户端:

1.客户端获取到SSL证书后,先到CA进行证书验证,若证书不信任或已过期,则弹出不安全的提示,由用户决定是否继续访问;

5.浏览器缓存

浏览器的缓存机制:浏览器缓存机制主要是从新鲜度及较验值来决定浏览器是从缓存的副本获取资源还是从服务器端获取新的资源版本;

新鲜度(过期机制):缓存副本的有效期。满足以下条件,浏览器会认为该副本是有效的、足够新的;1.含有完整的过期时间控制头信息且处于有效期内;2.浏览器已经使用过缓存副本,且在一个会话中检查过新鲜度;满足以上任一条件,浏览器会直接从缓存副本中获取资源;

较验值(验证机制):服务器返回资源的时候有时在控制头信息会携带资源的实体标签(etag),它可以作为浏览器再次请求资源的较验标识,若发现标识不匹配,则说明资源发生变化或已过期需要重服务器端重新获取资源数据;

浏览器缓存主要分为强缓存协商缓存

由cache-control(相对时间)/expires(绝对时间)来决定是否开启强缓存,last-modified(资源的上次修改时间)/etag决定是否开启协商缓存;

若开启强缓存,则客户端直接从缓存中获取资源不会再请求服务器端;若开启协商缓存,则客户端仍先访问服务器端,由服务器端决定是否从缓存中获取资源,服务器端若返回304状态码,则说明请求的资源未发生变化,从缓存中获取即可,否则仍整个数据重新发给浏览器;

一般情况下,强缓存跟协商缓存会一起使用,因为即使设置了缓存时间,当用户点击时,浏览器会忽略缓存直接向服务器端发送请求,这时候协商缓存就能通过304减少响应开销;

6.产生跨域的原因?常见的跨域问题?解决跨域的方案原理?

浏览器存在同源策略:同协议、同主机、同端口。违反同源策略就会造成跨域问题;

常见的跨域问题:不同域名下的localStorage、请求资源的跨域、iframe(不同主域或同主域不同子域)

解决跨域:

  1. jsonp: 利用script标签的src属性可跨域原理,请求时需加上自定义回调函数传参,且后端通过该回调函数返回数据;针对get请求,因此存在安全问题且参数长度有限制,另外还需要后端做配合;

  2. 可通过iframe: window.location、postMessgae等属性

  3. CORS资源共享策略(后端配置):

通过后端配置Acess-Control-Allow-Origin指定可访问的源;

7.浏览器输入url的渲染过程?浏览器内核有哪些?

浏览器输入url的渲染过程:浏览器向服务端请求获取到html文件流,js引擎将文件流转换成人能看懂的字符流,然后再通过tokenier语法分析转换成机器能识别的标签文件,然后解析html构建dom树,再解析样式文件构建CSSOM树,再通过dom树跟CSSOM过滤掉不需要显示的标签及display为none的元素构建出渲染树,再计算渲染树每个元素的尺寸大小进行布局,最后通过层级顺序进行绘制(会有一个绘制记录表),后渲染到页面显示内容;

浏览器常见内核(渲染引擎):IE(trident)、Gecko(firebox)、Webkit(safrai)、Blik基于Webkit(chorm、Edge浏览器、Opera)

8.什么是闭包?闭包的优缺点

闭包是一个可以访问其他函数内部变量的函数。其存在的意义是产生一个可长久保存的局部变量,可解决全局变量被污染的问题,但也会由于变量未被及时回收造成内存泄漏。

9.事件循环机制?常见宏任务、微任务?输出下面代码打印顺序

async function async1() {
     console.log('async1')  
}
async function async2() {
   console.log('async2 start')
   await async1();
   console.log('async2 end')
}
setTimeout( () => {
   console.log('setTimeout')
},  0);
new Promise(function(resolve){
    console.log('promise1')
   resolve('ces')
}).then(function(){
    console.log('promise1-then')
})
async2();
new Promise(function(resolve){
    console.log('promise2')
   resolve('ces')
}).then(function(){
    console.log('promise2-then')
})
// 遇到setTimeout属于宏任务 存放到宏任务队列 setTimeout1;
// new Promise构造函数立即执行 输出promise1且then方法存放到微任务队列 promise1;
// async2相当于new Promise,所以输出 async2 start,await后面其实是跟一个promise对象,若不是则自动转换,输出async1,同时await会暂停执行异步函数后面的代码;
// new promise立即执行 输出promise2,then接着存放到微任务队列;
// 主线程任务执行完,从微任务队列调用执行,先执行promise1输出promise1-then;
// 再执行async2的返回结果,输出async2-end;
// 再执行第二个then微任务,输出promise2-then;
// 微任务执行完毕,执行宏任务setTimeout输出setTimout;

// promise1,async2 start,async1,promise2,promise1-then,async2-end,promise2-then,setTimeout

11.Promise、async、await

promise是es6出现的,用来解决异步请求中地狱回调的问题。而async、await是es8提出的异步函数,让以同步方式写的代码可以异步执行,相对于promise更加简洁。await必须在async内部使用,async默认返回一个promise对象,若不是则自动转换为promise对象,也即是await后面跟一个promise对象。

12.this作用域问题、apply/call/bind区别

全局上下文浏览器中指window对象,所有通过var定义的变量和函数都会成为window对象的属性和方法;

每个函数调用都有自己的上下文,当代码执行流进行函数时,函数的上下文被推入一个上下文栈中,当函数执行完后,上下文栈会弹出该函数执行上下文,将控制权还给之前的执行上下文;

作用域链决定了上下文的执行顺序,内部上下文能访问外部上下文中的属性方法,反之则不能;

this作用域问题主要涉及全局上下文作用域跟局部上下文作用域。apply、call、bind都可以用来改变this指向问题,apply多个参数时数组传递,call多个参数时逗号分隔,bind多个参数时可逗号分隔也可数组;apply/call都是对函数直接调用,而bind返回的仍然是一个函数,需另外加()进行调用;

13.let、const、var区别?js是如何支持块级作用域的?

var定义全局变量,可重复声明,存在变量提升;

let、const定义局部变量,不能重复声明且不存在变量提升。const声明时必须同时赋值;

js中var定义的变量被加入到变量环境,块作用域变量会被添加到一个栈结构的词法环境中且每个作用域块中的变量都有一个独立的栈数据中,当访问变量时,先从词法环境中的栈顶查找,若没查到则继续向下查找,并将栈顶元素弹出,若整个词法环境中都无该变量,则向变量环境中查找;

14.数据类型的判断?typeof及instanceof的原理

typeof主要用来判断基本数据类型,返回字符串;

[] instanceof Array可用来判断引用数据类型,返回布尔值;

Object.prototype.toString.call()返回字符串;

typeof原理:js在底层存储变量时,会在变量机器码的低位1-3位来存储变量的类型信息;

null所有机器码均为0,undefined用-2^30整数表示;所以在判断null类型时会返回object;

instanceof原理:只要右边的变量在左边的原型链上即返回true;主要用于判断某个实例是否属于某个类型;

// 判断rightValue的prototype是否在leftValue的原型链上
function instanceof(leftValue, rightValue) {
      const rightProto = rightValue.prototype; // 右边表达式的prototype
      leftValue = leftValue.__proto__; // 左边表达式的__proto__
      while(true) {
         if (leftValue === null) return false;
         if (leftValue === rightProto) {
             return true;
         }
         leftValue = leftValue.__proto__;
      }
}

15.new一个对象的过程

  1. 在内存中创建一个对象;

  2. 该对象内部有一个proto指针指向构造函数的prototype属性;

  3. 构造函数内部的this指向该对象;

  4. 执行构造函数内部代码(给新对象添加属性),若构造函数返回一个非空对象,则返回该对象否则返回新创建的对象; 

16.前端性能优化

精灵图(雪碧图)、静态资源引用第三方CDN库、图片js文件等压缩合并、使用缓存、懒加载、减少对dom的操作等;

17.localStorage、sessionStorage、cookie区别

localStorage本地持久化存储,除非手动清除,存在跨域问题,相同域名下方可共享数据;

session回话式存储,大小为5M,会话关闭数据清除,不同标签页不可共享session数据;

cookie大小仅为4k;

18.请求中cookie常见的属性值有哪些

name、token、domain、maxAge(失效时间)、size(cookie大小)、value、http字段(cookie的httppOnly属性)、secure(设置是否只能通过https传递该cookie)

19.编码解码

20.unicode与utf-8

unicode其实属于一种字符集编码规则的标准;

刚开始ASCll字符集出现,规定一个字符由一个字节(8个比特位表示)0~127,这样仅能标识数字、字母、控制符总共128个字符,不能做到全国统一;后面国内出现了gbk、gb2312能够表示更多字符,其他国家也制定其国家的标准,但是这样仍存在沟通间乱码的问题,仍不能解决统一问题;

后续提出unicode标准,采用usc-2字符集,一个字符由两个字节表示,能表示128*128更多的字符,但仍不能涵盖所有的字符,后又提出usc-4字符集,一个字符由4个字节表示,表示的字符范围更加广泛,但同时也造成了存储空间资源的浪费(一个数字或者一个字母本身只需要8位表示即可,却需要补24个0),所以当时unicode并不是所有人支持;

后面出现了utf-8,采用8位来传输数据,且长度可变,一般由1-4个字节表示字符;

若一个字符只需要一个字节的话(0-127) 0XXXXXXX,若需要两个字节(128-2047)110XXXXX10XXXXXX, 三个字节的话1110XXXX10XXXXXX10XXXXXX,即第一个字节的前n位为1,n+1位为0,其余字节10开头,其他位置将unicode码转换成二进制从右往左填充即可;

21.nextTick原理及适用场景

若需要对更新后的视图进行操作则可用到nextTick(微任务);

22.深拷贝与浅拷贝?分别有哪些实现方式?编码实现深拷贝

深拷贝浅拷贝主要是针对引用类型数据;assign、splice(数组里面存在嵌套时)、直接赋值(引用类型时)、clone都属于浅拷贝;cloneDeep、JSON.parse(JSON.stringify())、递归等深拷贝;

function cloneDeep(a) {
    let result = {};  // 判断是否为引用类型 
    function isObject(data) {
        if ((typeof data === 'object' || typeof data == 'function') && data !== null) return true;
        else return false;
    }  // 如果为数组,则更改result数据类型  if (Array.isArray(data)) result = [...data];
   for(let key of a) {
       if(a.hasOwnProperty(key)) {
            if (isObject(a[key])]) {
                 result[key] = cloneDeep(a[key])
            } else {
                 result[key] = a[key]
            }
       }
   }  return result;
}

23.实现盒子水平居中有哪些方式

绝对定位3种: left/right/bottom/top均为0,margin为auto; left/top为50%,transform: translate(50%) 兼容性问题; left/top为50%,margin-top/margin-left为高度/2;

flex布局:justify-content/align-items

table-cell布局

24.什么是bfc?如何触发bfc?

bfc其实就是一个独立的渲染区域,bfc盒子不受外界影响;

触发bfc:


一个根元素html/body就是一个bfc;

overflow不为visible;

float不为nonedisplaytable-cell、inline-block;

position为absolute、fixed;

bfc使用场景:

  1. 两个盒子边距重叠取最大值的问题;

  2. 清除浮动;

25.清除浮动的方式

  1. 父容器设置高度;

  2. 设置overflow:hidden;(利用bfc)

  3. 在浮动元素后添加空标签并设置clear:both(利用闭合思想,闭合出口入口,不让盒子溢出);

  4. 父元素添加:after或者:after、:before伪元素;

26.css常见的选择器及优先级

!important > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通配符选择器 > 继承 > 浏览器默认

27.webpack中loader与plugin的区别?loader的加载顺序?chunk? url-loader与babel-loader的区别

webpack是一个js应用程序的静态模块打包器;有四个核心概念: 入口(entry)、出口(output)、loader、插件plugins;从webpack4.0开始可以不用引入一个配置文件(存在默认配置),但它本身仍然是高度可配置的;

loader可以让webpack去处理非js的文件(webpack自身只理解JavaScript)。loader可以将所有类型的文件转换成webpack能够处理的有效模块,然后就可以利用webpack的打包能力进行处理;本质上,webpack loader将所有类型的文件转换为应用程序依赖图可以直接引用的模块。

在更高层面上,webpack loader有两个目标:

test属性:用于标识出应该被对应loader进行转换的某个或某些文件;

use属性:表示进行转换时,应该使用哪个loader;

loader的加载顺序与书写顺序相反,采用compose从右往左的编程思想;

chunk: chunk是webpack打包过程中,一堆module的集合;webpack从一个入口文件即入口模块开始,入口模块在引用其他模块,模块再引入用模块。webpack沿着引用关系逐个打包模块,这些moudle就形成了一个chunk。如果有多个入口文件,将产生多条打包路径,一条路径就会形成一个chunk。大多情况下,一个chunk产生一个bundle;

产生chunk的途径:
entry入口、异步加载模块、代码分割

entry配置为字符串或数组时仍只会产生一个chunk,对象类型时,一个字段就产生一个chunk;(注意产生多个chunk时,output中filename不能写死,否则报错);

file-loader用来将图片、字体、媒体等文件进行打包的,webpack遇到图片文件模块时会找到对应的file-loader进行打包,file-loader首先将图片文件移动到打包出口文件下,并生成一个hash随机数作为图片名称,最后将打包后的图片名称返回给require函数;url-loader与filter-loader功能类似,一般配合使用,当文件大小小于限制值,则返回base64编码,否则交给file-loader将文件移动到出口文件下;

babel-loader为了js代码能更好的兼容各种环境,默认只会将ES6/7/8JS语法转换为ES5语法,但不能对新的api进行转换(set、map、promise、async、generator等),需要借助于babel-polyfill(它是在源代码运行前执行的,我们需要让它成为一个线上依赖,而不是dev依赖,且需要在入口顶部引入,保证它在其他任何代码/依赖声明前被调用);@babel/preset-env根据指定的执行环境进行转换;

优化webpack打包:

  1. 设置mode。如果不设置的话,会默认生产环境production会进行tree shaking(去除无用代码)、uglifyjs(代码压缩混淆);

  2. 缩小文件搜索范围。

可以设置alias别名,不设置的话webpack会采用向上递归的方式一层层查询,egL: import vue from vue 会从node_modules中递归查找,设置别名后, webpack会从指定路径开始查找;

配置include、exclude也可以减少loader搜索转换时间;

设置noParse.当我们引用一些依赖时,eg:Jquery webpack会先解析该库是否依赖其他包,但我们对于jquery这类依赖,一般认为不会引用其他包,增加noParse属性,可以告诉webpack不必解析,以此增加webpack打包速度;

设置extensions。webpack会根据设置的extensions定义的后缀去查找文件;

  1. 使用HappyPack开启多进程loader转换

由于js单线程,loader只能一个一个文件进行转换及压缩。HappyPack的基本原理将这部分任务分解到多个子进程中并发执行,最后把结果发送到主线程,减少总的构建时间;

  1. 使用webpack-parallel-uglify-plugin优化代码压缩时间;

  2. 第三方模块抽离

  3. 配置缓存cache-loader(loader没有内置cache时)

28.TCP、UDP区别?三次握手、四次挥手

29.原型及原型链

30.谈谈对css盒子模型的理解

31.vue的数据双向绑定原理?vue中的key作用?vue中diff算法的理解?vue中的computed与watch的区别?

32.元素绑定及销毁事件的方式有哪几种?各有什么区别

33.request-header请求头中有哪些配置项

34.函数防抖与节流的区别及实现

35.MVC与MVVM、MVP之间的区别

36.vue的生命周期?vue中的data为什么是一个函数?

37.箭头函数与普通函数区别

38.事件委托

39.vue-router路由模式及原理

40.keep-alive实现原理

41.vuex几大核心属性

42.输出下面打印结果

var  a = 10;
var obj = {
    a: 20,
    say: () => {
        console.log(this.a)
    },
    anotherSay() {
        console.log(this.a)    
    }      
}
obj.say(); // 10 箭头函数无this 向外找
var anotherSay = obj.anotherSay(); // 20 函数作用域
obj.say.call(anotherSay, 30) // 10 箭头函数不能改变this指向 所以仍为10

算法题

1.编码实现数组扁平化

2.编码实现数组全排列

3.编码将数字转换为金钱格式

eg:121313331 -> 121,313,331

4.解析url中参数并将中文解码且如果参数key重复,则将值合并到数组中

eg: https://www.cnblogs.com/test.html?id=1&id=2&name=%E6%B5%8B%E8%AF%95&age=18

结果为:{ id: [1, 2], name: '测试', age: 18}

5.计算字符串中无重复字符的最大长度

eg:asdadafjkldw -> dafjkldw无重复的最大字符串 长度为8