前端八股文

url渲染
1、进行DNS解析,域名到对应的ip地址,dns解析耗时,可用dns-prefetch预解析优化
2、TCP三次握手,建立TCP链接
- c -> s 发送询问
- s -> c 回复询问,并询问
- c -> s 回复询问
四次挥手
- 主 -> 被 关闭主动通道,只能被动接收
- 被 -> 主 收到关闭消息
- 被 -> 主 关闭主动通道
- 主 -> 被 收到关闭消息
https建立TLS加密
- 验证证书,确认加密方式
五层因特网协议栈
- 从应用层的发送http请求,到传输层通过三次握手建立tcp/ip连接,再到网络层的ip寻址,再到数据链路层的封装成帧,最后到物理层的利用物理介质传输

  • http 状态码
    3、浏览器请求数据
  • 浏览器缓存机制
    - 强制缓存
    - 浏览器直接从缓存中读取文件,不需要发送请求
    - http1.0 响应头 => expires 绝对时间,浏览器时区和服务器时区不一致时 => 缓存失效
    - http1.1 响应头 => cache-control 相对时间
    - 协商缓存
    - 浏览期发送请求,服务器决定是否使用缓存
    - Last-Modified/if-Modified-Since 时间粒度是秒
    - Etag/If-None-Match 根据文件内容生成一个标记
  • 获取html文件,构建DOM树
    • 边下载边解析
  • 下载css文件,构建style树
    • 边下载边解析
  • DOM树和style树组合成渲染树
  • 下载js文件,运行js
    • js运行会阻塞DOM树的渲染
      4、 layout布局、绘制像素

queue
stack

promise

  • promise 异步编程的一种解决方案,可以将异步回调写法变成链式调用写法,流程更加清晰,代码更加优雅
  • 三个状态,两个过程,一些方法
    • pending、fulfilled、rejected
    • pending -> fulfilled == resolve
    • pending -> rejected == reject
    • then 接收两个回调,成功回调,失败回调
    • catch 接收一个失败回调,也可以抛出代码错误
    • Promise.all 接收一个promise数组,都成功时返回成功的数组,有一个失败,返回失败的错误
    • Promise.race 返回第一个改变状态的结果
    • Promise.allSettled 所有promise实例结束后才会返回,成功的返回value,失败的返回err
    • Promise.any 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
    • all和race传入的数组中如果有会抛出异常的异步任务,那么只有最先抛出的错误会被捕获,并且是被then的第二个参数或者后面的catch捕获;但并不会影响数组中其它的异步任务的执行。
ata.filter(({id}) => {
  return selectedIds.includes(id);
})

const ids = {};
selectedIds.forEach(id => ids[id] = 1);
data.filter(({id}) => {
  return !!ids[id];
})


debounce

function debounce(fn, wait){
  let timer = null;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn, wait);
  }
}

throttle

function (fn, delay) {
  let prev = null;
  let timer = null;
  return function() {
    const now = Date.now();
    if(prev && now - prev > delay) {
      clearTimeout(timer);
      timer = sertTimeout(fn, delay);
    } else {
      fn.apply(this, arguments)
      prev = Date.now();
    }
  }
}

quickSort 

function quickSort(arr) {
  if(arr.length <= 1) return arr;
  const pivotIndex = Math.floor(arr.length / 2);
  const pivot = arr.splice(pivotIndex, 1);
  let left = []
  let right = [];
  for (let i = 0; i < arr.length; i++) { 
    if( pivot > arr[i]) {
      left.push(arr[i])
    } else {
      right.push(arr[i])
    }
  }
  return quickSort(left).concat(pivot, quickSort(right));
}

// 空间换时间 o(n2) => o(n)

d

react

react UNSAVE_

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

挂载阶段

  • constructor
  • static getDerivedStateFromProps(nextProps, prevState)
  • render
  • componentDidMount

更新阶段

  • getDerivedStateFromProps
  • shouldComponentUpdate(nextProps, nextState)
  • render
  • getSnapshotBeforeUpdate(prevProps, prevState)
  • componentDidUpdate(prevProps, prevState, snapshot)

卸载阶段

  • componentWillUnmount

  • static getDerivedStateFromError

  • componentDidCatch

state -> setState

  • 在合成事件和钩子函数中是异步的,在原生事件和setTimeout中是同步的

  • react setState之后

    • react会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程
    • react会根据最新的state构建一颗新的虚拟DOM树
    • 使用diff算法得出新树和旧树的差异
    • 根据差异对界面进行最小化的重新渲染

