前端面试问题汇总(不断更新)

一、前端面试问题汇总

1.判断js中对象的字节数

第一种:
npm install object-sizeof
var sizeof = require(‘object-sizeof’) // 2B per character, 6 chars total => 12B console.log(sizeof({abc: ‘def’}))

第二种:
https://www.cnblogs.com/sefaultment/p/11518625.html

2.js中number分浮点和整数吗?

不分,全是64位浮点数,单精确度(32位 1 8 32 )、双精确度(64位 1 11 52)

3.js怎么打印出对象中的循环引用串

一个 JSON 扩展包 做到了这一点, 使用 JSON.decycle

4.进程和线程的区别

线程在进程下行进(单纯的车厢无法运行)
一个进程可以包含多个线程(一辆火车可以有多个车厢)
不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)

5.进程线程通信方式与问题

管道:速度慢,容量有限,只有父子进程能通讯

FIFO:任何进程间都能通讯,但速度慢

消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

信号量:不能传递复杂消息,只能用来同步

共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存

6.宏任务微任务

宏任务:定时器
微任务:promise
先执行全局同步任务,然后执行微任务然后宏任务(有不同层级)

7.盒模型

类型:block\inline\flex,属性:margin\border\padding\content
block:默认一个盒子一行,h,p等都是block盒子
inline:width、height不起作用,垂直边距不会把其他盒子推开,水平的会,a,em,span
flex:对外显示block,对内部盒子为flex类型

标准盒模型:设置的宽高为content的宽高(默认)
IE盒模型:设置的宽高为content+padding+border通过box-sizing: border-box;转换为IE模型

8.隐藏元素的几种方法

overflow:hidden; /* 占据空间,无法点击 */overflow的hidden用来隐藏元素溢出部分,占据空间,无法响应点击事件

opacity:0;/* 占据空间,可以点击 */透明度降为0

visibility:hidden; /* 占据空间,无法点击 */隐藏元素,这个是彻底的隐藏了元素,不占据空间,也就不影响布局,当然也无法响应事件

position:relative; left:-99999px; top:-90999px;/* 占据空间,无法点击 */

z-index:-1000;/* 不占据空间,无法点击 */让其他元素遮挡住

9.rem布局

根据根元素(html)字体大小,如:html的font-size=10px,2rem为20px
加上媒体查询@media screen and (min-width: 375px),设置不同的font-size
存在的问题:人们对于文字的舒适度,字体大小大概是绝对的

10.BFC-不会影响外部的盒子

产生条件:
body 根元素浮动元素
float 除 none 以外的值绝对定位元素
position (absolute、fixed)
display 为 inline-block、table-cells、flex
overflow 除了 visible 以外的值 (hidden、auto、scroll)

产生的问题:
上下盒子边距会重叠,解决:变成两个BFC
BFC内部有浮动的盒子会高度塌陷,解决:父盒子添加overflow:hidden清除浮动

11.es6

let,const,map,set,promise,箭头函数,async,await,解构,class,import from,export

12.箭头函数普通函数区别

this指向,不加大括号默认return,一个参数可以不加小括号,无构造函数因为没有prototype,无arguments
普通函数想不发生this的改变需要bind

13.上下文与执行栈

全局上下文在栈底,每当调用一个函数就创建一个上下文入栈,函数执行完毕销毁出栈

14.webpack loader和plugin的区别,分别用过哪些

loader转换指定类型的模块功能,plugins能够被用于执行更广泛的任务比如打包优化、文件管理、环境注入

css-loader和style-loader模块是为了打包css的,less-loader

babel-loader和babel-core模块时为了把ES6的代码转成ES5

url-loader和file-loader是把图片进行打包的

15.模块化

es6,import,export,每个文件就是一个模块

16.代码规范:eslint

17.http与https

http2(80):

二进制保存信息,为将来的高级应用打好基础,因为可以定义其他类型的帧

多工:客户端,服务器可以同时发送多个数据请求或回应

头部信息压缩,速度更快

服务器主动推送,发现网页中需要的资源,主动推送

明文传输,不加验证,无状态,超文本传输协议

http3:协议改成了udp,但是开发人员加入了自己做的层加强了传输的可靠性,速度更快,延迟更低

https(443):

多了一层tsl、ssl加密(对称加密,非对称加密),ssl加密传输协议

18.网络安全

xss,csrf攻击?
中间人攻击?
如何防御?

19.状态管理的几种方法

redux,hooks,xstate,mobx等

20.水平垂直居中(宽高未知)

flex
transform

