前端硬核知识点(一)

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,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。

image.png

参考地址:https://www.cnblogs.com/chenhuichao/p/10818396.html

简述 Javascript 原型以及原型链
image.png

参考地址:https://www.cnblogs.com/loveyaxin/p/11151586.html

简述 Vue 的生命周期
image.png image.png
简述浏览器的缓存机制
image.png

参考地址:https://www.cnblogs.com/suihang/p/12855345.html

简述 diff 算法的实现机制和使用场景

场景:diff算法用来修改一小段dom,不会引起dom树的重绘
机制:diff算法将virtual dom的某个节点数据改变后生成的新的vnode与旧的节点比较,并替换为新的node
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

image.png

参考:https://www.cnblogs.com/wind-lanyan/p/9061684.html

简述虚拟 dom 实现原理

虚拟DOM:

是一个JS对象。它的作用是判断DOM是否改变、 哪些部分需要被重新渲染。 vdom完全是用js去实现,和宿主浏览器没有任何联系,此外得益于js的执行速度,将原本需要在真实dom进行的创建节点,删除节点,添加节点等一系列复杂的dom操作全部放到vdom中进行,这样就通过操作vdom来提高直接操作的dom的效率和性能。

  1. 用JavaScript模拟DOM树,并渲染这个DOM树
  2. 比较新老DOM树,得到比较的差异对象
  3. 把差异对象应用到渲染的DOM树。

比较两棵DOM树的差异,是虚拟DOM的最核心部分,这也是人们常说的虚拟DOM的diff算法,两颗完全的树差异比较一个时间复杂度为 O(n^3)。但是在我们的web中很少用到跨层级DOM树的比较,所以一个层级跟一个层级对比,这样算法复杂度就可以达到 O(n)。如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajMBAqeT-1610607911333)(https://i.loli.net/2021/01/05/rB5VNbkyGUZvmQp.png)]

流程:
image.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马上调用这个匿名函数
image.png

如果我们不加另一对括号,直接写成

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 的区别是什么?
image.png

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值