1. BFC BFC指的块级格式化上下文,意思就是独立的布局环境,bfc内部的元素布局与外部互不影响。解决外边距合并、高度塌陷、浮动遮盖的问题。

  2. visibility:hidden能继承不能点击、display:none不能继承不能点击,opacity:0不能继承能点击;

  3. 居中为何使用transform 因为transform是合成属性,会创建独立的合成层,不会触发重排重绘操作。而margin会触发重排操作,性能开销更大。

  4. sticky是相对于最近能滚动的父级元素定位,不脱离文档流。

  5. 设置自适应大小的正方形 通过width、height设置为固定的vw。或者设置百分比的width和padding-bottom。

  6. 清除浮动 bfc、伪元素

  7. ie盒模型和标准盒模型 ie盒模型的宽高会包括边框和内边距。

  8. DOCTYPE是HTML5的文档声明,告诉浏览器使用哪个HTML版本标准解析文档。

  9. 语义化标签的作用

  • 在没有css样式时也能呈现清晰的结构
  • 有利于SEO
  • 方便团队开发和维护,具有可读性
  1. src和href的区别
  • src会暂停其它资源的下载,直到将该资源加载、编译、执行。
  • href表示超链接,浏览器会并行下载,不会停止当前文档的处理。
  1. 严格模式是以浏览器支持的最高标准执行,混杂模式表示页面以宽松向下兼容的方式显示。
  2. a元素还可以用来锚点和下载资源。
  3. 箭头函数没有this、arguments、super,this是从上层作用域链继承。
  4. 继承
  • 原型链继承:无法向父级构造函数传递参数,共享父级的引用类型,函数是复用的,
  • 借用构造函数继承:能向父级构造函数传递参数,不共享父级的引用类型,函数无法复用。
  • 组合继承:结合原型链、借用构造函数,可以传参数、父级引用类型不共享、函数复用,缺点是调用两次父类构造函数。第一次是生成子类实例时,第二次是原型链继承时。
  • 原型式继承:创建一个空函数,直接将原型指向需要继承的实例。缺点是引用类型共享,函数无法复用。
  • 寄生式继承:将原型式继承封装一下,内部增强对象,函数可以复用了。
  • 寄生式组合继承:直接基于父类的原型生成一个实例对象,
function Father
1
  1. new的实现