二、注意点

  1. 字符串和数字相加会自动字符串拼接,其他不会,如:

    1
    2
    "37" - 7 // 30
    "37" + 7 // "377"
  2. 字符串转化为数字
    parseInt(number,redix)和parseFloat(number,redix)
    将字符串转换为数字的另一种方法是使用一元加法运算符(+"1.1") + (+"1.1") = 2.2

  3. 进制

    1
    2
    3
    4
    0, 117 and -345 (十进制, 基数为10)
    015, 0001 and -0o77 (八进制, 基数为8)
    0x1123, 0x00111 and -0xF1A7 (十六进制, 基数为16"hex")
    0b11, 0b0011 and -0b11 (二进制, 基数为2)

    浮点数

    1
    2
    3
    4
    3.14
    -.2345789 // -0.23456789
    -3.12e+12 // -3.12*1012
    .1e-23 // 0.1*10-23=10-24=1e-24

    false

    1
    2
    3
    4
    5
    6
    false
    undefined
    null
    0
    NaN
    空字符串(""

    其他都是true,包括以下这种你可能认为是true的:

    1
    2
    3
    var b = new Boolean(false);
    if (b) //结果视为真
    if (b == true) // 结果视为假
  4. for in与for of
    简单来说前者遍历key,后者遍历value,但是又有不同,for of一般用来遍历数组index是数字的值,而自定义的数组元素不能遍历出,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let arr = [3, 5, 7];
    arr.foo = "hello";//key是自定义的foo

    for (let i in arr) {
    console.log(i); // 输出 "0", "1", "2", "foo"
    }

    for (let i of arr) {
    console.log(i); // 输出 "3", "5", "7"
    }
  5. map与object
    map: set,get,has,delete,clear,.size
    map的key可以是任意类型,object的key只能是string类型,不管什么类型都视为字符串
    map可以简单地获取尺寸
    weakmap,key是对象,对象内部的私有数据和方法被存储在WeakMap类型的privates变量中。所有暴露出的原型和情况都是公开的

  6. set与array

    1
    2
    3
    4
    5
    //set->array
    Array.from(mySet);
    [...mySet2];
    //array->set
    mySet2 = new Set([1,2,3,4]);

    array删除用splce(index,number),set删除用delete(value)

  7. 枚举对象的所有属性
    方法一:for…in 循环
    该方法依次访问一个对象及其原型链中所有可枚举的属性。
    方法二:Object.keys(o)
    该方法返回对象 o 自身包含(不包括原型中)的所有可枚举属性的名称的数组。
    方法三:Object.getOwnPropertyNames(o)
    该方法返回对象 o 自身包含(不包括原型中)的所有属性(无论是否可枚举)的名称的数组。

  8. 网页自适应
    方法一:网页头部加上<meta name="viewport" content="width=device-width, initial-scale=1" />
    解释:网页宽度默认等于屏幕宽度(width=device-width),原始缩放比例(initial-scale=1)为1.0,即网页初始大小占屏幕面积的100%
    方法二:如无必要不要用绝对尺寸px,用百分比,字体用em,rem
    方法三:流动布局float
    方法四:flex布局
    方法五:媒体查询的方式用不同的css
    如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .example {
    padding: 20px;
    color: white;
    }
    //屏幕分辨率小于600红色背景
    @media screen and (max-width: 600px) {
    .example {background: red;}
    }

    //屏幕分辨率大于600绿色背景
    @media screen and (min-width: 600px) {
    .example {background: green;}
    }

    方法六:图片自适应
    img { max-width: 100%;}

  9. try-catch 能抛出 promise 的异常吗
    不能,因为promise是异步任务,已经放入了异步任务队列

  10. 面向对象的三大基本特征
    一、封装,就是将客观事物抽象为逻辑实体,实体的属性和功能相结合,形成一个有机的整体
    二、继承,在继承机制下形成有层级的类,使得低层级的类可以延用高层级类的特征和方法
    三、多态,是指一个类的同名方法,在不同情况下的实现细节不同

  11. 接口和类区别
    接口值加类型定义,有什么,不实现
    类实现

  12. ts不能多继承,只能继承一个类,但是可以a继承b,b继承c,接口可以多继承

  13. js操作dom
    获取节点
    getElementById主义只有一个
    getElementsByClassName
    getElementsByTagName
    getElementsByName
    querySelector选择第一个,class为.classname,id为#idname,,tag为tagname

    1
    2
    <input name="login"/>)
    var el = document.querySelector("input[name='login']");

    querySelectorAll选出所有
    以上直接后面跟上(‘a’)的形式即可。
    创建节点
    createElement创建元素,如:

    1
    2
    3
    4
    5
    var elem = document.createElement("div");  
    elem.id = 'haorooms';
    elem.style = 'color: red';
    elem.innerHTML = '我是新创建的haorooms测试节点';
    document.body.appendChild(elem);

    修改节点
    appendChild—添加到末尾,如parent.appendChild(child);
    如果在节点树已存在,则删除该节点,再放到新的位置
    insertBefore—parentNode.insertBefore(newNode, wantNode);

