[JS] Topic - this is ”closure“
Ref: 为什么要用闭包?
背景
闭包是自带运行环境的函数
发哥是自带背景音乐的男人~
就是有权访问另一个函数作用域的变量的函数。
函数式编程的闭包,就是函数的调味包。
方便用户调用函数。不必为了维护繁杂的外部状态而烦恼。
我们常见的闭包形式就是:【基于静态作用域的一个编程技巧】
(1) a 函数套 b 函数,
(2) 然后 a 函数返回 b 函数,
这样 b 函数在 a 函数以外的地方执行时,依然能访问 a 函数的作用域。
其中 “b 函数在 a 函数以外的地方执行时” 这一点,才体现了闭包的真正的强大之处。
静态作用域
Ref: 浅谈静态作用域和动态作用域
Ref: JavaScript 词法、静态、动态作用域初级理解
若干需要关注点(概念)
1)执行环境(作用域)函数执行环境 变量作用域 2)函数作用域和声明提前 3)自由变量 4)词法作用域和静态作用域 5)动态作用域
1)执行环境(作用域)函数执行环境 变量作用域
每个执行环境都有一个与之关联的“变量对象(variable object)”,环境中定义的所有变量和函数都保存在这个对象中。我们编写的代码是无法访问这个对象的,但解析器在处理数据时会在后台使用它。
全局执行环境是最外围的一个执行环境,在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法来创建的。某个执行环境中的所有代码执行完毕后,该环境就会被销毁,保存在其中的所有变量和函数定义也随之销毁。
函数执行环境:每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
作用域链:它的用途是保证对执行环境有权访问的所有变量和函数的有序访问,作用域链的前端,始终都是当前执行的代码所在的环境的变量对象。当代码在一个执行环境中执行时,会创建变量对象的一个作用域链(scope chain)。
2)声明提前
【不怎么理解原例子】
3)自由变量:在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量。
var x = 10;
function fn(){
var b = 20;
console.log(x + b); // <---- x 就是一个自由变量。
}
4)词法作用域和静态作用域:词法作用域等同于静态作用域,静态作用域规则查找一个变量声明时依赖的是源程序中块之间的静态关系;【JavaScript 是使用词法作用域】
5)动态作用域规则依赖的是程序执行时的函数调用顺序。
静态作用域和动态作用域的一个重要区别在于:
* 静态作用域规则查找一个变量声明时依赖的是源程序中块之间的静态关系;
* 而动态作用域规则依赖的是程序执行时的函数调用顺序。
说的具体点,就是静态作用域查找的是距离当前作用域最近的外层作用域中同名标识符的声明,
而动态作用域则是查找最近的活动记录。
大多数现在程序设计语言都是采用静态作用域规则,
而只有为数不多的几种语言采用动态作用域规则,包括APL、Snobol和Lisp的早期方言。
而采用静态作用域的语言中,基本都是最内嵌套作用域规则:由一个声明引进的标识符在这个声明所在的作用域里可见,而且在其内部嵌套的每个作用域里也可见,除非它被嵌套于内部的对同名标识符的另一个声明所掩盖。为了找到某个给定的标识符所引用的对象,应该在当前最内层作用域里查找。如果找到了一个声明,也就可以找到该标识符所引用的对象。否则我们就到直接的外层作用域里去查找,并继续向外顺序地检查外层作用域,直到到达程序的最外嵌套层次,也就是全局对象声明所在的作用域。如果在所有层次上都没有找到有关声明,那么这个程序就有错误。
Ref: Javascript之旅——第十站:为什么都说闭包难理解呢?
例子一:
闭包变量:name
<script type="text/javascript"> //比较函数
function createComparison(propertyName) { return function ( obj1, obj2 ) {
var item1 = obj1[propertyName];
var item2 = obj2[propertyName]; if (item1 < item2)
return -1; if (item1 > item2)
return 1; if (item1 == item2)
return 0;
}
} //比较name
var compare = createComparison("name"); var result = compare( { name: "d", age: 20 }, { name: "c", age: 27 } );
</script>
注意对下面这个列表所表示的scope的检索范围优先级的理解。
例子二:
<script type="text/javascript"> var arr = new Array(); function Person() {
for (var i = 0; i < 10; i++) { //要记住,这个属性函数申明,只有立即执行才会取scope属性,但这里不会立即执行,哈哈
var item = function () {
return i;
}; arr.push(item);
}
} Person(); for (var i = 0; i < arr.length; i++) {
console.log(arr[i]());
}
</script>
给匿名函数再增加一个副本。
<script type="text/javascript"> var arr = new Array(); function Person() {
for (var i = 0; i < 10; i++) { var item = function (num) {
return function () { // 给每个匿名function一个副本就好了
return num;
}
} (i); arr.push(item);
}
} Person(); for (var i = 0; i < arr.length; i++) {
console.log(arr[i]());
}
</script>
延长作用域链:无论函数在哪里被调用或者如何被调用,它的词法作用域都只由函数被声明时所处的位置决定,所以,函数所能访问变量的"权限"只由声明位置决定,利用这个特性就可以利用闭包(将这个函数return出去,该函数声明位置不变,所以可访问变量的"权限"依然不变)使函数外部可以访问函数内部的变量。
[JS] Topic - this is ”closure“的更多相关文章
- [JS] Topic - why "strict mode" here
Ref: Javascript 严格模式详解 使得Javascript在更严格的条件下运行: - 消除Javascript语法的一些不合理.不严谨之处,减少一些怪异行为; - 消除代码运行的一些不安全 ...
- 三个JS函数闭包(closure)例子
闭包是JS较难分辨的一个概念,我只是按自己的理解写下来,如有不对还请指出. 函数闭包是指当一个函数被定义在另一个函数内部时,这个内部函数使用到的变量会被封闭起来形成一个闭包,这些变量会保持形成闭包时设 ...
- [JS] Topic - variable and function hoisting
Ref: 深入理解js的变量提升和函数提升 一.变量提升 简直就是es5的遗毒! console.log(global); // undefined 竟然能打印?因为变量提升,下一行就有定义 var ...
- [JS] Topic - Object.create vs new
故事背景 Ref: 你不知道的javascript之Object.create 和new区别 var Base = function () {} (1) var o1 = new Base(); (2 ...
- [JS] Topic - hijack this by "apply" and "call"
Ref: 详解js中的apply与call的用法 call 和 apply二者的作用完全一样,只是接受参数的方式不太一样. 参数形式: Function.apply(obj,args) call方法与 ...
- [JS] Topic - define "class" by tricky methods
Ref:Javascript定义类(class)的三种方法 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(O ...
- [Code::Blocks] Install wxWidgets & openCV
The open source, cross platform, free C++ IDE. Code::Blocks is a free C++ IDE built to meet the most ...
- 本人SW知识体系导航 - Programming menu
将感悟心得记于此,重启程序员模式. js, py, c++, java, php 融汇之全栈系列 [Full-stack] 快速上手开发 - React [Full-stack] 状态管理技巧 - R ...
- JS,html压缩及混淆工具
现在已经出现了不少有自己特色的: JSMin Javascript compressor Packer Closure Compiler YUI Compressor Pretty Diff Java ...
随机推荐
- Asp.Net Mvc项目初始化说明
文件夹说明: App_Start 项目的启动配置 Content css以及图片资源存放位置 Controllers.Models.View控制器.模型.视图存放位置 Scripts js以及js插件 ...
- IO流(1)—之序列化与反序列化
1.概念 序列化:把Java对象转换为字节序列的过程称为对象的序列化 反序列化:把字节序列恢复为Java对象的过程称为对象的反序列化 注:只有实现了Serializable和Externalizabl ...
- Math类操作数据
Math 类位于 java.lang 包中,包含用于执行基本数学运算的方法, Math 类的所有方法都是静态方法,所以使用该类中的方法时,可以直接使用类名.方法名,如: Math.round(); 常 ...
- Using a Virtex Device to Drive 5V CMOS-Level Signals
Must tri-state outputs and use an external resistor to pull up to 5V To drive 5V CMOS-level inputs, ...
- Delphi的接口委托示例
{ 说明:该事例实现的效果,在单个应用或代码量小的项目中,可以完全不用接口委托来完成. 之所以采用委托接口,主要是应用到:已经实现的接口模块中,在不改变原有代码的情况下, 需要对其进行扩展:原始 ...
- 微信小程序wx.switchTab传参问题
业务背景:从提问跳到列表需要刷新,以显示刚提交的数据. 但是官方文档 wx.switchTab 明确指明路径后是不能带参数的,怎么办? 网上有很多解决方案是:switchTab成功跳转后调用succe ...
- JavaScript比较两个对象的值是否相等
JavaScript比较两个对象的值是否相等 function isObjectValueEqual(a, b) { var aProps = Object.getOwnPropertyNames(a ...
- WebSocket——为Web应用带来桌面应用般的灵活性【转载+整理】
原文地址 本文内容 WebSocket 简介 浏览器端的 JavaScript 实现 Java 端的 WebSocket 实现 对 Web 应用的重新思考 使用WebSocket时所需注意的要点 We ...
- wifipineapple外接SD卡
通过SSH或者web访问URL, http://172.16.42.1:1471 输入帐号:root 密码:pineapplesareyummy(默认账号密码) ssh连接:ssh root@172 ...
- MDX Cookbook 12 - 计算 SMA 简单移动平均 LastPeriods() 函数的使用
先认识一下这几个名词 Moving Average (MA) 移动平均,或者叫做移动平均线,是技术分析中一种分析时间序列数据的工具.最常见的就是利用股价,回报或交易量等变数计算出移动平均.可以利用移动 ...