前端-自检清单

93 阅读18分钟

来源大前端面试宝典—前端自检清单

JavaScript

自检问题

  1. 什么是值?什么是类型?什么是变量? 它们之间的区别和联系
  2. 基本类型和引用类型的区别是什么?null 和 undefined 区别是什么?
  3. “一切皆对象”怎么理解? number 也是对象么?字符串也是对象么?
  4. 基础类型存放在栈上,引用类型存放在堆上,请问是为什么? 字符串是存放在栈上么?对象中有一个 number 属性,那么 number 属性是存放在堆上还是栈上?
  5. == 的判断逻辑是什么?
  6. 作用域的本质是什么?闭包和作用域的关系是什么?
  7. let,const,var 三者的本质不同是什么?为什么不推荐使用 var
  8. 数组的本质是什么,运用了什么样的设计模式?数组和对象的关系是什么?
  9. 原型链能够实现所谓的继承的本质原因是什么?
  10. 箭头函数是用来解决什么问题的?
  11. 什么是高阶函数?用处和用法?
  12. 什么是异步编程,为什么说它对 Web 开发很重要?

参考回答

1.什么是值?什么是类型?什么是变量? 它们之间的区别和联系?

值是数据;类型是数据的类型,包括基本类型和引用类型;变量是一个用于保存任意值的命名占位符;

2.基本类型和引用类型的区别是什么?null 和 undefined 区别是什么?

根据值是否具有不可变性(有固定的长度),将其类型划分为基本类型和引用类型。内存空间分为栈内存和堆内存:

栈内存:

  • 存储的值大小固定
  • 空间较小
  • 可以直接操作其保存的变量,运行效率高
  • 由系统自动分配存储空间

基本类型的值存储在栈内存当中,由于存储的值大小固定,因此具有不可变性。let num = 3; num = 5这并不代表值3变成了值5,而是在num = 5时,栈又开辟了新的空间存储值5,变量num指向了这片空间,这也叫按值传递(每次赋值给变量时,都会创建该值的副本)。

堆内存:

  • 存储的值大小不定,可动态调整
  • 空间较大,运行效率低
  • 无法直接操作其内部存储,使用引用地址读取
  • 通过代码进行分配空间

引用类型的值存储在堆内存中,他在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的值。可以轻易的这些值。let obj = {a:1}; let obj1 = obj; obj1.a = 3; console.log(obj.a) //3,其中let obj1 = obj定义一个变量obj1,并使用存储在obj变量中的地址来初始化obj1(这个地址也在内存中赋值了一份,两个地址共同指向{a:1}),这是一个引用传递。

undefined类型只有一个值undefined,表示已声明但未初始化变量的值。typeof(已声明但未初始化 / 未声明 的变量)返回的都是undefined(逻辑上表示都无法执行实际操作,虽然这两个变存在根本性差异);null类型只有一个值null,表示一个空对象指针,这也是typeof null返回object的原因(不同对象在底层都表现为二进制,js中二进制前3位都是0的话会被判断为object类型,null的二进制表示全都是0,,所以会有上面的bug);undefined 值是由 null 值派生而来的,ES3增加这个值的目的是为了明确空对象指针和未初始化变量的区别,console.log(null == undefined); // true

3.“一切皆对象”怎么理解? number 也是对象么?字符串也是对象么?

并非所有数据类型都是对象,基本类型都不是对象。之所有一些基本类型的值可以访问属性和方法,是因为引擎自动把字面量转化成js中的内置对象(如:String、Number、Boolean、Object、Function、Array、Date、Error、RegExp)

4.基础类型存放在栈上,引用类型存放在堆上,请问是为什么? 字符串是存放在栈上么?对象中有一个 number 属性,那么 number 属性是存放在堆上还是栈上?

因为基础类型在创建的时候已确定大小,而引用类型创建的时候无法确定大小?或由栈和堆的特点决定的,栈存值大小固定且效率高,而对空间大而运行效率低;

参考

字符串: 存在堆里,栈中为引用地址,如果存在相同字符串,则引用地址相同。

数字:小整数存在栈中,其他类型存在堆中。

其他类型:引擎初始化时分配唯一地址,栈中的变量存的是唯一的引用。

5.== 的判断逻辑是什么?

先将两个值进行强制类型转换,再确定操作符是否相等。

