前端面试题整理

前端面试题

1. JS 作用域和作用域链

作用域

作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同,表示的执行环境的对象也不一样。

  • 在 Web 浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为 window 对象的属性和方法创建的
  • 在 Node 环境中,全局执行环境是 global 对象。

某个执行环境中所有的代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)。
每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将被环境弹出,把控制权返回给之前的执行环境。ECMAScript 程序中的执行流正是由这个方便的机制控制着。
作用域就是代码执行开辟栈内存。

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)。

  • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象。
  • 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境。
  • 全局执行环境的变量对象始终都是作用域链上的最后一个对象。

内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。
如函数的执行,形成一个私有作用域,形参和当前私有作用域中声明的变量都是私有变量,保存在内部的一个变量对象中,其下一个外部环境可能是函数,也就包含了函数的内部变量对象,直到全局作用域。
当在内部函数中,需要访问一个变量的时候,首先会访问函数本身的变量对象,是否有这个变量,如果没有,那么会继续沿作用域链往上查找,直到全局作用域。如果在某个变量对象中找到则使用该变量对象中的变量值。
由于变量的查找是沿着作用域链来实现的,所以也称作用域链为变量查找的机制。
这个机制也说明了访问局部变量要比访问全局变量更快,因为中间的查找过程更短。但是 JavaScript 引擎在优化标识符查询方面做得很好,因此这个差别可以忽略不计。

2. 首屏优化

首屏优化分为两大方向:资源加载优化 和 页面渲染优化。
压缩资源,使用 CDN ,http 缓存等。

路由懒加载

把不同路由对应的组件分割为不同的代码块,当路由被访问的时候,再加载对应的组件。
如果是SPA(单页面应用),优先保证首页加载。
SPA 是一种特殊的 Web 应用,是加载单个 HTML 页面并在用户与应用程序交互时动态更新该页面的。它将所有的活动局限于一个 Web 页面中,仅在该 Web 页面初始化时加载相应的 HTML 、 JavaScript 、 CSS 。一旦页面加载完成, SPA 不会因为用户的操作而进行页面的重新加载或跳转,而是利用 JavaScript 动态的变换 HTML(采用的是 div 切换显示和隐藏),从而实现UI与用户的交互。在 SPA 应用中,应用加载之后就不会再有整页刷新。相反,展示逻辑预先加载,并有赖于内容Region(区域)中的视图切换来展示内容。

服务端渲染SSR

服务端渲染(SSR)后,简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。渲染时请求页面,返回的body里已经存在服务器生成的html结构,之后只需要结合css显示出来。这就节省了访问时间和优化了资源的请求。
传统的 SPA 方式过程繁多:

  • 下载 html ,解析,渲染
  • 下载 js ,执行
  • ajax 异步加载数据
  • 重新渲染页面

而 SSR 则只有一步:

  • 下载 html ,解析,渲染
分页

根据显示设备的高度,设计尽量少的页面内容。即,首评内容尽量少,其他内容上滑时加载。

图片lazyLoad

先加载内容,再加载图片。

3. JS事件循环

一、在了解js的事件循环之前,我们先了解一下浏览器的任务线程
在浏览器执行各种进程,浏览器是多进程,每一个浏览器的标签都可以都可以理解为一个多进程的任务进程,浏览器渲染进程属于进程中的一种,主要负责,页面渲染,脚本执行,任务处理,那么线程大概有:(html的结构解析,css解析成dom树,),js脚本的主线程,事件触发线程,定时器线程,http线程。

二、关于事件循环
虽然说js是一个单线程执行,但是还是分为同步和异步,也可以说为主线程,和异步线程,那么如果在异步线程中,任务队列绝对起到绝对重要的作用,同步任务一般都会在主线程去执行,执行完之后,再去执行异步任务,也就是在异步线程,那么这时候异步任务就可以进入任务队列去执行异步任务,上诉不断地过程,让我们叫做循环事件(Event loop)。

三、关于宏任务和微任务
在事件循环中,每进行一次循环操作称为tick,通过阅读规范可知,每一次 tick 的任务处理模型是比较复杂的,其关键的步骤可以总结如下:
1.在此次 tick 中选择最先进入队列的任务( oldest task ),如果有则执行(一次)
2.检查是否存在 Microtasks ,如果存在则不停地执行,直至清空Microtask Queue
3.更新 render
4.主线程重复执行上述步骤