function newFn (fn, ...args) {
  const obj = {}
  Object.setPrototype(obj, Fn.prototype)
  const result = fn.apply(obj, args)
  return result instanceof Object ? result : obj
}
1
2
3
4
5
6
  1. call接收的多个参数,apply接收的数组,bind返回一个函数,参数跟call类似。
  2. 事件循环机制
  3. 函数柯里化,将多参数的函数简化成单参数的函数,该函数返回以剩余参数的单个参数为参数的函数。
  • 减少重复传递不变的参数,达到复用的效果。
  1. promise.all,如果参数不是promise,则用promise.resovle转为promise。
  2. this的指向
  • this是跟着调用对象走的
  • 箭头函数不会创建自己的执行上下文,所以this继承上级的this。
  1. 事件监听:捕获和冒泡。从window开始到目标节点再回到window。事件委托就是利用事件冒泡。
  2. 闭包和应用场景
  • 能访问到函数内部变量的函数。
  1. 写一个判断变量类型的函数
  2. script标签 defer和async 的区别,async是立即下载,同步执行。defer是立即下载,页面解析完成后再执行。
  • DOMContentLoaded是在defer script执行完毕后执行。
  • 优先下载同步script,其余顺序下载。
  1. 原型与原型链
  • 每个函数都有一个prototype属性,叫做原型对象;每个对象都有_proto_属性,指向其构造函数的原型对象;当查询一个对象的属性时,会先查询这个对象本身有无这个属性,如果无,则会访问_proto_属性去查找原型对象有没有,原型对象也有_proto_属性,一路会Object构造函数的原型对象,如果也没有的话,则会反回undefined,因为Object构造函数的原型对象的原型对象为null。这就是原型链。
  1. 作用域链条
  • js有全局执行上下文和函数执行上下文,当js查找一个变量时,会从当前所处的作用域往上查询。原理是当js文件执行时,会编译最外层的代码,创建一个全局作用域,推入作用域栈的栈底,然后执行代码到函数时,会编译创建一个函数作用域,推入作用域栈中,作用内部包含一个变量环境、词法环境、outer,词法环境是个栈结构,其中let、const就是通过词法环境实现的。outer指向上级作用域,outer的指向只跟函数的声明位置有关,在编译的时候就决定好了。
  1. instanceof原理
  • 基于原型连查找的。判断构造函数的prototype是否在实例的_proto_属性上。
  1. js垃圾回收机制
  • 标记清除:从根对象开始递归遍历对象的引用关系,给能访问到的对象打上标记。随便把未打上标记的对象清除。
    • 优点:不存在循环引用;
    • 缺点:会暂停程序执行,引起卡顿;内存碎片化。
  • 标记整理:标记清除+整理;解决内存碎片化的问题。
  • 引用计数:对象每被引用一次就加1,不再被引用时就减1,清除计数为0的。
    • 优点:实时回收;
    • 缺点:循环引用。
  • V8垃圾回收:分为新生代和老生代,新生代采用scavenge算法将内存分为两半,每次用一半来存储数据,快满的时候采用标记清除,把存活的直接迁移至另一半,同时清空当前的。其中存活时间较长的对象晋升到老生代。老生代采用标记整理清除算法。同时还采用了增量标记、三色标记法、写屏障、惰性清理等策略优化回收策略。
  1. 实现apply、call、bind方法
  2. parseInt(num, radix)解析规则,
  3. 截流防抖的实现。
  4. weakSet、weakMap
  5. 实现sleep
  6. 数据量大的情况下使用for循环,小数据则使用forEach。因为forEach要执行回调函数,需要创建额外的调用栈和函数上下文。
  7. 10万个元素的数组,取第一个元素和最后一个元素的时间几乎一样,因为都是直接根据索引取,js的数组是通过对象实现,查索引也就是查hash表。
  8. 深拷贝和浅拷贝
  9. setTimeout设置的时间会存在误差,因为那个时间只是表示把回调函数挂入宏任务栈的时间,要等主线程执行完同步任务才会执行宏任务。
  10. await和async的原理
  11. symbol的用途
  • 防止命名冲突
  • 设置私有变量
  • 提供遍历接口
  1. promise.resolve
  2. intanceof实现原理
  3. encodeURI和encodeURIComponent的区别
  4. for in 和 for of 的区别
  5. 箭头函数内部的this是绑定运行时的父级上下文
  6. new Number(3)返回的是一个对象
  7. class static private
  8. onclick绑定的事件为冒泡型事件。
  9. document.onload 和 ready区别
  10. 三次握手和四次挥手
  11. https中间人攻击、劫持攻击和剥离攻击
  12. 验证证书合法性
  13. http状态吗
  14. 单点登录
  15. get与post的区别
  16. dns劫持、xss攻击
  17. csrf攻击
  18. 前端如何实现即时通讯。
  19. url解析全过程
  20. cookies、localStorage、sessionStorage
  21. 手写promise
class myPromise {