转换操作数的类型时,相等和不相等操作符遵循如下规则:

  • 如果一个操作数是布尔值,则将布尔值转换为数值再比较

  • 如果一个操作数是字符串,另一个是数值,则尝试将字符串转换为数值再比较

    • 注:布尔值和字符串都会使用Number()进行转换,Number()parseInt严格很多
  • 如果一个操作数是对象,另一个不是对象,则调用对象的valueOf()方法取其原始值再比较

    • toString()返回对象的字符串表示。valueOf()返回对象对应的字符串、数值或布尔值表示。通常与toString()的返回值相同。
      | 对象 | 返回值 | | --- | --- | | Array | 数组的元素被转换为字符串,这些字符串由逗号分隔,连接在一起。其操作与 Array.toString 和 Array.join方法相同。 | | Boolean | Boolean 值 | | Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC | | Function | 函数本身 | | Number | 数字值 | | Obejct | 对象本身,这是默认情况 | | String | 字符串值 |

进行比较时,相等和不相等操作符遵循如下规则

  • null和undefined相等
  • null和undefined不能转换为其他类型的值再进行比较
  • 如果一个操作数是NaN,则相等操作符返回false,即使另一个操作数是NaN
  • 如果两个操作数都是对象,则比较它们是不是同一个对象(指向同一个对象)。

全等相比于相等,不会进行类型转换,推荐使用,有助于在代码中保持数据类型的完整性。

6. 作用域的本质是什么?闭包和作用域的关系是什么?

参考

作用域是一套规则,规定了在运行时代码的某些特定部分中变量、函数和对象的可访问性。作用域链是作用域这套规则的实现。

JavaScript 属于解释型语言,JavaScript 的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

解释阶段:

  • 词法分析
  • 语法分析
  • 作用域规则确定

执行阶段:

  • 创建执行上下文
  • 执行函数代码
  • 垃圾回收

JavaScript 解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是 this 的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。

函数在调用激活时,会开始创建对应的执行上下文,在执行上下文生成的过程中,变量对象、作用域链、this的值会被分别确定。

在 fn 函数中,取自由变量 x 的值时,要到哪个作用域中取?——要到创建 fn 函数的那个作用域中取,无论 fn 函数将在哪里调用。

“无论函数是在哪里调用,也无论函数是如何调用的,其确定的词法作用域永远都是在函数被声明的时候确定下来的”

闭包使得作用域链上的变量对象不被垃圾回收机制回收,可以记住并访问所在作用域,因为嵌套函数(闭包)的引用被保留了

852b3116b4e04c479e93b7a528605dea_tplv-k3u1fbpfcp-watermark.png

7. let,const,var 三者的本质不同是什么?为什么不推荐使用 var

作用域规则:var声明的变量在函数作用域下有效,let和const声明的变量在块作用域下有效

变量提升:var声明的变量存在变量提升,let和const不存在

重复声明/赋值:var声明的变量可以重复声明和赋值,let和const不可以

let和const的区别:const声明变量时必须同时初始化,且变量的值不能改变

为什么不推荐使用var?var创建的变量都是挂载在顶级对象上面,重复定义会改变之前定义的值,会造成全局变量不可控,变量污染;重复声明不报错,代码不易维护。使用let和const,变量有了明确的作用域、声明位置和不变的值。

推荐使用const?可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。优先使用 const 来声明变量,只在提前知道未来会有修改时,再使用 let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。

8. 数组的本质是什么,运用了什么样的设计模式?数组和对象的关系是什么?

数组是特殊的对象,typeof arr // "object"

数组是特殊的对象,继承了对象原型的所有方法,但是多了作为数组原型的方法,例如push、pop等

9. 原型链能够实现所谓的继承的本质原因是什么?

依靠_proto_。构造函数的实例有一个_proto_属性指向构造函数的原型,当访问实例的属性时,如果在当前对象上找不到,就访问对象的_proto_,以此访问到了构造函数的属性,实现继承机制。

10. 箭头函数是用来解决什么问题的?

主要设计目的是以特定的方式改变this的行为特性,解决this相关编码的一个特殊而又常见的痛点。在箭头函数内部,this绑定不是动态的,而是词法的。箭头函数的this指向其所在的作用域的变量对象。

11. 什么是高阶函数?用处和用法?