规范中规定,task分为两大类, 分别是 Macro Task (宏任务)和 Micro Task(微任务), 并且每个宏任务结束后, 都要清空所有的微任务,这里的 Macro Task也是我们常说的 task

宏任务:script( 整体代码),setTimeout,setInterval,UI交互事件

微任务:promise,nextTick

4. 线程和进程是什么?

进程:cpu分配资源的最小单位(是能拥有资源和独立运行的最小单位)。
线程:是cpu最小的调度单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)。
栗子:比如进程=火车,线程就是车厢。
一个进程内有多个线程,执行过程是多条线程共同完成的,线程是进程的部分。
一个火车可以有多个车厢。
每个进程都有独立的代码和数据空间,程序之间切换会产生较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。

为什么js是单线程

JS是单线程的原因主要和JS的用途有关,JS主要实现浏览器与用户的交互,以及操作DOM。
如果JS被设计为多线程,如果一个线程要修改一个DOM元素,另一个线程要删除这个DOM元素,这时浏览器就不知道该怎么办,为了避免复杂的情况产生,所以JS是单线程的。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

5. js中的基础数据类型有哪几种? 了解包装对象吗?

六种,string, number, boolean, undefiend, null, symbol
基础数据类型临时创建的临时对象,称为包装对象。其中 number、boolean 和 string 有包装对象,代码运行的过程中会找到对应的包装对象,然后包装对象把属性和方法给了基本类型,然后包装对象被系统进行销毁。

6. 对内存泄漏的了解

一、理解

  • 定义:程序中已在堆中分配的内存,因为某种原因未释放或者无法释放的问题
  • 简单理解: 无用的内存还在占用,得不到释放和归还,比较严重的时候,无用的内存还会增加,从而导致整个系统卡顿,甚至崩溃。

二、生命周期

  1. 分配期
    分配所需要的内存,在js中,是自动分配的。
  2. 使用期
    使用分配的内存,就是读写变量或者对象的属性值。
  3. 释放期
    不需要时将该内存释放,js会自动释放(除了闭包和一些bug以外)。内存泄漏就是出现在这个时期,内存没有被释放导致的。

三、可能出现内存泄漏的原因

  1. 意外的全局变量
  2. DOM元素清空时,还存在引用
  3. 闭包
  4. 遗忘的定时器
如何优化内存泄漏?
  • 全局变量先声明在使用。
  • 避免过多使用闭包。
  • 注意清除定时器和事件监听器。

7. HTTP与HTTPS的区别