react fiber

  • 基于浏览器的单线程调度算法
  • 16之前使用的是递归,很难中断,16之后使用循环
  • fiber 一种将递归diff,拆分成无数个小任务的算法,他随时能够中断,恢复。停止恢复的时机取决于当前帧内还有没有时间用于计算

time slice

  • 时间分片基于可中断、重启的fiber架构,中断当前的渲染,执行紧急任务,保证页面的流畅运行

redux

  • store
  • state
  • action
  • action creator
  • reducer
  • dispatch
  • 1、用户通过dispatch方法发出action
  • 2、store自动调用reducer,接收action和当前的state,返回新的state
  • 3、state改变,store调用监听函数,更新view

react-redux

  • provider 从最外部封装整个应用,向connect模块传递store
  • connect 连接react和redux
    • 获取state
    • 将state和action通过props的方式传入原组件
    • 监听state变化

react-thunk

  • 异步中间件
  • 使dispatch可以传递一个函数
  • 把redux流程外的逻辑塞到了流程内

script 标签中增加corssorigin属性

  • 可以获得更多的错误信息

react hooks

  • useState
  • useEffect
  • useRef
  • useCallback
  • useMome
  • useContext
  • useReducer
  • 闭包问题,过时的闭包问题
    • useEffet中拿不到最新的state
      • 依赖中增加state
    • 异步更新问题
      • useState中使用函数方法

super

  • 子类调用super,传递this,使子类this获取父类中的属性和方法

TypeScript

  • 微软开源,可选的 强类型的JavaScript的超集,支持最新的js语法,不在浏览器上直接运行,需要编译成js

  • 为什么用TS

    • 稳定性,ts的静态类型检查系统,能够提升代码的质量,提高系统的稳定性,减少线上bug
    • 可读性, 类型定义加上IDE的智能提示,提升了代码的可读性
    • 可维护性, 所有的调用方,都遵守类型定义,在长期的迭代中,增强了可维护性

diff

  • .js \ .ts
  • 支不支持ES6
  • 弱类型 / 强类型
  • 运行时暴露错误 / 编译时暴露错误

接口是什么?

类是什么?

  • 创建对象的模版,具有逻辑实体,有属性和方法
  • 封装、继承、多态、抽象
  • 使用class创建

装饰器

  • 一种特殊类型的声明,可用于类,方法,访问器,属性,参数
  • 用@符号为前缀的函数,
  • 以声明的方式将注释和元数据添加到现有的代码中

泛型

  • 可重用组件方法的工具,创建处理多种数据类型的组件
  • 定义时用标示,引用时用具体类型替换

interface和type的区别

基本类型

  • number,string,boolen,null,undefined,symbol

类型断言

  • 可以用来手动指定一个值的类型, 断定这个变量的类型是啥
  • <类型>值 or 值 as 类型

类型推导
- ts根据一定的定义可以推导出变量的类型

类型保护
- 对于多类型的变量,当使用typeOf判断之后可以确定变量的类型

类型别名
- type 声明一个别名 类似接口

函数重载

  • 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
  • 可以重复定义一个函数的类型

declare

  • 声明一个变量的定义,编译完会删除
  • 用于声明第三方库暴露的变量

闭包

  • 当函数可以访问并记住所在的词法作用域时,就产生了闭包。
  • 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,内部函数访问外部函数的局部变量,利用闭包可以突破作用域链,将函数内部的变量和方法传递到外部。
  • 闭包特性:
  • (1)函数内再嵌套函数
  • (2)内部函数可以引用外层的参数和变量
  • (3)参数和变量不会被垃圾回收机制回收 (过时了)

面向对象oop

  • 面向对象编程就是把需求抽象成一个对象,对这个对象进行分析,为其添加对应的特征属性和行为方法,我们将这个对象称为类

如何优雅的写出符合W3C的代码

  • 合理的使用html标签,语义化标签,块标签,行内标签,行内块标签
  • 规范化书写css顺序,几何形状类型,位置类型,样式类型,尽量少的嵌套css
  • 尽量使用ES6等新语法书写js,代码简洁,易读
  • 合理的书写注释
  • 变量命名的规范化,语义化

