前言
分享一下最近面试碰到的一些题目,有些题目特别基础的题目,比如箭头函数什么作用这里就不写了。
vue实现原理
最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的.
- 实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
- 实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
- 实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图.
- mvvm入口函数,整合以上三者
defineProperty有一个缺点就是你无法绕过定义属性这一行为,es6有一个解决方法参考学习es6的proxy 和 reflect。 再分享一个Github上一个mvvm实现:vue实现原理
vuex 和 redux 差异
Vuex 其实是一个针对 Vue 特化的 Flux,主要是为了配合 Vue 本身的响应式机制。当然吸取了一些 Redux 的特点,比如单状态树和便于测试和热重载的 API,但是也选择性的放弃了一些在 Vue 的场景下并不契合的特性,比如强制的 immutability(在保证了每一次状态变化都能追踪的情况下强制的 immutability 带来的收益就很有限了)、为了同构而设计得较为繁琐的 API、必须依赖第三方库才能相对高效率地获得状态树的局部状态等等(相比之下 Vuex 直接用 Vue 本身的计算属性就可以)所以 Vue + Vuex 会更简洁,也不需要考虑性能问题,代价就是 Vuex 只能和 Vue 配合。Vue + Redux 也不是不可以,但是 Redux 作为一个泛用的实现和 Vue 的契合度肯定不如 Vuex。
作者:尤雨溪
链接:https://www.zhihu.com/question/38546875/answer/76970954
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
通过proxy实现数据劫持
const OBSERVERS = new Set(); //定义一个集合存放监听函数
const observeFn = fn => OBSERVERS.add(fn); //定义一个监听器函数
const observeObj = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) { //劫持set
const result = Reflect.set(target, key, value,receiver);
OBSERVERS.forEach(observeFn => observeFn());
return result;
}
var person = observeObj({
name: '张三',
age: 20
});
function print() {
console.log(`${person.name}, ${person.age}`)
}
function warn() {
alert(person.name)
}
observeFn(warn);
observeFn(print);
person.name = '李四';
react生命周期 & setState
组件挂载中执行的函数:
- constructor():ES6类的构造函数(为了初始化state或绑定this)
- getInitialState():ES5中初始化state。(现在只需要在写在1中)
- getDefaultProps():ES5中初始化props。在ES6中使用defaultProps()方法。(可以写在1中,通过props)
- componentWillMount:组件挂载前调用,只执行一次。
- render():渲染组件,必须实现该方法。
- componentDidMount: 组件挂载后调用,只执行一次
组件的props或者state改变时更新函数:
- componentWillReceiveProps(nextProps): 当父组件的render()方法执行后就会触发该方法。初始化时不调用。
- shouldComponentUpdate(nextProps,nextState):当props改变或state改变时调用,初始化时不调用,返回boolean。true表示继续执行render方法,fasle表示放弃本次渲染。
- render():渲染组件。
组件卸载函数:
- componentWillUnmount():将组件从DOM树移出,防止内存溢出。
setState() 用于安排一个组件的 state 对象的一次更新。当状态改变时,组件通过重新渲染来响应。简单说一下原理,调用函数,react内部会执行一个任务,获取当前state,执行state更新,如果一个任务还未完成,并发了很多个setstate,react会将这些set 统一成一个更新任务,执行后只会进行一次dom更新。
虚拟dom原理
利用js解析html生成虚拟dom树,大致结构如下代码,然后利用这个虚拟dom树生成一个真的dom树渲染到页面。
diff算法:在改变dom的时候,会重新构造一个dom树,用来和旧的树相比,提取差异的部分应用到真实的dom树上。
采用虚拟dom最根本的原因就是dom操作性能消耗极大,缺点就是要写一大堆构件虚拟dom的js代码。根据项目dom操作多不多,权衡利弊合理使用虚拟dom。
var element = {
tagName: 'ul', // 节点标签名
props: { // DOM的属性,用一个对象存储键值对
id: 'list'
},
children: [ // 该节点的子节点
{tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
{tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
{tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
]
}
上面对应的HTML写法是:
<ul id='list'>
<li class='item'>Item 1</li>
<li class='item'>Item 2</li>
<li class='item'>Item 3</li>
</ul>
移动端屏幕适配 & 触碰事件
- 采用flexable等插件,需要了解其原理(比如动态改写meta,html的font-size,设备dpr值等)
- 使用css3 嗅探改变font-size ,适配不同dpr的font-size
触摸屏幕发生的事件
- click: 类似pc的click,但连续触发有200ms左右的延迟
- touchstart:手指触摸到屏幕会触发
- touchmove:当手指在屏幕上移动时,会触发
- touchend:当手指离开屏幕时,会触发
- touchcancel:可由系统进行的触发,比如手指触摸屏幕的时候,突然alert了一下,或者系统中其他打断了touch的行为,则可以 触发该事件
express 和 koa 差异
- express采用es5的callback模式,而koa采用co框架实现promise回调
- koa只保留基本语法,抛弃了express内置route,static等中间件
webpack原理及优化
原理
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
优化
- 利用UglifyPlugin删除引用未使用的无用代码,压缩js代码,css添加minimize参数压缩css
- 通过commonsChunkPlugin提取公共代码
- 通过ParallelUglifyPlugin多线程压缩js代码
- 缩小文件范围,通过exclude ,inclue等配置路径,优化打包效率
- 通过happypack插件多线程处理loader
- 通过dllplugin接入动态链接库
。。。webpack优化的方法还有很多,有兴趣的可以自行查阅
gulp基本原理
gulp可以认为是grunt的升级版,运用了node的流来处理文件,大大强化了性能。通过各种 Transform Stream 来实现文件的处理,然后再进行输出。Transform Streams 是 NodeJS Stream 的一种,是可读又可写的.
babel实现
- babel-core:babel转译器本身,提供了babel的转译API,如babel.transform等,用于对代码进行转译。像webpack的babel-loader就是调用这些API来完成转译过程的。
- babylon:js的词法解析器
- babel-traverse:用于对AST(抽象语法树,想了解的请自行查询编译原理)的遍历,主要给plugin用
- babel-generator:根据AST生成代码
babel的polyfill和runtime的区别:
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Set、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。
ssr和客户端渲染的区别
* ssr 在服务器就把数据填充到html,返回的是完整的页面,利于所搜索引擎seo
* 更快的内容到达时间,特别是网络较差的时候
* 服务端代码没有客户端那么灵活组合
* 相比客户端渲染,ssr有更高的服务器负载,成本增加。
垂直居中实现
///不知道父容器和自身高度
parentElement{
position:relative;
}
childElement{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
///使用flex
parentElement{
display: flex;
align-items: center;
}
web安全
xss攻击防御
- 对输出的html标签进行转义(htmlEncode)
- 对用户提交的数据进行验证,限制长度,特殊字符过滤等
sql注入防御
- 层级化数据库权限,不要使用管理员权限
- 对用户输入的信息进行数据库查询敏感词的过滤,限制长度等
后记
差不多就到这里了。这篇文章过年前po主将会持续更新,通过面试来找自己的不足是非常高效,面试官会针对你的简历,你的所学,针对性的考察你。前端路漫漫,其修远兮,慢慢走吧。
如果觉得本文对你有所帮助,就star一下吧~大传送之术! 我的博客Github