面试题1

46 阅读9分钟

vue传值优化?
props $emit $attrs $listeners provide/inject refs parents\

复杂请求options的作用?
复杂请求可能对服务器数据产生副作用。例如delete或者put,都会对服务器数据进行修改,所以在请求之前都要先询问服务器,当前网页所在域名是否在服务器的许可名单中, 服务器允许后,浏览器才会发出正式的请求,否则不发送正式请求。

闭包就是由函数创造的一个词法作用域,里面创建的变量被引用后,可以在这个词法环境之外自由使用。闭包将变量变成局部变量 闭包通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。

es6 new Set()无重复值的有序列表。new Map()一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。

Symbol的时候,可以传入一个String类型的参数。不可改变且唯一的、

link和import 加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。

wepack多个页面

upload预览 FileReader

webpack钩子
entryOption entry 被处理过之后调用。
afterPlugins 在初始化内部插件集合完成设置之后调用
afterResolvers 分解器 resolver 设置完成之后触发。
initialize 当编译器对象被初始化时调用
beforeRun 在开始执行一次构建之前调用,compiler.run 方法开始执行后立刻进行调用
run 在开始读取 records 之前调用
watchRun 在监听模式下,一个新的 compilation 触发之后,但在 compilation 实际开始之前执行。
normalModuleFactory NormalModuleFactory 创建之后调用。
beforeCompile 在创建 compilation parameter 之后执行。

https和http

https是http的安全版本,也叫超文本安全传输,https是有加密传输协议的通道,并且SSL提供了安全加密基础,https主要是用于http的传输,并且在HTTP与TCP之间有一个特殊的加密/身份验证。

http是一种普通的传输协议,在互联网上,所有的文件都要遵守这个HTTP协议,同时超文本也是http传输的基本部分,实现客户端和服务器的相互请求

webpack独立打包与缓存处理

Mixins 可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,值的修改在组件中不会相互影响

vue hash原理
onhashchange事件来实现设置window.location.hash

window.onhashchange = function (e) {
    let hash = window.location.hash;
    if (hash == '#/home') {  
      home.style.display = 'block';
      about.style.display = 'none';
    } else if (hash == '#/about') {
      home.style.display = 'none';
      about.style.display = 'block';
    }
  } 

vue 双向数据绑定
第一步: 需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步: compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步: Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:

1、在自身实例化时往属性订阅器(dep)里面添加自己 2、自身必须有一个update()方法 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步: MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。\

vue异步加载
按需加载时使用vue异步加载
vue-router配置路由,使用vue的异步组件技术,可以实现按需加载
配置路由 component: resolve => require(['../components/PromiseDemo'], resolve)
使用webpack的require.ensure技术,也可以实现按需加载\

vue全局组件
Vue.component 来创建组件 Vue 实例话之前被引入

vuex
vuex Mutation不能使用异步函数
vuex Mutation 开发过程中,我们常常会追踪状态的变化。虽然也会使状态正常更新,但是会导致开发者工具有无法追踪到状态的变化。
造成状态改变的不可追踪,假设一个按钮我们需要每次点击是+1,从0开始。同步中使用Mutation连续点击3次我们可能见数据0,1,2,3。异步中使用Mutation则显示0,3. 和我们预期结果不一致,所以会造成状态改变的不可追踪。
State 数据源
Getters 对列表进行过滤并计数
Mutations
Actions
Modules 允许我们将 store 分割成模块 store.state.a // -> moduleA 的状态

计算属性与$watch的区别?
computed 与 watch 的区别在于,前者是在依赖的属性发生改变时触发回调函数,后者则是在属性本身发生改变时触发回调函数
computed是对属性的统一处理
Watch 根据变化重置这个属性
computed之后执行watch\

父beforeCreate-> 父create -> 子beforeCreate-> 子created -> 子mounted -> 父mounted

内存泄漏
为什么说隐藏数据了呢,因为普通用户只能通过get set等api对数据进行查看和更改等操作,没法对data直接更改,达到所谓隐藏数据的效果
闭包: 函数嵌套;在所在作用域外被调用
闭包:使用了外层区域某个变量,那么这个代码区域执行完之前,外层的那个变量肯定不能被释放,并且根据垃圾回收机制,被另一个作用域引用的变量不会被回收
定时器:this.timer = setInterval(()=>{console.log('i am still alive!')}, 500),千万注意this.timer = null并不能清理掉定时器!一定要写clearInterval(this.timer)才能清理掉

1.节流:n秒内只运行一次,若在n 秒后重复执行,只有一次执行
2.防抖: n秒后执行该事件,若在n秒后被重复触发,则重新计时
区别:防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。

Websocket它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。即:websocket分为握手和数据传输阶段,即进行了HTTP握手 + 双工的TCP连接。
client向server发起连接,server接受client连接。双方建立连接,Client与server完成一次读写之后,它们之间的连接并不会主动关闭,用心跳保活

cookie跨域 根域名相同的不同源的cookie才有可能实现跨域访问。 b.baidu.com获取域名a.baidu.com存储的cookie,涉及到跨域,给cookie设置domain属性即可 domain属性规定cookie的跨域范围,可以实现cookie被baidu.com或其子域名访问。 path默认为其根目录,path=/

vue data为什么是function 就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念,组件每复用一次 Object是引用数据类型。如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了 只有函数构成作用域(注意理解作用域。每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。

for in for of区别
for in遍历的是数组的索引(index)字符串,会便利遍历原型方法和属性, for of遍历的是数组元素值(value)

webpack打包原理是根据文件间的依赖关系对其进行静态分析,然后将这些模块按指定规则生成静态资源,当 webpack 处理程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个 bundle

new做了什么? 首先创一个新的空对象。
根据原型链,设置空对象的 proto 为构造函数的 prototype 。
构造函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)。
判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象。\