  constructor (executor) {
    this.status = 'pending'
    this.value = undefined
    this.reson = undefined
    this.fulfilledFns = []
    this.rejectedFns = []
    
    let resolve = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        this.value = value
        this.fulfilledFns.forEach(fn => fn())
      }
    }

    let reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected'
        this.reason = reason
        this.rejectedFns.forEach(fn => fn())
      }
    }

    executor(resolve, reject)
  }

  then (onFulfilled, onRejected) {
    const promise2 = new myPromise((res, rej) => {
      if (this.status ==== 'fulfilled') {
        const x = onFulfilled(this.value)
        resolvePromise(promise2, x, res, rej)
      }

      if (this.status === 'rejected') {
        const x = onRejected(this.reason)
        resolvePromise(promise2, x, res, rej)
      }

      if (this.status === 'pending') {
        this.fulfilledFns.push(() => {
          const x = onFulfilled(this.value)
          resolvePromise(promise2, x, res, rej)
        })
        this.rejectedFns.push(() => {
          const x = onRejected(this.reason)
          resolvePromise(promise2, x, res, rej)
        })
      }
      
    })

    function resolvePromise (promise, x, res, rej) {
      if (x instanceof myPromise) {
        if (x === promise) { rej('自己引用自己'); return }

        x.then((xValue) => {
          res(xValue)
        }, (xReason) => { 
          rej(xReason)
        })
        
      } else {
        res(x)
      }
    }

    return promise2
  }
}
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  1. http1.0、1.1、2.0、3.0的区别
  • http1.1比1.0
    • 支持持久化连接,一个tcp连接可以传输多个http请求,一个域名最多支持6个tcp连接。
    • 通过host字段,支持虚拟主机,1一个ip对应多个域名。
    • 支持动态内容,将数据分成若干个数据包,然后后一个数据包带有一个数据包的大小。最后已一个零长度的包代表数据传输结束。
    • 新增cookies,存在浏览器端的数据,每次请求都会携带。
  • http2.0比http1.1
    • 只保持一个TCP长连接。
    • 增加二进制分帧层,实现多路复用。
    • 设置请求的优先级
    • 支持头部压缩。
    • 服务器推送
  • http3.0
    • 使用udp,实现quic协议。
    • 未广泛推广。

alt text alt text

  • 原型
  • 作用域链条
  1. 模块
  • CommonJS模块:module.exports = xxx导出,require()导入
  • ESM模块:export xxx导出,import xxx from xxximport()导入,export xxx from xxx中转
  • ts中,importexport会将当前文件标记为模块,不再能全局使用。
  1. 类实现接口,接口声明一个类的构造函数。
  2. 枚举的js代码实现
  3. const enum xxx 可以获得性能提升
  4. enum + namespace 可以给枚举添加静态方法
  5. target 和 lib的区别
  6. 无函数实现的情况下,函数类型声明的两种方式。
  7. 函数重载的意义:强制约束参数数量的关联性。比如4个可选参数,可以传1、2个,传4个,不能只传3个,可以通过函数重载实现。
  8. 双重断言xxx as any as XXX
  9. 对象字面量作为参数时,拥有更严格的类型检查。
  10. 类型保护的方法:typeofinstanceofinXXX.xxx、用户自定义类型保护函数。
  11. readonlyArray

# 自我介绍

面试官,您好,我叫刘煊港,今年26岁,2020年毕业于湖南工商大学软件工程专业,目前就职于思为科技有限公司前端工程师岗位,主要负责小程序、saas后台管理系统、app相关的需求开发和性能优化,主要用的技术栈有vue、uni-app、ts等。我个人会经常逛掘金和github来了解行业趋势和知识扩展,对自我要求也较高,注重typescript提升代码质量和可读性、熟练使用快捷键提升开发效率。并且有很好的团队合作意识,乐于推动团队建设。

