一、Webpack
二、Vue
1、diff
- 面试题:
- mixin和mixins:
- vue 虚拟 diff:
- diff 详细步骤:
- Vue3 diff:
- React、Vue2、Vue3的三种Diff算法
- 没有key的diff
- Diff。具体流程patch、sameVnode、patchVnode、updateChildren 方法实现
- Key的作用 对比 场景
- vue3.0特性 好
- vue3.0特性 移除的
所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标
签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它
们,否则vue只会替换其内部属性而不会触发过渡效果。
key的作用是尽可能的复用 DOM 元素
- 虚拟dom 优点:
保证性能下限。 操作真实的dom结构是一件非常昂贵的事情,虚拟Dom利用js对象来模拟真实的dom,从而降低了逻辑层面对dom结构操作的成本
无需操作真实的dom。 通过双向数据绑定,当数据发生改变的时候,dom结构中的节点自动更新,无需我们手动处理
可移植性高,跨平台性好。 无论是vue、react还是weex等,我们都能看到虚拟dom的身影,通过各自的渲染进制进行将Dom结构渲染出来
缺点:
- 无法进行极致优化: 虽然虚拟 DOM+合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
2、响应式 watch computed nextTickt
nextTick知道吗,实现原理是什么?
在下次 DOM 更新循环结束之后执行延迟回调。nextTick主要使用了宏任务和微任
务。根据执行环境分别尝试采用
* Promise
* MutationObserver
* setImmediate
* 如果以上都不行则采用setTimeout
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。
官网的生命周期图中,init reactivity是晚于beforeCreate但是早于 created的。
watch加了immediate,应当同init reactivity周期一同执行,早于created。
而正常的watch,则是mounted周期后触发data changes的周期执行,晚于created。
3、生命周期、router、vuex、插件...
- vue父子生命周期:
- Vue 生命周期详解:
- MVC MVVM MCVP:
- vue-router 文档:
- vue-router原理:
- 前端路由:
- Vuex文档:
- Vuex实现方法原理:
- 源码分析:
- 插件方法
- 插件流程
- Vue cli3 库模式搭建组件库并发布到 npm:
- 组件库按需加载-babel-plugin-component:
- 按需加载的原理
- Function VS Class 组件
- Mixins HOC
- Vue3.0 Function API
- Vue3 究竟好在哪里?(和 React Hook 的详细对比)
- HOC、Render props、Hooks
- vue中extend,mixins,extends,components,install的几个操作
- vue scope
- vue install 插件机制 及在vuex和vue-router中的处理 内部实现
- extend,extends,minxin,minxins的用法和区别
- v-for v-if优先级
- v-show v-if却别机使用场景
三、React
juejin.im/post/684490… juejin.im/post/684490… juejin.cn/post/684490… 事件处理 核心思想
- setState:
- react中constructor和super:
- Flux、Redux、Vuex、MobX
- Redux 与 Mobx 思想的适用场景
- setState 做了什么
- hooks 闭包
- react hooks
四、HTTP 加密 跨域
常见md5,SHA1,RSA、ECC、HMAC
www.imooc.com/article/291… 跨域设置cookie
- localstorage的跨域存储方案:
- 详解 Cookie,Session,Token
- cookie localStorage sessionStorage区别
- 前端localstorage+cookie 解决同主域名跨域传值
另外,不同浏览器无法共享localStorage和sessionStorage中的信息。同一浏览器的相
同域名和端口的不同页面间可以共享相同的 localStorage,但是不同页面间无法共享
sessionStorage的信息。这里需要注意的是,页面仅指顶级窗口,如果一个页面包含多个
iframe且他们属于同源页面,那么他们之间是可以共享sessionStorage的。在实际开发
过程中,遇到的最多的问题就是localStorage的同源策略问题。为了了解这个问题,我们
先得清楚什么是同源策略。同源策略(same-origin policy)是浏览器执行的一种安全措
施,目的是为了保证用户信息的安全,防止恶意的网站窃取数据。浏览器的同源策略具体如下:
- XSS CSRF:
- http无response问题排查
1. 通过抓包分析,请求是否通过浏览器达到服务器,这个可以通过抓包中的IP进行查看,查看是否有当前的请求达到服务器,如果没有达到,那问题很明显就是发出请求后,没有达到服务器。
2. 如果抓包分析,服务器有相应的反应,但是没有下发response,这个时候就要推断tomcat服务是否存在问题,是否并发过大,导致出来不过来超时等等。
3. 如果抓包分析,服务器有相应的回应,并且response下发握手,但是没有相应的浏览器端,这个时候就要看服务器端的网络,这个也是可以通过抓包分析到底在那个网络端受到阻碍。
1.在首部后少加了/r/n,回车换行,服务器判断你请求还没发送完,所以没有响应。
2.centent-length和content内容不对应;也就是说length数值写大了,还没有读取到length值大小的数据,所以服务器判断你请求没发送完
五、 CSS
六、 GIT
七、模块化
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
CommonJS 模块输出: 值拷贝 加载方式: 对象
ES6 模块输出: 引用(符号链接) 加载方式: 静态解析
AMD 依赖前置 requirejs
CMD 就近依赖 seajs
八、算法、数据结构
栈(先进后出)、队列(先进先出)
- Js数据类型如何存储:
- 链表数组区别:
- Js数组方法:
- 哪些改变原数组:
- Js字符串方法:
- Js基础数据类型,以及如何存储,null undefined区别:
- 数据在内存中的存储
- 64 道算法题
- 栈、堆、队列深入理解
九、优化
- 前端性能与异常上报:
- 移动端性能优化:
- Performance:
- vue首屏加载优化:
- 常规首屏优化:
- 优化的性能指标:
- 骨架屏:
- 垃圾回收 & 内存管理:
- 常见内存泄漏
- Js优化
- 页面加载、页面渲染、vue项目优化、webpack方向
- 长列表怎么优化
- webpack优化
- http 优化
- http缓存优化
- 数组优化 ArrayBuffer
* web worker? (感觉还是同步的比较好点,之前也没实际尝试过)
* 把长数组截成数段后通过计算找到对应的再去slice?(这个目前正在尝试)
* ArrayBuffer?(听说性能很好...)
十、工程化、自动化
十一、JavaScript
- 事件循环:
- setImmediate 、setTimeout 、 process.nextTick:
- 隐式型转换
- ES6:
- 交集、并集、补集 :
- 实现JSON.stringify和JSON.parse:
- Object.create:
- 临时性死区(TDZ):
- 常见加密算法:
- AST抽象语法树:
- 浏览器多线程和js为啥是单线程:
- ajax、fetch、axios:
- 深拷贝:
- Node:
- NodeJS有难度的面试题
- 面试官问你关于node的那些事(进阶篇)
- 面试官问你关于node的那些事(基础篇)
- koa实现
- JS 实现两个大数相加 0.1 + 0.2 !== 0.3,大数相加: [0.2+0.3]juejin.cn/post/684490…
- JS 异步发展流程 —— 异步历史:
- Promise中的then第二个参数和catch有什么区别:
- RESTful AP:
- 并发限制异步调度器,保证同时最多运行2个任务
promise www.jianshu.com/p/0c737e899…
- 数组去重,考虑了数字字符
- 合并两个有序数组
十二、Promise
- 详细Promise Generator async
- promise原理实现
- 手写 Promise
- 简单实现Promise流程
- 手写 Promise.all
- Promise 实现async 有点复杂讲解详细:
- 非Promise 实现async await:
- 错误捕获:
- 串行promise:
- Promise中的then第二个参数和catch有什么区别:
- JS 异步发展流程 —— 异步历史:
- 历史、回调、promise、Generator、async-await 好 promise原理
- promise实现
- 异步流程控制、单一请求、并发请求,按顺序处理结果,控制最大并发数
- JS Ajax并发请求控制,串行、并行、promise.all 并发控制
- 中断promsie
- 最小编辑距离:给出两个单词word1和word2,计算出将word1 转换为word2的最少操作次数
- promise实现原理
说到底,Promise 也还是使用回调函数,只不过是把回调封装在了内部,使用上一直通过 then 方法的链式调用,使得多层的回调嵌套看起来变成了同一层的
promise的缺点 1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。 2、如果不设置回调函数,promise内部抛出的错误,不会反应到外部。 3、当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
promis的优点
1.解决回调地狱(Callback Hell)问题 (1)有时我们要进行一些相互间有依赖关系的异步操作,比如有多个请求,后一个的请求需要上一次请求的返回结果。过去常规做法只能 callback 层层嵌套,但嵌套层数过多的话就会有 callback hell 问题。比如下面代码,可读性和维护性都很差的。
十三、原型链 作用域 继承 闭包 new this
要创建 Person https://juejin.cn/post/6892033805143277575
的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下
4
个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。
- 封装、继承、多态:
- 关于setInterval和setTImeout中的this指向问题
- this 指向
- 手动实现new, call, apply, bind,深浅拷贝,防抖,节流,Promise.all()
- 多种方式实现 LazyMan sleep
1、this永远指向函数运行时所在的对象,而不是创建时所在的对象,箭头函数除外
2、匿名函数和不处于任何对象中的函数,this指向window
3、call,apply,bind指的this是谁就是谁
4、普通函数调用,函数被谁调用,this就是谁箭头函数中没有this绑定,必须通过查找作用域链来决定其值。
如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象
this 指向
1、this永远指向函数运行时所在的对象
而不是创建时所在的对象,箭头函数除外
2、匿名函数和不处于任何对象中的函数,this指向window
3、call,apply,bind指的this是谁就是谁
4、普通函数调用,函数被谁调用,this就是谁箭头函数中没有this绑定,必须通过查找作用域链来决定其值。
如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象
编程领域中作用域分为静态作用域,和动态作用域,js中使用的是静态作用域
静态作用域,也叫词法作用域,代码写完后,变量的作用域就已经确定不变了
作用域是可访问变量的集合。
闭包是怎么定义的呢?当函数可以记住并访问所在的词法作用域时,就
产生了闭包,即使函数在当前词法作用域之外执行。来看一个具体例子:
function foo () {
var a = 2
function bar () {
console.log(a)
}
return bar
}
var baz = foo()
baz() //2
1、记住此法作用域,使其不被销毁
2、能够访问函数所在的词法作用域的变量
3、创建模块(设计私有变量,公有函数等)
使用场景:
http://www.cnblogs.com/star-studio/archive/2011/06/22/2086493.html
1、使用闭包代替全局变量
2、函数外或者其他函数中访问某一函数内部的参数
3、在函数执行之前为要执行的函数提供参数
4、在函数执行之前为函数提供在函数执行或饮用时
才能知道的具体参数
5、为节点循环绑定click事件,在事件函数中使用当
次循环的值或节点而不是最后一次的值或节点
6、暂停执行
7、包装相关功能
十四、设计模式
优点:
观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。 缺点:
如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
观察者模式与发布订阅模式都是定义了一个一对多的依赖关系,当有关状态发生变更时则执行相应的更新。 不同的是,在观察者模式中依赖于 Subject 对象的一系列 Observer 对象在被通知之后只能执行同一个特定的更新方法,而在发布订阅模式中则可以基于不同的主题去执行不同的自定义事件。相对而言,发布订阅模式比观察者模式要更加灵活多变。 我认为,观察者模式和发布订阅模式本质上的思想是一样的,而发布订阅模式可以被看作是观察者模式的一个进阶版。 设计模式只是一种思想,某一种设计模式都可以有很多种不同的实现方式,各种实现都有其优劣之分,具体的实现方式需要基于不同的业务场景。上述是我对观察者模式和发布订阅模式学习之后的一些理解
十五、事件流 事件委托 New this bind 防抖和截流
1、IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档
中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
2、捕获时间流:,document对象首先接收到click事件,然后事件沿DOM树依次向下,一
直传播到事件的实际目标,即<div>元素。图片展示了事件捕获的过程。
target在事件流的目标阶段;
currentTarget在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,
两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,
target指向被单击的对象
currentTarget指向当前事件活动的对象(一般为父级)。
事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到 document 层次(根元素),也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必为每个可点击的元素分别添加事件处理程序。
事件委托的优点
* 可以大量节省内存占用,减少事件注册
* 可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
使用事件委托注意事项
使用“事件委托”时,并不是说把事件委托给的元素越靠近顶层就越好。
事件冒泡的过程也需要耗时,越靠近顶层,事件的”事件传播链”越长,也就越耗时。
第三个参数
* true - 事件句柄在捕获阶段执行
* false- false- 默认。事件句柄在冒泡阶段执行
防抖:高频出发的事件,在指定单位时间内,只响应最后一次.
截流:高频触发的事件,在指定单位时间内,只响应第一次,如果在指定时间内再次触发则
只重新计算时间
十六、编程
var lowestCommonAncestor = function(root, p, q) {
//上述情况2
if (!root || root == p || root == q) return root
//找不到,遍历左右子树
const left = lowestCommonAncestor(root.left, p, q)
const right = lowestCommonAncestor(root.right, p, q)
//上述情况1
if (left && right) return root
//上述情况3
if (left) return left
return right
};
addEventListener第三个参数
*
true - 事件句柄在捕获阶段执行 *
false - false - 默认。 事件句柄在冒泡阶段执行
var a = document.getElementById('outer');
var b = document.getElementById('p');
a.addEventListener('click', function(e) {
console.log(b);
console.log(e.target === b);
if (e.target !== b) {
// 执行
console.log('执行')
}
}, true);
- js实现的map方法
function Map() {
var struct = function(key, value) {
this.key = key;
this.value = value;
};
// 添加map键值对
var put = function(key, value) {
for (var i = 0; i < this.arr.length; i++) {
if (this.arr[i].key === key) {
this.arr[i].value = value;
return;
}
};
this.arr[this.arr.length] = new struct(key, value);
};
// 根据key获取value
var get = function(key) {
for (var i = 0; i < this.arr.length; i++) {
if (this.arr[i].key === key) {
return this.arr[i].value;
}
}
return null;
};
// 根据key删除
var remove = function(key) {
var v;
for (var i = 0; i < this.arr.length; i++) {
v = this.arr.pop();
if (v.key === key) {
continue;
}
this.arr.unshift(v);
}
};
// 获取map键值对个数
var size = function() {
return this.arr.length;
};
// 判断map是否为空
var isEmpty = function() {
return this.arr.length <= 0;
};
this.arr = new Array();
this.get = get;
this.put = put;
this.remove = remove;
this.size = size;
this.isEmpty = isEmpty;
}
var map = new Map();
map.put(1, 1);
map.put("1", "1");
console.log(map.get(1));
console.log(map.get('1'));
function foo() {
setTimeout(() => {
foo();
})
}
foo();
- 统计数组中每个元素出现的次数,考虑了字符串及数值
var arr = ['2', 1, 5, 4, 7, '9', 4, 1, '2', 6, 8, 2];
for (var i = 0, len = arr.length, newArr = []; i < len; i++) {
var isPush = true;
for (var j = 0, l = newArr.length; j < l; j++) {
if (arr[i] === newArr[j].val) {
isPush = false;
newArr[j].count++;
}
}
if (isPush) {
newArr.push({
val: arr[i],
count: 1
});
} else {
isPush = true;
}
}
console.log(newArr);
就是下载文件时,不必重头开始下载,而是从指定的位置继续下载,这样的功能就
叫做断点续传。 断点续传的理解可以分为两部分:一部分是断点,一部分是续
传。断点的由来是在下载过程中,将一个下载文件分成了多个部分,同时进行多个部
分一起的下载,当某个时间点,任务被暂停了,此时下载暂停的位置就是断点了。
续传就是当一个未完成的下载任务再次开始时,会从上次的断点继续传送。
以前文件无法分割,但随着html5新特性的引入,类似普通字符串、数组的分割,
我们可以可以使用slice方法来分割文件。所以断点续传的最基本实现也就是:前端
通过FileList对象获取到相应的文件,按照指定的分割方式将大文件分段,然后一
段一段地传给后端,后端再按顺序一段段将文件进行拼接。
而我们需要对FileList对象进行修改再提交,在之前的文章中知晓了这种提交的一
些注意点,因为FileList对象不能直接更改,所以不能直接通过表单
的.submit()方法上传提交,需要结合FormData对象生成一个新的数据,通过
Ajax进行上传操作。