高阶函数是一个将函数作为参数或者返回值的函数。例如map、filter。

12. 什么是异步编程,为什么说它对 Web 开发很重要?

js的需要长时间运行的代码,交给浏览器另一个线程去运行,运行完毕之后再添加到js的单线程中去运行,保证了js程序不堵塞。

浏览器

自检问题

  1. 事件模型
  2. 一文看懂浏览器事件循环
  3. 浏览器安全策略
  4. 事件循环
  5. BOM API
  6. Chrome 浏览器中的进程和线程

参考回答

1. 浏览器事件模型 参考

浏览器是事件驱动的,什么都抽象为事件。当一个事件发生的时候,浏览器会初始化一个事件对象,然后这个事件对象会按照事件传播机制进行传播。事件传播机制分为三个阶段,开发者可以选择监听不同的阶段,以达到目的。

事件代理是利用事件传播机制,将本来是子元素的事件处理函数,放到父元素上去。这样当子元素发生事件时,通过事件传播依然可以执行这个事件处理函数,即父元素代理了这个事件。这样做的好处是减少事件注册,节省内存占用;减少与DOM交互次数,提高性能。

事件循环就像是浏览器的调度器,决定v8什么时候执行什么代码。

image.png

v8:v8引擎的内存空间分为栈(执行栈)和堆

浏览器:浏览器提供了web API(包括DOM),和事件队列(任务队列)

view

宏任务:

  • script(整体代码)
  • setTimeout()
  • setInterval()
  • postMessage
  • I/O
  • UI交互事件

微任务:

  • new Promise().then(回调)
  • MutationObserver(html5 新特性)

注:全局代码属于宏任务

在v8引擎编译并执行js代码时,会将同步代码压入执行栈,执行代码时如果碰到异步事件,会将异步事件挂起(此时浏览器另一个线程会来处理这个异步事件),异步事件有了结果后将其放入事件队列,等待主线程中同步代码全部执行完,再把事件队列中的任务一个个放入执行栈执行。

只不过异步事件又分为宏任务和微任务,相应地事件队列分为宏任务队列和微任务队列,在将事件队列中的任务加入执行栈的时候,先把微任务执行了,再执行宏任务。

注:v8执行代码时,碰到函数,会有一个创建阶段,一个执行阶段。在创建阶段,v8会将当前函数的执行上下文压入执行上下文栈(此栈随着执行栈的销毁而销毁),执行上下文包括变量对象、作用域链、this的值。v8执行代码时,查询变量就到当前函数的执行上下文去找,找不到就沿着作用域链去找。而这个作用域链取决于静态作用域(在函数声明时就已经决定了),不管v8何时调用函数,要查找的变量只要还在执行上下文栈中就会被查找到。闭包的存在就使得它上一层的执行上下文保留下来了。

2. 浏览器安全策略

参考

  • BOM API
  • Chrome 浏览器中的进程和线程

参考

网络

自检问题

  1. WebSocket 工作在七层(或者四层)中的哪一层?和 HTTP 是什么关系? 是基于 UDP 的还是 TCP 的?
  2. TCP 为什么是三次握手?为什么是四次挥手?
  3. CDN 的工作原理是什么?
  4. 运营商劫持是什么?如何防范?
  5. HTTPS 一定是安全的么?如果不是,那么在什么情况下是不安全的?
  6. 如何劫持 HTTPS 请求。 比如你需要抓 HTTPS 的包,怎么做?
  7. 支付宝和微信的离线支付是怎么做的?
  8. Token 和 Cookie 有什么区别和联系呢?其分别是为了解决什么样的事情?
  9. WebSocket 需要 cookie 么?为什么?
  10. WebSocket 是怎么实现点对点通信和广播通信的?
  11. 如果访问你的 APP 很慢,你自己无法重现。 初步定位到网络问题, 那么你怎么能具体定位到问题呢?
  12. traceroute, Ping 的原理是什么?
  13. 192.168.0.1 和 192.168.1.1 如何通信?
  14. DNS 是如何泄漏个人隐私的?怎么防范?
  15. 从网络协议模型(七层 or 四层)的角度分析一下,浏览器访问 192.168.3.4:8088 的具体过程。

参考回答

1. WebSocket 工作在七层(或者四层)中的哪一层?和 HTTP 是什么关系? 是基于 UDP 的还是 TCP 的?

