闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

闭包在js中是一个很常见的一个结构,它允许你访问父级作用域的变量,并在持续保持引用时保证父级作用域的这个变量不会被内存回收机制回收。这样的特性,在实际项目开发中技能给我们带来很多方便与好处,但如果用的不好,也可能能导致内存泄漏,让你的项目卡顿。

我们今天要讨论的主要是在Vue源码中的一些闭包的使用,并且通过这些使用实例深入的了解闭包的运行原理。

下面,我们就暂举Vue源码中使用闭包的两个例子来看看Vue是如何使用闭包的吧(事实上,Vue源码中使用闭包来实现功能的地方不胜枚举,此处只是挑出两个比较有代表性的实例讲解,如果想了解更多,可以详细研读Vue源码,相信你会收获满满):

  • 数据响应化Observer中使用闭包
// 注:由于Vue源码中有大量与闭包不相关的代码可能会影响阅读和理解,
// 故此处不照抄Vue源码,而是本人根据Vue源码的实现原理实现的简易版响应式代码,方便阅读与理解
function defineRealive(target, key, value){return Object.defineProperty(target, key, {get(){console.log(`通过getter获取数据:${value}`);return value;},set(val){console.log(`通过setter设置数据:新值-${val};旧值-${value}`);// 很多人会疑问,value明明是形参,为什么给他赋值就能够达到数值改变的效果呢?形参不是出了这个函数就没用了么?// 其实,这就用到了闭包的原理,value是外层函数defineRealive的参数,而我们实际上使用value确是在内层的get或set方法里面// 这样就形成了一个闭包的结构了。根据闭包的特性,内层函数可以引用外层函数的变量,并且当内层保持引用关系时外层函数的这个变量// 不会被垃圾回收机制回收。那么,我们在设置值的时候,把val保存在value变量当中,然后get的时候再通过value去获取,这样,我们再访问// obj.name时,无论是设置值还是获取值,实际上都是对value这个形参进行操作的。value = val;}});
}let obj = {name: 'kiner',age: 20
};Object.keys(obj).forEach(key=>defineRealive(obj, key, obj[key]));obj.name = 'kanger';// 控制台输出:通过setter设置数据:新值-kanger;旧值-kiner
obj.age = 18;// 控制台输出:通过setter设置数据:新值-18;旧值-20// 控制台输出:通过getter获取数据:kanger
// 控制台输出:通过getter获取数据:18
// 控制台输出:kanger 18
console.log(obj.name,obj.age);

如果觉得上面的代码还是不容易理解,那么,我们换种方式再看看:

// 这样是不是就比较好理解了呢,形参也是一个普通的局部变量,只是可能我们平时使用的时候,
// 一般不会对形参进行赋值操作,因为大部分情况,形参都是外部传入的数据,我们无需修改。
// 所以,我们直接理解为:我们在一个函数外定义了一个变量,然后在函数内使用这个变量,而这个变量
// 在内部函数,无论是get、还是set,其实都是同一个。我们只是用这个变量拿来暂存数据而已
function defineRealive(target, key, value){// 相比上面的代码,实际只加了这一行,以及后面参数的参数名,把形参保存在一个局部变量里面let realValue = value;return Object.defineProperty(target, key, {get(){console.log(`通过getter获取数据:${realValue}`);return realValue;},set(val){console.log(`通过setter设置数据:新值-${val};旧值-${realValue}`);realValue = val;}});
}
  • 全局Api中的$watch方法中使用闭包
// 根据Vue的$watch原理实现的简易版$watch
Vue.prototype.$watch = function(exp, cb, options = {immediate: true, deep: false}) {let watcher = new Watcher(this, exp, cb, options);return () => {watcher.unWatch();};
}

从$watch方法的实现中,我们可以看出,这其实也是一个闭包的结构,用户调用方法时,会实例化一个Watcher对象并保存在变量watcher,然后返回一个函数,在这个函数里面,调用了watcher下的unWatch方法。也就是说,用户可以通过以下方式进行监听/移除监听属性变化


let obj = {name: 'kiner',age: 20
};//  监听obj.name的改变
let unWatchName = this.$watch("obj.name",function(newVal, oldVal){console.log(`新值:${newVal};旧值:${oldVal};`);
});// 取消监听,取消后,obj.name的改变不再会通知
unWatchName();

这样实现的巧妙之处在于,我们无须关心要调用谁去取消监听,你怎么监听的,他就给你返回一个取消监听的方法,直接调用这个方法取消就可以了。

通过上面的讲解,你是否对闭包的使用有了更加深入的认识呢,如果对闭包的使用有什么疑问或者有什么新奇的想法的话,欢迎一起讨论研究。

Vue源码学习之Vue对于闭包的使用相关推荐

  1. vue源码学习--vue源码学习入门

    本文为开始学习vue源码的思路整理.在拿到vue项目源码的之后看到那些项目中的文件夹,会很困惑,不知道每个文件夹内的世界,怎么变换,怎样的魔力,最后产生了vue框架.学习源码也无从学起.我解决了这些困 ...

  2. Vue源码学习之Computed与Watcher原理

    前言  computed与watch是我们在vue中常用的操作,computed是一个惰性求值观察者,具有缓存性,只有当依赖发生变化,第一次访问computed属性,才会计算新的值.而watch则是当 ...

  3. Vue源码学习 - 组件化(三) 合并配置

    Vue源码学习 - 组件化(三) 合并配置 合并配置 外部调用场景 组件场景 总结 学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:<Vue.js2.0 源码揭秘>. 黄轶 ...

  4. VUE源码学习第一篇--前言

    一.目的 前端技术的发展,现在以vue,react,angular为代表的MVVM模式以成为主流,这三个框架大有三分天下之势.react和angular有facebook与谷歌背书,而vue是以一己之 ...

  5. Vue源码学习 - 组件化一 createComponent

    Vue源码学习 - 组件化一 createComponent 组件化 createComponent 构造子类构造函数 安装组件钩子函数 实例化 VNode 总结 学习内容和文章内容来自 黄轶老师 黄 ...

  6. Vue源码学习 - 准备工作

    Vue源码学习 - 准备工作 准备工作 认识Flow 为什么用 Flow Flow 的工作方式 类型推断 类型注释 数组 类和对象 null Flow 在 Vue.js 源码中的应用 flow实践 总 ...

  7. Vue源码学习之initInjections和initProvide

    Vue源码学习之initInjections和initProvide 在进行源码阅读之前先让我们了解一个概念:provide/inject,这个是Vue在2.2.0版本新增的一个属性,按照Vue官网的 ...

  8. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  9. Vue源码学习: 关于对Array的数据侦听

    摘要 我们都知道Vue的响应式是通过Object.defineProperty来进行数据劫持.但是那是针对Object类型可以实现, 如果是数组呢? 通过set/get方式是不行的. 但是Vue作者使 ...

  10. Vue源码学习(一):源码的入口在哪里

    Vue源码解读系列 文章目录 Vue源码解读系列 前言 一.源码下载 二.目录解读 三.找到打包入口文件 四.如何进行代码调试 总结 前言   如何设计API和如何使用元编程思想(元编程,简单说是指框 ...

最新文章

  1. 服务器默认字符集 网页乱码,关于apache默认字符集乱码的问题
  2. 计算机网络期末复习提纲
  3. 【图像处理】——在plt绘制的坐标窗口中,捕获鼠标点,在右下角显示点的坐标
  4. 4月9日51CTO.com编辑部训练
  5. Android入门笔记03
  6. wacom数位板怎么调压感_手绘板压感是什么 数位板压感怎么调【教程】
  7. matlab 离散求偏导,matlab怎么求离散曲面的偏导数
  8. 语音识别特征处理(MFCC,Fbank,PNCC)
  9. TokenGazer评级丨Storj:V3 升级方案带来更好前景,但仍面临技术和竞争上的挑战...
  10. 有钱人和你想的不一样
  11. Golang:加密解密算法
  12. Android实现mp3音频剪辑(带试听)
  13. 《激荡三十年》——来了解我们的时代
  14. 学生信息管理系统——查询学生信息(Java+web综合)
  15. android 车载控制手机音乐播放器,【图】浅谈车载音响播放器之安卓篇
  16. Programmer Dvorak键盘布局
  17. QA 特辑 | 百万员工不上班也能领全勤奖的原因都在这里了!
  18. 【听】情人,罗曼蒂克消亡史
  19. 【洛谷P2598】狼和羊的故事【网络流】
  20. cache命中页表命中么_最伟大的命中

热门文章

  1. codeblock的若干使用技巧
  2. 【pyqt5学习】——日历控件calendarWidget设置单元格格式(前景、背景)、日历控件属性编辑
  3. sublime text3之使用等宽字体
  4. 大疆新品:机甲大师RoboMaster S1介绍(AI 学习小伙伴)
  5. JAVA从入门到放弃01
  6. 01.网络工程师常识
  7. 微信小程序 图片处理:压缩、上传、审核
  8. 工业条形码扫描枪:如何为您的应用选择合适的扫描枪
  9. wps表格宏被禁用如何解禁_宏被禁用怎么办?excel/word宏已被禁用解决方法
  10. paraview使用GUI连接服务器