removeChild—var deletedChild = parent.removeChild(node);
节点属性
.attributes返回节点所有属性数组
getAttribute()返回该属性的值

  1. 页面加载前的白屏如何处理
    项目写一个静态页面,等加载完成后在跳转到真正的路由
    预渲染、骨架图

  2. 性能优化
    一、分页列表显示,不用请求全部数据,请求当页需要展示的数据就好。
    二、适当使用PureComponent/ShouldComponentUpdate/React.memo(函数组件),但是注意这是浅比较
    三、useMemo,避免复杂计算浪费性能
    四、懒加载 需要的时候再去加载
    五、父级没有什么用处时,可以用<>,这样没有额外的标记,减少浏览器的额外渲染
    六、不要写内联函数,否则每次渲染都会重新创建该函数并绑定
    七、避免内联样式,这会需要额外的渲染和处理
    八、慎重处理条件渲染,安装与卸载很费性能,基于diff策略
    九、render是纯函数,不要改变状态,否则会循环渲染
    十、列表内容渲染加独一无二的key,避免用默认的index作为key
    十一、防抖和节流
    十二、使用cdn
    十三、可以用css或html处理不用js
    十四、服务器端预加载
    实例

  3. for in for of
    for in遍历key,包括原型上的都可以遍历出来,适用于对象
    不想遍历出原型,可以用hasOwnProperty或者Object.keys
    for of遍历value,适用于数组

  4. 图片懒加载
    思路:图片未进入到可视区域时,先把图片地址保存在自定义属性上,等图片进入到可视区域再把真正的地址给到scr属性。
    实现:看着一个代码就够

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <script>
    // 获取所有的图片标签
    const imgs = document.getElementsByTagName("img");
    // 获取可视区域的高度,兼容浏览器
    const viewHeight = window.innerHeight || document.documentElement.clientHeight;
    // num用于统计当前显示到了哪一张图片,避免每次都从第一张图片开始检查是否露出
    let num = 0;

    function lazyload() {
    console.log("滚动...");
    for (let i = num; i < imgs.length; i++) {
    // 用可视区域高度减去元素顶部距离可视区域顶部的高度
    let distance = viewHeight - imgs[i].getBoundingClientRect().top;
    // 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出
    if (distance >= 0) {
    // 给元素写入真实的src,展示图片
    imgs[i].src = imgs[i].getAttribute("data-src");
    // 前i张图片已经加载完毕,下次从第i+1张开始检查是否露出
    num = i + 1;
    }
    }
    }

    // 防抖函数
    function debounce(fn, delay = 500) {
    let timer = null;
    return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
    fn.call(this, args);
    }, delay);
    };
    }

    // 是的页面初始化是加载首屏图片
    window.onload = lazyload;
    // 监听Scroll事件,为了防止频繁调用,使用防抖函数优化一下
    window.addEventListener("scroll", debounce(lazyload, 600), false);
    </script>
  5. Promise.all

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 封装 Promise.all方法
    Promise.all = function (values) {
    return new Promise((resolve, reject) => {
    let result = []; // 存放返回值
    let counter = 0; // 计数器,用于判断异步完成
    function processData(key, value) {
    result[key] = value;
    // 每成功一次计数器就会加1,直到所有都成功的时候会与values长度一致,则认定为都成功了,所以能避免异步问题
    if (++counter === values.length) {
    resolve(result);
    }
    }
    // 遍历 数组中的每一项,判断传入的是否是promise
    for (let i = 0; i < values.length; i++) {
    let current = values[i];
    // 如果是promise则调用获取data值,然后再处理data
    if (isPromise(current)) {
    current.then(data => {
    processData(i, data);
    }, reject);
    } else {
    // 如果不是promise,传入的是普通值,则直接返回
    processData(i, current);
    }
    }
    });
    }
  6. localStorage只要在相同的协议、相同的主机名、相同的端口下(相同域名下),就能读取/修改到同一份localStorage数据。
    sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。

上一篇

typescript用法