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协议。
    • 未广泛推广。

# 自我介绍

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

  • 原型
  • 作用域链条
  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