function myNew(context) {
  const obj = new Object();
  obj.__proto__ = context.prototype;
  const res = context.apply(obj, [...arguments].slice(1));
  return typeof res === "object" ? res : obj;
}

强缓存和协商缓存
强缓存浏览器会在响应头中cache-control:max-page=(单位为秒)no-cache每次都必须去服务端做新鲜度校验。
协商缓存会在响应头中有两个参数并且在下次请求时在 request header 就把这两个带上,服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源:
etag:每个文件有一个,改动文件了就变了,就是个文件hash,每个文件唯一。
last-modified:文件的修改时间,精确到秒
强缓存 从缓存取 200(from cache) 否,直接从缓存取
协商缓存 从缓存取 304(not modified) 是,正如其名,通过服务器来告知缓存是否可用
相同点:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据
不同点:强缓存不发请求到服务器,协商缓存会发请求到服务器\

200 - 成功。
301 - 永久重定向(配合 location,浏览器自动处理)。
302 - 临时重定向(配合 location,浏览器自动处理)。
304 - 资源未被修改。
403 - 没权限。
404 - 资源未找到。
500 - 服务器错误。
504 - 网关超时。

wepack钩子
environment 读取环境
afterEnvironment 读取环境后触发
initialize 初始化
beforeRun 运行前的准备活动,主要启动了文件读取功能
run “机器”已经跑起来了,在编译之前有缓存,则启用缓存,这样可以提高效率。
beforeCompile beforeCompile开始编译前的准备,创建的ModuleFactory,创建Compilation,并绑定ModuleFactory到Compilation上。同时处理一些不需要编译的模块,比如ExternalModule(远程模块)和DllModule(第三方模块)
compile 进行编译
make 编译的核心流程
afterCompile 编译结束
shouldEmit 获取compilation发来的电报,确定编译时候成功,是否可以开始输出了。
emit 输出文件
afterEmit 输出完毕
done 所有流程结束

AST解析过程

(1) 读取js文件中的 ( 字符流 )
(2) 通过 ( 词法分析 ) 生成 token ----------- 词法分析也叫扫描scanner,分词阶段,token是一维数组
(3) 通过 ( 语法分析 ) 生成 AST ------------- 语法分析也叫解析器
(4) 生成 ( 机器码 ) 执行 -------------------- 编译阶段也叫编译器\

webpack打包原理:
1、读取webpack的配置参数;
2、启动webpack,创建Compiler对象并开始解析项目;
3、从入口文件(entry)开始解析,并且找到其导入的依赖模块,递归遍历分析,形成依赖关系树;
4、对不同文件类型的依赖模块文件使用对应的Loader进行编译,最终转为Javascript文件;
5、整个过程中webpack会通过发布订阅模式,向外抛出一些hooks,而webpack的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。

webpack热模块更新的总结如下:
通过webpack-dev-server创建两个服务器:提供静态资源的服务(express)和Socket服务
express server 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
socket server 是一个 websocket 的长连接,双方可以通信
当 socket server 监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)
通过长连接,socket server 可以直接将这两个文件主动发送给客户端(浏览器)
浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新

webpack优化
happypack多实例构建 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 它将任务分解给多个子进程去并发执行,子进程处理完后再将结果发给主进程。 这个库作者已经不维护了,webpack4 后的推荐使用 thread-loader
CommonsChunkPlugin 提取分离第三方库和公共模块 通过entry.vendor:[vue] plugins:{new wepack.optimize.commonsChunkPlugin('vendor', 'vendor.js')}
thread loader 多实例构建 某个任务消耗时间较长会卡顿,多进程可以同一时间干多件事,效率更高 options: { workers: 2 } 进程数2
减少 resolve 的解析 把 loader 应用的文件范围缩小
babel-loader 开启缓存 cacheDirectory
terser-webpack-plugin 开启 parallel 参数 并行压缩

vue2.0双向数据绑定 发布-订阅模式 observable 数据劫持:object.defineProperty绑定的对象,对象时触发get和set方法来触发一系列视图更新 watcher 依赖收集:每个组件都会有相对应watcher实例,当我们操作数据时,依赖项的setter会被调用,并通知watcher重新计算

vue3.0组合API和vue mixins
vue2.0mixin缺陷 1.属性名冲突,导致mixin中数据被替换。 2.无法向mixin传入参数

var提升问题
先解析代码,获取到所有被声明的变量。然后再运行。所有变量的声明语句都会被提升到代码头部。 computed属性的结果是会被缓存的,并且依赖响应式数据的变化才会发生改变 定义的函数接收return的结果,return属于同步执行的,是没办法拿到异步请求结果的

event loop 主线程 主线程空了,就会去读取"任务队列" 任务队列 在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。 根据这个异步事件的类型,实际上会被放到宏任务队列或者微任务队列。 当前调用栈执行完毕时会优先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件

diff 当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁
通过isSameVnode进行判断,相同则调用patchVnode方法
找到对应的真实dom,称为el
如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
如果oldVnode有子节点而VNode没有,则删除el子节点
如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点

自定义指令 directive

props为什么不建议修改

created前做了什么
initInjections(vm): 让子组件inject的项可以访问到正确的值。
initState(vm): 将组件定义的状态挂载到this下。
initProvide (vm): 初始化父组件提供的provide依赖。
created: 执行组件的 created 钩子函数。

单点登陆
cross-storage框架解决跨域问题 www.jianshu.com/p/5234b0984… github.com/zendesk/cro…