Vue 中双向数据绑定的实现原理是怎样的?
// 通过Object.defineProperty( )设置了对象Book的name属性
// get就是在读取name属性这个值触发的函数,set就是在设置name属性这个值触发的函数
// vue通过这种方法来进行数据劫持
var Book = {}
var name = '';
Object.defineProperty(Book, 'name', {
set: function (value) {
name = value;
console.log('你取了一个书名叫做' + value);
},
get: function () {
return '《' + name + '》'
}
})
Book.name = 'vue权威指南'; // 你取了一个书名叫做vue权威指南
console.log(Book.name); // 《vue权威指南》
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

参考地址:https://www.cnblogs.com/chenhuichao/p/10818396.html
简述 Javascript 原型以及原型链

参考地址:https://www.cnblogs.com/loveyaxin/p/11151586.html
简述 Vue 的生命周期


简述浏览器的缓存机制

参考地址:https://www.cnblogs.com/suihang/p/12855345.html
简述 diff 算法的实现机制和使用场景
场景:diff算法用来修改一小段dom,不会引起dom树的重绘
机制:diff算法将virtual dom的某个节点数据改变后生成的新的vnode与旧的节点比较,并替换为新的node
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

参考:https://www.cnblogs.com/wind-lanyan/p/9061684.html
简述虚拟 dom 实现原理
虚拟DOM:
是一个JS对象。它的作用是判断DOM是否改变、 哪些部分需要被重新渲染。 vdom完全是用js去实现,和宿主浏览器没有任何联系,此外得益于js的执行速度,将原本需要在真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作全部放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。
- 用JavaScript模拟DOM树,并渲染这个DOM树
- 比较新老DOM树,得到比较的差异对象
- 把差异对象应用到渲染的DOM树。
比较两棵DOM树的差异,是虚拟DOM的最核心部分,这也是人们常说的虚拟DOM的diff算法,两颗完全的树差异比较一个时间复杂度为 O(n^3)。但是在我们的web中很少用到跨层级DOM树的比较,所以一个层级跟一个层级对比,这样算法复杂度就可以达到 O(n)。如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajMBAqeT-1610607911333)(https://i.loli.net/2021/01/05/rB5VNbkyGUZvmQp.png)]
流程:
简述图片的懒加载原理
先将img标签的src链接设为同一张图片(这样只请求一次),然后给img标签设置自定义属性(比如 data-src),然后将真正的图片地址存储在data-src中,当JS监听到该图片元素进入可视窗口时,将自定义属性中的地址存储到src属性中,src变化发生请求,加载图片。达到懒加载的效果。
简述 Javascript 中的防抖与节流的原理并尝试实现
防抖:当持续触发事件时,一定时间内没有再触发事件,事件处理函数才会执行一次,防止短时间调用高频次数的事件。
// 防抖函数
function debounce(fn, delay) {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn(...args);
}, delay)
}
}
节流函数:当持续触发一个事件时,保证一段时间段内只执行一次。防止重复的 ajax 调用,防止请求数据的混乱,网络拥塞,占用服务器带宽,增加服务器压力。
// 节流函数
function throttle(fn, delay) {
let flag = true;
return function (...args) {
if (!flag) {
return;
}
flag = false;
setTimeout(() => {
fn(...args)
flag = true;
}, delay);
}
}
什么是闭包,什么是立即执行函数,它的作用是什么?简单说一下闭包的使用场景
闭包:能够读取其它函数内部变量的函数。闭包是将函数内部和函数外部连接起来的一座桥梁
使用场景:一个是可以读取函数内部的变量,另一个是让这些变量的值始终保持在内存中。
// 函数f2为闭包
// 注意,函数内部声明变量的时候,要使用var命令。如果不用的话,实际上声明了一个全局变量
// nAdd的值是一个匿名函数(anonymous function)
// nAdd这个匿名函数本身也是一个闭包,相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
立即执行函数:1声明一个匿名函数,2马上调用这个匿名函数
如果我们不加另一对括号,直接写成
function(){alert('我是匿名函数')}()
浏览器会报语法错误。想要通过浏览器的语法检查,必须加点小东西:
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
立即执行函数作用:创建一个独立的作用域。这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
// 问题例子
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
}
}
// for运行结束,i的值是6。用户肯定是在循环完后点击,得到的值就都是6
//解决例子
// 函数后的();表示要执行这个函数。所以要求后面这个括号()前面必须是一个表达式。
// !的作用是将function(){...}函数体转为一个函数表达式。
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
!function(ii){
liList[ii].onclick = function(){
alert(ii) // 0、1、2、3、4、5
}
}(i)
}
// 在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。
// i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 ii 「分别」是 0、1、2、3、4、5。
简述浏览题事件循环机制
调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环。
参考地址:https://www.cnblogs.com/yqx0605xi/p/9267827.html
localstorage 与 cookie 的区别是什么?

参考地址:https://www.cnblogs.com/candy-xia/p/11561542.html