JS面试题

195 阅读12分钟

自我介绍

面试官下午好,我叫小浪浪,今天来贵公司面试前端岗位。我从事前端开发有两年多了,主要技术栈是Vue。在上家公司主要负责,H5、PC以及后台管理系统等项目开发。平常习惯逛一些技术社区丰富自己的技术,像掘金,知乎之类的。我的性格比较温和,跟同事朋友相处时比较外向,在工作中代码开发中喜欢全心全意的投入,对于工作认真负责。以上是我的自我介绍,谢谢。

JS相关

html5新特性、语义化

浏览器渲染机制、重绘、重排

网页生成过程:

  • HTML被HTML解析器解析成DOM树
  • CSS被CSS解析器解析成DOM树
  • 结合DOM树和CSSOM树,生成一颗渲染树(Render Tree)
  • 生成布局Flow,即将所有渲染树的所有节点进行平面合成
  • 将布局绘制在屏幕上
  • 重排(也称回流):render树中的部分或全部因为元素的规模尺寸、布局、隐藏等改变需要重新计算render。(宽度、高度、位置)发生改变后就会引起重排
  • 重绘:当元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。(color 、background、box-shadow)等属性
  • 重排必定引发重绘,但重绘不一定引发回流,且回流代价更高
  • 执行顺序:先回流后重绘

JS原型

  • 每一个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor)
  • 每一个实例都包含一个指向原型对象的内部指针__proto__。原型对象的__proto__指向的Object.prototype
  • Object.prototype.__proto__指向的是null,也就是原型的顶层。
  • 原型: Person -> Person.prototype -> constructor -> Person
  • 原型链:构造函数生成的实例对象person person.proto -> Person.prototype -> Person.prototype.proto -> Object.prototype -> Object.prototype__proto__ -> null

闭包

闭包是指有权访问另外一个函数作用域中的变量的函数。通俗一点的理解:函数内部嵌套函数,函数内部范围函数外部的变量

  • 闭包的优点:
    1. 创建私有变量,避免全局变量污染
    2. 延迟变量的生命周期
  • 闭包的缺点:
    1. 会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

微任务和宏任务

  1. JS是单线程的脚本语言
  2. 执行循序:先执行主线程代码 > 微任务 > 宏任务(有微则微,无微则宏)
  3. 微任务:nextTick、Promise.then、catch、finally
  4. 宏任务:I/O、setTimeout、setInterval 同步代码一开始就放入执行栈中先执行,过程中遇到异步操作,就放到对应的任务队列中,等主线程空闲之后取出任务队列的东西放到执行栈中执行。然后重复上面的步骤,直至完成所有的任务(事件循环)。

JS数据类型、typeof、instanceof

  1. 基本数据类型:string、number、boolean、null、undefined、object(array、function)、symbol(ES10 BigInt)
  2. typeof主要同来判断数据类型,返回有string、boolean、number、function、object、undefined
  3. instanceof判断该对象是谁的实例
  4. null表示空对象,undefined表示声明未赋值的变量

this指向

this指向最后一次调用这个方法的对象。在全局函数中,this等于window。当函数被作为某个对象调用是,this等于那个对象。在实际开发中,this的指向可以通过四种调用模式来判断。

  1. 函数调用,当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象window,严格模式下为undefined
  2. 方法调用,如果一个函数作为一个对象的方法来调用时,this指向这个对象
  3. 构造函数调用,this指向的这个用new新创建的对象
  4. 使用apply、call、bind来调用,可以指定调用函数的this指向。apply接收参数是数组,call接收列表多个参数用逗号隔开,bind返回一个绑定this后的新函数

new 关键字

  1. 创建一个空新对象
  2. 将新对象继承构造函数的原型
  3. 将构造函数的this指向这个新对象,执行构造函数的代码(为这个对象添加属性)
  4. 判断函数的返回值类型,如果是值类型,返回创建的对象,如果是引用类型,就返回这个引用类型的对象

作用域、作用域链

  1. 作用域:负责收集和维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识的访问权限。(全局作用域、函数作用域、块级作用域)。出了花括号就不能访问。
  2. 作用域链:作用域链就是从当前作用域开始一层一层向上寻找某个变量,直到找到全局作用域还是没有找到,就宣布放弃。这种一层一层的关系就叫作用域链。

事件冒泡、捕获(委托)

  • 事件冒泡指在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个的父级对象传播,最终父级对象触发了事件。(由内向外传播)。
  • 事件委托本质上是利用浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且在父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式成为事件代理。
  • 阻止事件冒泡:event.stopPropagation() IE下:event.cancelBubble = true;
  • 阻止事件传播:event.prevnetDefault() IE下event.returnValue = true;

ES6新增属性

  1. const、let不可重复的声明,具有块作用域。
  2. 变量的解构,剩余参数(...args),扩展运算符(...数组、对象)
  3. 箭头函数
  4. Set和Map数据结构
  5. Proxy
  6. Promise
  7. async awiat
  8. Module(import/export) 1.Promise常用方法
  • Promise是异步的一种解决方案,比传统的解决方案更合理更强大
  • reject resolve all race allSettled any try
  • Promise的prototype方法:then catch finally
  • Promise有三个状态:Pending Fulfilled rejected,状态一旦改变就不会再变了,只有两种情况,进行中到(成功或者失败)
  • all: Promise.all([p1, p2]) 只有当p1和p2变成成功的时候才会执行then否则执行catch
  • race: Promise.race([p1, p2]) 以第一个实例返回的结果,作为最终的结果,第一个实例返回成功执行then 否则执行catch
  • allSettled: 等待实例完成全部执行完成,无论如何只会返回成功
  • any 只要实例有一个返回成功,结果返回成功,如果实例全部返回是失败则执行catch