HTTP(HyperText Transfer Protocol:超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。HTTP 默认工作在 TCP 协议 80 端口,用户访问网站 http:// 打头的都是标准 HTTP 服务。HTTP 协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
HTTPS(Hypertext Transfer Protocol Secure:超文本传输安全协议)是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
HTTPS 默认工作在 TCP 协议443端口,它的工作流程一般如以下方式:
1、TCP 三次同步握手
2、客户端验证服务器数字证书
3、DH 算法协商对称加密算法的密钥、hash 算法的密钥
4、SSL 安全加密隧道协商完成
5、网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改。

区别
  • HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
  • 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
  • http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
  • HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

8. 数组排序及去重

一、简单的sort排序:

var arr = [1,5,3,87,23];
arr.sort(function(a,b) {
    return a-b;
})
console.log(arr); // 输出:[1,23,3,5,87]
注:若返回b-a可获得从大到小的排序;
数组的sort方法只能实现简单的按位排序,并不精确。

二、冒泡排序

var arr = [1,5,2,6,3,3,4,56,7,5,5,5,6,7,8];

function fn(arr) {   //冒泡排序(以从小到大为例)
    for(var i=0;i arr[j+1]) {  
                var temp = arr[j];  //交换这两个值的位置
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    return arr;
}

三、选择排序

function fn(arr) { //选择排序
    //用这个数分别和别的数相比较,改变的是索引的位置,每轮结束后才交换为位置
    for(var i=0; iarr[j]) {
                minIndex = j;  //改变最小索引的指向
            }
        }
        var temp = arr[i];   //每轮比较结束,将最初假定的最小值和实际最小值交换
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;  //将排序后的数组返回
}

9. 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

当发送一个URL请求时,不管这个URL是web页面URl还是Web页面上每个资源的URL,浏览器都会开启一个线程来处理这个请求,同时在远程DNS服务器上启动一个DNS查询。这能使得浏览器得到请求对应的IP地址。
浏览器与远程web服务器通过TCP三次握手协商来建立一个TCP/IP连接,该握手包括一个同步报文,一个同步-应答报文和一个应答报文。这三个报文在浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,然后服务器相应并接受客户端的请求,最后由客户端发出该请求已被接受的报文。
一旦TCP/IP连接建立,浏览器会通过该连接向远程服务器发送HTTP的GET请求。远程服务器找到资源并使用HTTP相应返回该资源。

10. http缓存

http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力。

强缓存

在 Chrome 中,强缓存又分为 Disk Cache (存放在硬盘中)和 Memory Cache (存放在内存中),存放的位置是由浏览器控制的。是否强缓存由 Expires、Cache-Control 和 Pragma 3 个 Header 属性共同来控制。

  • Expires
    Expires 的值是一个 HTTP 日期,在浏览器发起请求时,会根据系统时间和 Expires 的值进行比较,如果系统时间超过了 Expires 的值,缓存失效。由于和系统时间进行比较,所以当系统时间和服务器时间不一致的时候,会有缓存有效期不准的问题。Expires 的优先级在三个 Header 属性中是最低的。
  • Cache-Control
    Cache-Control 是 HTTP/1.1 中新增的属性,在请求头和响应头中都可以使用,常用的属性值如有:

    • max-age:单位是秒,缓存时间计算的方式是距离发起的时间的秒数,超过间隔的秒数缓存失效
    • no-cache:不使用强缓存,需要与服务器验证缓存是否新鲜,进入协商缓存
    • no-store:禁止使用缓存(包括协商缓存),每次都向服务器请求最新的资源
    • private:专用于个人的缓存,中间代理、CDN 等不能缓存此响应
    • public:响应可以被中间代理、CDN 等缓存
    • must-revalidate:在缓存过期前可以使用,过期后必须向服务器验证
  • Pragma(优先级高)
    Pragma 只有一个属性值,就是 no-cache ,效果和 Cache-Control 中的 no-cache 一致,不使用强缓存,需要与服务器验证缓存是否新鲜,在 3 个头部属性中的优先级最高。

协商缓存

  • ETag/If-None-Match(优先级高)
    首次请求的时候响应头会返回一个,ETAG,内容是一串hash值,此时刷新之后,发现状态码变成304,此时的请求头上会有一个If-None-Match属性,内容与上次请求的ETAG值一样。即通过对比两个属性的值。
  • Last-Modified/If-Modified-Since(有时间精度问题,或者文件修改,但内容没改,就不会走缓存)
    Last-Modified/If-Modified-Since 的值代表的是文件的最后修改时间,第一次请求服务端会把资源的最后修改时间放到 Last-Modified 响应头中,第二次发起请求的时候,请求头会带上上一次响应头中的 Last-Modified 的时间,并放到 If-Modified-Since 请求头属性中,服务端根据文件最后一次修改时间和 If-Modified-Since 的值进行比较,如果相等,返回 304 ,并加载浏览器缓存。
缓存位置(优先级从高到低)
  • Service Worker
    借鉴了Web work的思路 让JS 运行在主线程之外
  • Memory Cache
    内存缓存 效率快 存活短 渲染进程消失就结束。比较大的js css文件放进这里。
  • Disk Cache
    磁盘缓存 比内存缓存慢 但是储存容量大和储存时长长。小的js css放这里。内存使用率偏高的时候文件优先进入这里。
  • Push Cache
    http2的内容
本地存储
  • Cookie
    cookie的诞生是为了弥补http管理状态上的不足。缺陷:容量小。紧跟域名,同域情况下,无论当前地址是否需要,请求都会带上,当请求变多很影响性能。安全问题cookie能被获取到,然后修改发给服务器。
  • LocalStorage
    同样紧跟域名;容量大(5M);不接触服务器;永久会话,除非手动删除;通过setItem、getItem手动获取、设置。
  • sessionStorage
    基本同local,但是针对服务器,会话级别,关闭页面就没了。一般用于form表单,刷新页面后缓存表单的值。

你可能感兴趣的:(前端)