前端安全

  • XSS 跨· cross site scripting
    • 类型
      • 储存型 存到数据库-》用户获取数据-》执行 评论、商品评价
      • 反射型 存到url上-》服务端获取-》返回给前端-》前端执行 跳转
      • DOM型 存到url上-》前端获取参数-》执行
    • 防御
      • 字符转义,
        • dengerouslySetInnerHTML/v-html
      • cookie的httpOnly
      • csp
      • 验证码
  • CSRF 跨站请求伪造 cross site request forgevies
    • 方式
      • get请求 通过img
      • post请求 通过自执行的form
      • a链接 引导用户点击
    • 防御
      • 请求中添加token
      • 双重cookie验证
      • 同源检测

webpack
- 对webpack的理解
- 是一个模块打包工具,管理项目中的模块依赖,进行合并,拆分,编译成静态资源
- loader和plugin的区别
- loader是转换器,本质是一个函数,对接收到的内容进行转换,对其他类型的资源进行转义等预处理工作,在rules中配置,比如ts-loader,scss-loader
- plugin是扩展器,是一个插件,对webpack的功能进行扩展,在plugins中配置,比如 html-webpacl-plugin,unlifyjs-webpack-plugin
- webpack热更新的原理
- 热更新又叫热替换,这个机制可以做到不刷新浏览器的情况下,用变更的模块替换旧的模块,达到视图的自动更新
- 核心就是通过webSocket建立服务端与客户端的链接,当服务端监听到文件变动时,向客户端推送消息,客户端拉取最新文件,进行增量更新

vue
vue.js是采用的数据劫持结合发布者-订阅者模式的方式,通过object.defineProperty()来劫持各个属性的setter/getter
在数据变动时,发布消息给订阅者,触发相应的监听回调