# 面试题

  • 项目中遇到的难点

    • 工程化难点
      • 优化uni-app开发体验
        • 明确我要解决的问题,小程序端本地开发编译慢
        • 最初的想法是把pages.json文件拆分到各模块,然后在打包之前,把pages.json文件组装在一起。缺点就是改造成本较大,需要拆分文件。不方便统一管理了。
        • 后面逛社区的时候,发现了一个插件里介绍了uni-app提供了一个page.js的文件钩子,uni在打包时会读取该文件并执行,文件导出的是一个函数,接受参数为pages.json的json数据,返回的也是json数据,可以在函数内部对json字符串做处理。
        • 于是我就写了一个脚本,在执行之前动态去生成pages.js文件,然后根据脚本的执行参数对内部的分包进行拆分,从而达到减少打包文件的效果,实现快速编译。
        • 这次的优化显著提升了冷启动和热更新的速度。也在团队内部做了一次分享。
    • 技术难点
      • 明确要解决的问题
      • 自己想一下解决方案
      • 找社区或者github找有没有更好的实现方式
      • 最后结合实际情况,选择最适合的方案解决问题
  • http介绍

    • http1.1
      • 支持持久连接,默认开启,一个tcp连接上可以传输多个http请求。
      • 每个域名最多维护6个tcp连接
      • 增加Host字段,提供虚拟主机的支持,支持多个域名公用1个ip地址
      • 支持动态内容传输,引入Chunk transfer机制,服务器将数据分割成若干个任意大小的数据块,每个数据块附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。
      • 客户端cookies、安全机制
      • 问题
        • 队头阻塞:在没有接收到上一个http响应时,不会开启下一个请求。
        • tcp机制的慢启动导致带宽利用率不理想
        • 同时多条tcp连接会竞争固定的带宽
    • http2.0
      • 一个域名只使用一个tcp长连接
      • 多路复用
        • 通过增加二进制分帧层实现多路复用,把请求转换成一个个带请求ID的帧。
        • 服务器收到优先资源的请求,可以暂停别的请求来优先处理。
      • 可以设置请求的优先级
      • 服务器可以提前将数据推送到浏览器
      • 头部压缩
    • tcp的队头阻塞:中途一个数据包丢失导致重传等待导致
    • 当达到2%的丢包率时,http/1.1比http/2的表现好。
    • tcp协议的僵化
      • 中间设备的僵化
      • 操作系统更新滞后
  • http状态码

    • 2开头表示成功
    • 3开头表示重定向
      • 301 永久重定向
      • 302 临时重定向
    • 4开头表示找不到资源
      • 403被禁止
      • 404找不到资源
    • 5开头表示服务器有问题
  • XSS攻击

    • 跨站脚本攻击
    • 攻击者通过技术手段往网站注入恶意脚本,获取用户cookies、sessionID等敏感数据,从而危害数据安全。
    • 存储型:攻击者将恶意代码存入服务器端数据库中,用户请求网页时,服务器端将恶意代码拼接进html返回给用户。
    • 反射型:攻击者将恶意代码拼入URL,用户打开URL时,服务器端将URL中的恶意代码拼接进html返回给用户。
    • DOM型: 攻击者将恶意代码拼入URL,用户打开URL时,前端取出URL中的恶意代码并执行。
    • 防范的话html做转译。
  • CSRF攻击

    • 利用服务器的漏洞和用户的登录状态在第三方站点实施攻击
    • 引诱用户点击恶意链接,然后隐式调用漏洞接口
    • 问题:怎么利用用户的登录状态
    • 阻止
      • 充分利用好Cookies的SameSite属性
      • 通过Referer、Origin验证请求的来源站点
      • CSRF Token
  • 浏览器缓存

    • cookies
    • storage
  • vue

    • vue和react的对比
      • react用jsx vue用单文件组件
    • 单项数据流和双向绑定的异同 *
    • vue3为什么使用proxy
      • vue2使用object.defineProperty有局限性
        • 对象新增属性无响应式
        • 数组.length无响应式
        • 数组的方法无响应式
  • 技术分享做过哪些

    • vscode快捷键的分享:主要分享快捷键的使用,如何使用快捷键提升效率,一些比较实用的快捷键。
      • 文件跳转
      • 多光标操作
      • 代码搜索
    • 优化uni-app开发模式下编译打包速度。
  • 算法题

    • 有效括号匹配
    • 字符串匹配
  • 离职原因

    • 我想找一个更有挑战性、并且有更大成长空间的工作。
    • 非常看好贵公司所处行业和所做的事情。