2.Async

  • 语法上面,使得异步操作变得更加方便,async函数返回的promise对象,只有async函数内部的异步操作执行完成才是执行then方法指定的回调函数
  • async 函数的返回值是Promise对象(异步),await是内部then命令的语法糖(同步)

3.Iterator

  • 原生具备Iterator接口的数据结构有:Array Map Set String TypedArray arguments NodeList 使用 for of遍历
  • 通过next调用内部成员,返回一个对象有两个属性值 value和done。其中value代表当前成员的值,done属性是一个布尔值,表示遍历是否结束

4.Symbol

  • 保证每个属性的名字都是独一无二的,防止属性名的冲突,这就是ES6移除symbol的原因

5.Module

  • 将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。内部的所有变量,外部无法获取。
  • 使用:通过export导出代码,再通过import导入。export导出可以使用as别名(v1 as newName)
  • export三种使用 export var m = 1; let m = 1; export { m } export { m as n};
  • import 使用:import { foo } from 'my_module' import * as main from 'my_module'
  • export default导出一个匿名函数,外部使用可以任意指定名字

6.函数

  • rest参数:用户获取函数的多余参数,这样就不需要使用arguments对象了,rest是一个数组(...rest)
  • 箭头函数
  • 三个点(...): 扩展运算符、浅拷贝、合并数据

7.Proxy

  • (1)可以理解成,在目标对象之前做一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供一种机制,可以对外界的访问进行过滤和改写。

前端性能优化

同源策略

一个域名下的js脚本未经允许的情况下,不能访问另外一个域下的内容。通常判断跨域的依据是协议、域名、端口号是否相同,不同则跨域。同源策略是对js脚本的一种限制,并不是对浏览器的限制,像img、script脚本请求不会有跨域限制

前端后任务通信

  • Ajax短连接
  • websocket长连接

跨域通信的几种方式

解决方案:

  1. json
  2. cors(设置Access-Control-Allow-Origin:指定可访问资源的域名)
  3. iframe的postMessage
  4. websocket
  5. node中间件
  6. nginx反向代理(proxy_pass)
  7. 日常工作中常用的是cors和nginx反向代理

浏览器本地缓存

  • 浏览器本地缓存主要有:Cookie、localStorage和seeionStorage和IndexDB
  • cookie大小只有4K,sessionStorage和localStorage可以达到5M
  • sessionStorage:仅在当前浏览器窗口关闭之前有效
  • localStorage始终有效,窗口或浏览器关闭也一直保存,数据持久化
  • cookie如果未设置有效时间,即关闭窗口或浏览器之前有效,如果设置了有效时间,已有效时间为准

网络安全、http协议

TCP和UDP的区别

区别UDPTCP
是否连接无连接面向连接
是否可靠不可靠,不适用流量控制和拥塞控制可靠,使用流量控制和拥塞控制
连接对象个数支持一对一、一对多、多对一只能一对一通信
传输方式面向报文面向字节流
使用场景适用于实时通信(ip电话、视频会议、直播等)适用于要求可靠性的应用,例如文件传输

http和https区别

  • http是不安全的,而https是安全的
  • http标准端口是80,https的标准端口是443
  • http无法加密,https对传输的数据进行加密
  • http无需证书,https需要CA机构wosign的颁发的SSL证书

GET和POST的区别

  • get在浏览器回退不会再次请求,post会再次请求
  • get请求会被浏览器主动缓存,post不会,需要手动设置
  • get请求参数会被完整保留在浏览器历史记录里,post中的参数不会
  • get请求在url中传送的参数是有限制的,post没有限制
  • get参数通过url传递,post放在request body中
  • get参数暴露在地址栏不安全,post放在报文内部更安全
  • get一般用于查询信息,post一般用于提交某种信息进行某些修改操作
  • get产生一个TCP数据包,post产生两个TCP数据包

http特性以及状态码

  • 200响应成功
  • 301永久重定向
  • 302临时重定向
  • 304资源缓存
  • 403服务器禁止访问
  • 404服务器资源未找到
  • 500、502服务器内部错误1
  • 504服务器繁忙

http缓存

  • 强缓存:expires/cache-Control

    1. 接口永远返回200(浏览器可以看到size)
    2. form monory cache从内存中获取
    3. fomr disk cache 从磁盘中获取
  • 协商缓存

    1. 客户端请求一个页面A
    2. 服务器返回页面A,并在响应头设置加上一个last-Midified/ETag
    3. 客户端展现该页面,并将页面连同last-modified/ETag一起缓存
    4. 客户端再次请求页面A,并将上次请求服务器响应的last-Modefied/ETag一起传递给服务器
    5. 服务器检查该last-modified或ETag,并判断是否被修改,未修改直接返回响应304和一个空的响应体,否则响应一个200新的请求。
      总结:对于浏览器的缓存机制做好简单的总结
  1. 首先通过Cache-Control验证强缓存是否可用
  2. 如果强缓存可用,直接使用
  3. 否则进入协商缓存,即发送HTTP请求,服务器通过请求中 If-Modined-Since或者If-None-Match这些请求字段检查资源是否更新
  4. 若资源更新,返回资源和200状态码
  5. 否则,返回304,告诉浏览器直接从缓存获取资源

Web前端开发的职责是什么

  1. 使用Div+css并结合Javascript负责产品的前端开发和页面制作;
  2. 熟悉W3C标准和各主流浏览器在前端开发中的差异,能熟练运用DIV+CSS,提供针对不同浏览器的前端页面解决方案
  3. 负责相关产品的需求以及前端程序的实现,提供合理的前端架构
  4. 与产品、后台开发人员保持良好沟通,能快速理解、消化各方需求,并落实为具体的开发工作
  5. 了解服务器端的相关工作,在交互体验、产品设计等方面有自己的见解