具体步骤:
1)需要observe(观察者)的数据对象进行遍历,包括子属性对象的属性,都加上setter和getter,这样的话,
给这个对象的某个值赋值,就会触发setter,那么就能监听到数据的变化
2)compile(解析)解析模版指令,将模版中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,
添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3)watcher(订阅者)是observer和compile之间通信的桥梁,主要做的事情是
1>在实例化时往属性订阅器(dep)里面添加自己
2>自身必须有一个update()方法
3>待属性变动dep.notice()通知时,能够调用自身的update()方法,并触发compile中绑定的回调,
4)mvvm作为数据绑定的入口,整合observer,compile和watcher来监听自己的model数据变化,通过compile来解析编译模版,
最终利用watcher搭起observer和compile之间的通信桥梁,达到数据变化->更新视图:视图交互变化->数据model变更的双向绑定效果

  • 渐进式框架

    • vue和react一样都是一个渲染UI的js库,本身是不做路由管理、数据管理的,如果需要可以增加插件进行渐进式开发
  • vue的声明式渲染

    • 声明一个组件的实例,绑定数据,方法,在html模版中进行插值绑定,实现数据与视图的绑定,不用操作DOM进行数据的初始化和更新
  • MVC/MVVM

    • MVC 用户操作-》控制器controller-》数据模型model-》视图view-》用户操作
    • MVVM 视图view 《-》视图模型viewModel 《-》 数据模型model
    • VM就是基于controler上封装了一层,帮助用户实现了一些逻辑
  • computed和watch的区别

    • computed计算属性,依赖其他属性值,当依赖属性变化时重新计算,有缓存
    • watch监听,当监听属性变化时执行异步操作,比如请求数据
  • vue中跟数组赋值

    • 使用vue重写的数组splice方法,
    • 使用vm.set方法
  • vue生命周期

    • beforeCreate 组件创建之前
    • created 组件实例创建完成 可以请求数据
    • beforeMount 组件挂载之前 可以请求数据
    • mounted 组件挂载完成 可以请求数据
    • beforeUpdate 更新之前
    • updated 更新完成
    • beforeDestory 卸载之前
    • destoryed 卸载完成
    • activited 组件激活时调用,keep-alive专属
    • deactivited 组件失活时调用,keep-alive专属
  • 对keep-alive的理解

    • vue内置的一个组件,可以使被包含的组件保留状态,阻止被重复渲染
    • 一般跟路由组件结合使用,用于缓存路由组件
    • 两个属性include/exclude
    • 两个方法 activited/deactivited
  • vue中组件通信

    • props
    • $emit
    • 全局事件总线 b u s . bus. bus.emit/ b u s . bus. bus.on
    • vuex
  • SSR的优缺点

    • 服务端渲染优点
      • 更好的SEO
      • 更快的首屏渲染
    • 服务端渲染的缺点
      • 更多的开发条件限制
      • 更多的服务器负载
  • vue-rouder的路由模式

    • hash 使用URL 哈希值作为路由,支持所有浏览器
      • hash实现的原理
        • url中的hash值,只是客户端的一种状态,不会向服务器发送
        • hash值改变,都会在浏览器访问历史中增加一个记录,因此能通过浏览器按钮控制hash
        • 可以通过 拼接hash的url,或者修改localtion.hash,改变hash值
        • 通过hashchange事件监听hash的变化,从而实现路由跳转
    • history 依赖HTML5 history api和服务端配置
      • history实现的原理
        • HTML提供的两个API history.pushState(),history.replaceState()在不刷新浏览器的情况下,操作浏览器的历史记录
        • pushState,replaceState实现url的变化
        • 使用popState事件监听url的变化触发路由跳转
    • 支持所有js运行环境,如nodejs服务端
  • proxy与Object.definedPropProperty区别

    • proxy监听对象的变化,可以直接监听数组的变化
    • proxy返回的是新对象,直接操作对象达到目的,denfineProperty需要遍历属性操作
    • proxy有兼容性问题
  • 虚拟DOM的原理

    • 用js对象模拟真实DOM树,对真实DOM进行抽象
    • 使用diff算法对比两颗虚拟DOM树的差异
    • 将差异的部分更新成真实的DOM
  • 虚拟DOM的优缺点

    • 优点
      • 性能优化,保证性能下限,性能普世性,在不用手动优化的情况下,也能保持不错的性能
      • 无需手动操作DOM
      • 跨平台,与浏览器DOM无关,例如服务端渲染
    • 缺点
      • 首次渲染慢,初始渲染需要虚拟DOM计算,生成大量的真实DOM
      • 无法进行极致优化
  • 虚拟DOM中key的作用

    • key是虚拟DOM对象中列表数据的标示,在进行虚拟DOM的diff算法是,有很大作用
    • 当列表数据发生变化时,通过key进行虚拟DOM的diff算法
      • 当key没有变时
        • item没有变,直接使用真实DOM
        • item变了,对原来真实的DOM进行数据更新
      • 当key变了
        • 销毁原来的真实DOM
        • 即使是数据没变
    • key为index的问题
      • 添加/删除/排序 -》 产生没有必要的真实DOM更新 -》页面渲染没问题,效率低
      • 如果item有输入框 -》 产生错误的真实DOM更新 -》页面渲染有问题
      • 解决,使用唯一标示,比如id
  • vue3.0

    • proxy -》 Object.defineProperty
    • 模版,更改了作用域插槽,改成了函数的形式,避免了插槽的变化引起父组件的更新
    • 对象式的组件声明方式,对typescript的结合更加友好
  • vue与react的比较

    • react的jsx语法vue的.vue语法,都需要编译后使用
    • 都使用了虚拟DOM
    • 基本单位都是组件
    • 都是渐进式框架
    • react是单项数据流MVC模式,vue是双向数据绑定MVVM模式
  • 发布-订阅模式(观察者模式?)

    • 发布者
    • 缓存的订阅者列表
    • 发布消息,遍历缓存列表中的订阅者,调用订阅者的方法
    • obj.list = [] obj.listen = function obj.trigger = function
  • 函数柯里化

    • 是一种函数的高阶用法,用于函数转换,可以将一个函数多次调用,保存之前调用的参数变量
    • 具体原理就是返回多个包装器
  • 如何理解 HTML 语义化

    • 让人更易懂
    • 让机器更易懂,利于SEO
    • 在没有css时,能展现出基本的结构样式
  • script 标签中 defer 和 async 的区别

    • script :会阻碍 HTML 解析,只有下载好并执行完脚本才会继续解析 HTML。
    • async script :解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。
    • defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。

    作用域链
    函数内部可以直接读取全局变量
    在函数外部自然无法读取函数内的局部变量。
    对象访问变量时,先在自身作用域下查找,找不到时会一级一级地向上寻找所有父对象的变量。这就是作用域链

原型链
每个对象都有一个隐式原型__proto__,指向创建该对象的函数的原型prototype
访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。

闭包
函数作为返回值,函数作为参数传递。
闭包就是能够读取其他函数内部变量的函数
只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

你可能感兴趣的:(技术博客,前端,http,网络协议,面试)