前言:html
昨天写了一个关于Java内部的博客,在内部类的最后一点中谈到了Java闭包的概念,他是这样定义闭包的:闭包是一个可调用的对象,它记录了一些信息,这些信息来自建立它的做用域。结合Java的内部类能够很好的理解这一点(若有须要可参考ThinkInJava以内部类)。忽然之间想到js中的闭包,一直都没法很好的理解,故借此又看了一下js中的闭包,对我我的而言,感悟良多,借此也与你们分享一下,但愿能够帮助你们,并一块儿快乐的学习成长,每天向上。java
js:闭包是一个返回给调用者的对象,而这个返回对象携带了一些调用者没法获取的信息安全
<script> function Car() { //定义class var color = "blue"; //定义属性 } Car.prototype.getColor = function() { //经过原型定义方法 console.info(this.color) return this.color; } var oCar1 = new Car();//建立对象实例 oCar1.getColor(); //调用方法 </script>
var a = "我是全局变量"; function myFunction() { var b = "我是局部变量" return a ; }
function my2(){
consoke.info(b) #报错
}
2.1 全局变量a:即属性window的属性,在同一页面内全部的js脚本,都共享同一个window对象,故共享全局变量a.闭包
2.2 局部变量b :局部变量只能用于定义它函数内部。对于其余的函数或脚本代码是不可用的。函数
备注:变量声明时若是不使用 var 关键字,那么它就是一个全局变量,即使它在函数内定义。学习
解题思路:须要一个变量,这个变量须要在方法内访问并加一,屡次调用该变量就是屡次加一的和,故不能把该变量定义在方法的内部,若是把该变量定义在方法的内部就不能实现屡次调用返回屡次调用的和,故把该方法定义为全局变量以下,但这样定义该变量即不安全如调用方法2 this
var counter = 0; function add() { return counter += 1; } function myFunction(){ document.getElementById("demo").innerHTML = add(); } function myFunction2(){ counter = 100; document.getElementById("demo").innerHTML = add(); } myFunction(); myFunction();//实现屡次调用返回,屡次调用的和 ##counter =2 myFunction2();//但若是调用该方法,就不返回屡次调用的和 #由于是全局变量,任何脚本均可更改该变量的值,这样及其不不安全。 ##counter =101
解题思路2:若是能把count变量隐藏起来不让其它js方法修改它不就好了吗?若是咱们熟悉Java语言,用Java就很容易解决该问题。由于Java提供的修饰符private能够控制属性的访问限制。并定义一个惟一public方法设置该属性(就是把属性定义为私有的,并提供惟一的get和set方法,就这么简单)。然而若是把问题抛给js就很难解决这个问题了,觉得js没有提供这样的修饰符,来控制访问属性。如何解决相似Java private成员的问题请看下面spa
JavaScript 支持嵌套函数。嵌套函数能够访问上一层的函数变量(咱们能够这样理解:内部的变量能够访问其外面的变量,而外面的不能访问内部的。prototype
//一个简单的js嵌套函数 function add() { //外部类 var counter = 0; function plus() { //嵌套函数 内部类 counter += 1; //嵌套函数能够访问其外部的变量 } plus(); return counter; }
类比Java :Java内部类能够访问外围对象的全部属性包括私有属性,js的嵌套函数好行也有这个属性😄。设计
var aa = ( function(){ alert("sssss"); return {}; } )() //备注:当咱们刷新当前页面时就会执行function方法并返回{}对象 //不须要手动调用该方法
当即执行函数的写法有不少中以上是最经常使用的方式()(),下面也是当即函数的写法
1 !function foo(){...}();
2 +function foo(){...}();
经过马上执行函数,而且返回一个空的对象,结合内嵌函数的特性,咱们可知这个对象是能够访问外围的属性和方法的。
而后咱们分析:利用嵌套函数和闭包的特性来分析下图
{//区域A(window) {//区域B return {//区域C 区域C返回到了区域A } } }
图一
结论以下
1. 区域A不能访问区域B定义的数据,故B就对A隐藏了。然而区域C能够访问区域B定义的数据,
2.区域C同过return返回给了区别A,若是区域C是一个方法,则A就能够调用这个方法,而这个方法是惟一能访问到B区域的(B提供了一个public方法共全局访问)。故B又提供了对A访问的方法。
这样就造成了一个js的闭包:(即闭包是一个返回给调用者的对象,而这个返回对象携带了一些调用者没法获取的信息)
备注:js方法也是对象
代码以下
var add = (function () { var counter = 0; return function () {return counter += 1;} })(); add(); add(); add(); // 计数器为 3
备注1:js函数分类
函数声明:function fname(){...}; 使用function关键字声明一个函数,再指定一个函数名。
函数表达式:var fname=function(){...}; 使用function关键字声明一个函数,但未给函数命名,最后将匿名函数赋予给一个变量。
匿名函数:function(){}; 使用function关键字声明一个函数,但未给函数命名。(匿名函数也属于函数表达式。)
备注2:js解析机制
js:解析机制:分为编译和执行两个阶段。
先编译:有人也称预编译,js解析器会扫描整个js文件,把以var (定义变量)和function(定义方法)开头语句作变量提高。
执行 :给定义的变量赋值,或执行相关方法(以括号‘()’结尾的语句,会看成方法来执行)
利用js解析机制来来回答为何函数会自我调用
在执行阶段,js解析器发现该函数 1 : 没有以var或function开头。
2 : 而且以'()'括号结尾
若是知足以上两个条件,没有特殊缘由都会称为马上执行函数。
备注3: js当即执行函数 vs Java单例模式
若是属性java的读者必定接触过单例模式:即一个应用系统中只容许拥有一个惟一的某个类型的实例对象,具体写法再次就很少介绍了。经过分析和观察当即执行函数,由于该函数的执行是在js解析器加载的时候执行的(能够类比为Java应用程序启动时加载单例),而且很难手动再次加载它(我是没有发现方法😄),故咱们能够理解当即函数就是单例设计模型(没有研究过js的设计模型,也不知道有没有😄)。
***************************************欢迎读者给出建议***********************************