理清 WebSocket 和 HTTP 的关系WebSocket 教程

工作再应用层;WebSocket和HTTP都是基于TCP协议的两个不同的协议,WebSocket依赖于HTTP连接;基于TCP

2. TCP 为什么是三次握手?为什么是四次挥手?

TCP三次握手才能保证双方都有发送和接受信息的能力,若是两次握手,客户端或许因为网络堵塞等原因放弃这个连接了,此时服务器还以为他自己发出确认请求后连接就建立了,为其分配内存之类的,白白浪费很多资源。

TCP关闭连接时,服务器要响应客户端的关闭请求,但此时服务器端的数据可能还没有传完,只好先发送一个确认ask包,等自己数据传输完了再发送一个fin包,这样就有了两次挥手,而不是三次握手一样,将一次握手和确认合并在一起l

3. CDN 的工作原理是什么?

CDN的工作原理是将源站的资源缓存在CDN各个节点上,当请求命中了某个节点的资源缓存时,立即返回客户端,避免每个请求的资源都通过源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验。

image-20220912144844913

4. 运营商劫持是什么?如何防范?

运营商是指提供宽带服务的ISP,包括中国电信、移动、联通,为了经济利益,会劫持用户的访问,称为运营商劫持。运营商劫持分为DNS劫持、http劫持、https劫持。

DNS劫持已被严厉接管,是违法行为;对于http劫持,可以加入防运营商劫持代码,判断ip是否来自黑名单,是则丢弃返回包,也可以拆包发送,让其检测不到是http请求。

5. HTTPS 一定是安全的么?如果不是,那么在什么情况下是不安全的?

网络面经:使用HTTPS就绝对安全了吗?

https通信如果检测出不合法的证书时,会进行风险提示,用户仍然可以授权信任证书继续操作,此时如果出现中间人攻击,https就不是安全的了。

6. 如何劫持 HTTPS 请求。 比如你需要抓 HTTPS 的包,怎么做?

HTTPS 一定是安全的吗?

可以自己签发证书,在客户端安装自己的根证书,这个证书就被浏览器信任,然后作为中间人劫持https请求。

7. 支付宝和微信的离线支付是怎么做的?

手机没网了,却还能支付,这是什么原理?

8. Token 和 Cookie 有什么区别和联系呢?其分别是为了解决什么样的事情?

傻傻分不清之 Cookie、Session、Token、JWT

Cookie是弥补http无状态的问题的,使用cookie可以使服务器识别前后两个请求是否来自同一浏览器,从而进行会话跟踪;Token是访问资源接口时所需要的资源凭证,是类似cookie的一种验证信息。

Token和cookie的认证流程很相似,都是服务端发给客服端,客户端在下次请求时带上token或cookie来进行验证;只不过token做了加密,而且是开发者自己决定要不要储存、发送给服务端(cookie默认储存与发送),不存在同源限制,比cookie更灵活。

9. WebSocket 需要 cookie 么?为什么?

WebSocket不需要cookie,因为使用WebSocket,客户端与服务端就一直保持连接的状态,双方可以互发数据,服务器也知道客户端的身份,不需要cookie来做验证。

10. WebSocket 是怎么实现点对点通信和广播通信的?

11. 如果访问你的 APP 很慢,你自己无法重现。 初步定位到网络问题, 那么你怎么能具体定位到问题呢?

面试官:如果你访问一个网站很慢,怎么排查和解决?

12. traceroute, Ping 的原理是什么?

13. 192.168.0.1 和 192.168.1.1 如何通信?

14. DNS 是如何泄漏个人隐私的?怎么防范?

DNS泄漏(产生的原因和修复办法)

15. 从网络协议模型(七层 or 四层)的角度分析一下,浏览器访问 192.168.3.4:8088 的具体过程。

浏览器根据ip地址与目标服务器建立TCP连接,浏览器发出http请求报文,由套接字传到运输层,将请求报文封装成TCP报文段,在网络层封装成ip数据报,查找路由表,确定通过哪个路径到达目的主机,ICMP提供网络传输中的差错检测;在数据链路层通过ARP将目的主机的ip地址映射成MAC地址,将ip数据报封装成帧;物理层将帧中的一个个比特从一个节点移动到下一个节点;服务器监听8088端口的客户端请求,再把响应信息返回给客户端