自我介绍
面试官下午好,我叫小浪浪,今天来贵公司面试前端岗位。我从事前端开发有两年多了,主要技术栈是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
闭包
闭包是指有权访问另外一个函数作用域中的变量的函数。通俗一点的理解:函数内部嵌套函数,函数内部范围函数外部的变量
- 闭包的优点:
- 创建私有变量,避免全局变量污染
- 延迟变量的生命周期
- 闭包的缺点:
- 会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
微任务和宏任务
- JS是单线程的脚本语言
- 执行循序:先执行主线程代码 > 微任务 > 宏任务(有微则微,无微则宏)
- 微任务:nextTick、Promise.then、catch、finally
- 宏任务:I/O、setTimeout、setInterval 同步代码一开始就放入执行栈中先执行,过程中遇到异步操作,就放到对应的任务队列中,等主线程空闲之后取出任务队列的东西放到执行栈中执行。然后重复上面的步骤,直至完成所有的任务(事件循环)。
JS数据类型、typeof、instanceof
- 基本数据类型:string、number、boolean、null、undefined、object(array、function)、symbol(ES10 BigInt)
- typeof主要同来判断数据类型,返回有string、boolean、number、function、object、undefined
- instanceof判断该对象是谁的实例
- null表示空对象,undefined表示声明未赋值的变量
this指向
this指向最后一次调用这个方法的对象。在全局函数中,this等于window。当函数被作为某个对象调用是,this等于那个对象。在实际开发中,this的指向可以通过四种调用模式来判断。
- 函数调用,当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象window,严格模式下为undefined
- 方法调用,如果一个函数作为一个对象的方法来调用时,this指向这个对象
- 构造函数调用,this指向的这个用new新创建的对象
- 使用apply、call、bind来调用,可以指定调用函数的this指向。apply接收参数是数组,call接收列表多个参数用逗号隔开,bind返回一个绑定this后的新函数
new 关键字
- 创建一个空新对象
- 将新对象继承构造函数的原型
- 将构造函数的this指向这个新对象,执行构造函数的代码(为这个对象添加属性)
- 判断函数的返回值类型,如果是值类型,返回创建的对象,如果是引用类型,就返回这个引用类型的对象
作用域、作用域链
- 作用域:负责收集和维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识的访问权限。(全局作用域、函数作用域、块级作用域)。出了花括号就不能访问。
- 作用域链:作用域链就是从当前作用域开始一层一层向上寻找某个变量,直到找到全局作用域还是没有找到,就宣布放弃。这种一层一层的关系就叫作用域链。
事件冒泡、捕获(委托)
- 事件冒泡指在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个的父级对象传播,最终父级对象触发了事件。(由内向外传播)。
- 事件委托本质上是利用浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且在父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式成为事件代理。
- 阻止事件冒泡:event.stopPropagation() IE下:event.cancelBubble = true;
- 阻止事件传播:event.prevnetDefault() IE下event.returnValue = true;
ES6新增属性
- const、let不可重复的声明,具有块作用域。
- 变量的解构,剩余参数(...args),扩展运算符(...数组、对象)
- 箭头函数
- Set和Map数据结构
- Proxy
- Promise
- async awiat
- 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长连接
跨域通信的几种方式
解决方案:
- json
- cors(设置Access-Control-Allow-Origin:指定可访问资源的域名)
- iframe的postMessage
- websocket
- node中间件
- nginx反向代理(proxy_pass)
- 日常工作中常用的是cors和nginx反向代理
浏览器本地缓存
- 浏览器本地缓存主要有:Cookie、localStorage和seeionStorage和IndexDB
- cookie大小只有4K,sessionStorage和localStorage可以达到5M
- sessionStorage:仅在当前浏览器窗口关闭之前有效
- localStorage始终有效,窗口或浏览器关闭也一直保存,数据持久化
- cookie如果未设置有效时间,即关闭窗口或浏览器之前有效,如果设置了有效时间,已有效时间为准
网络安全、http协议
TCP和UDP的区别
| 区别 | UDP | TCP |
|---|---|---|
| 是否连接 | 无连接 | 面向连接 |
| 是否可靠 | 不可靠,不适用流量控制和拥塞控制 | 可靠,使用流量控制和拥塞控制 |
| 连接对象个数 | 支持一对一、一对多、多对一 | 只能一对一通信 |
| 传输方式 | 面向报文 | 面向字节流 |
| 使用场景 | 适用于实时通信(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
- 接口永远返回200(浏览器可以看到size)
- form monory cache从内存中获取
- fomr disk cache 从磁盘中获取
-
协商缓存
- 客户端请求一个页面A
- 服务器返回页面A,并在响应头设置加上一个last-Midified/ETag
- 客户端展现该页面,并将页面连同last-modified/ETag一起缓存
- 客户端再次请求页面A,并将上次请求服务器响应的last-Modefied/ETag一起传递给服务器
- 服务器检查该last-modified或ETag,并判断是否被修改,未修改直接返回响应304和一个空的响应体,否则响应一个200新的请求。
总结:对于浏览器的缓存机制做好简单的总结
- 首先通过Cache-Control验证强缓存是否可用
- 如果强缓存可用,直接使用
- 否则进入协商缓存,即发送HTTP请求,服务器通过请求中 If-Modined-Since或者If-None-Match这些请求字段检查资源是否更新
- 若资源更新,返回资源和200状态码
- 否则,返回304,告诉浏览器直接从缓存获取资源
Web前端开发的职责是什么
- 使用Div+css并结合Javascript负责产品的前端开发和页面制作;
- 熟悉W3C标准和各主流浏览器在前端开发中的差异,能熟练运用DIV+CSS,提供针对不同浏览器的前端页面解决方案
- 负责相关产品的需求以及前端程序的实现,提供合理的前端架构
- 与产品、后台开发人员保持良好沟通,能快速理解、消化各方需求,并落实为具体的开发工作
- 了解服务器端的相关工作,在交互体验、产品设计等方面有自己的见解