javascript 闭包的理解
1,什么是闭包
“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
官方的解释实在是太高大上了,反正我是没有理解。闭包简单理解就是函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。说的在直白一点就是当function嵌套function的时候,内部函数可以访问外部函数里面的变量。
可以把闭包和面向对象结合起来,把闭包的外部函数想象成一个class,外部函数里面的变量想象成私有变量,闭包函数想象成一个普通方法,如果想实现某种逻辑的话,可以在普通方法里面实现,去实例化外部函数并调用普通方法即可, 我觉得这样更容易理解闭包。
闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。
接下来让我们先来看个例子
function fun(){ var n=0; this.plus = function(){ return n+=1; } } var _fun = new fun(); console.log(_fun.plus()) console.log(_fun.plus()) console.log(_fun.plus())
上面的demo就是个闭包,有权限访问另一个函数作用域内变量的函数都是闭包,因为变量n一直被plus引用,因此会一直在内存中存在不会被回收。(由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。)
2,闭包的几种方式
// 第一种 function add1(){ this.counter = 0; } // 在Javascript中每个函数都有一个Portotype属性,而对象没有,这个我们后面用面向对象再来解释 add1.prototype.plus=function(){ return this.counter+=1; } var _add1 = new add1(); console.log(_add1.plus()) console.log(_add1.plus())
// 第二种 var add2 = function(){ var obj = {}; obj.counter = 10; obj.plus = function(){ return this.counter+=1; } return obj; } var _add2 = new add2(); console.log(_add2.plus()) console.log(_add2.plus())
// 第三种 var add3 = new Function("this.counter = 20;this.plus = function(){return this.counter+=1;}"); var _add3 = new add3(); console.log(_add3.plus()) console.log(_add3.plus())
// 第四种 var add4={ "counter":30, "plus":function(){ return this.counter +=1; } } console.log(add4.plus()) console.log(add4.plus())
// 第五种 自调用函数 var add5 = (function(){ var counter = 40; return function(){ return counter += 1; } })() console.log(add5()) console.log(add5())
3,prototype 让我们用面向对象的方式来解释
上面第一种方法中使用到了prototype,这里我们来说下如何理解它。
var obj = function(){ }; obj .show = function(){ alert("我是静态方法"); }; obj .prototype.display = function(){ alert("我是实例方法"); };
obj.display(); // obj.Display is not a function
obj.show(); //正确
var _obj = new obj();
_obj.display(); //正确
_obj.show(); //_obj.Show is not a function
1、不使用prototype属性定义的对象方法,是静态方法,只能直接用类名进行调用!另外,此静态方法中无法使用this变量来调用对象其他的属性!
2、使用prototype属性定义的对象方法,是非静态方法,只有在实例化后才能使用!其方法内部可以this来引用对象自身中的其他属性!
4,作用域
var dom = function(){ var Name = "Default"; this.Sex = "Boy"; this.success = function(){ alert("Success"); }; }; alert(dom.Name); // Undefined
alert(dom.Sex); //Undefined
在Javascript中每个function都会形成一个作用域,而这些变量声明在函数中,所以就处于这个函数的作用域中,外部是无法访问的。要想访问变量,就必须new一个实例出来。
最后再来让我们看一个闭包的例子
// 闭包 var person = (function(){ var name="default"; //变量作用域为函数内部,外部无法访问 return { getName:function(){ return name; }, setName:function(_name){ name=_name; } } })() console.log(person.name) console.log(person.getName()) person.setName("jhone") console.log(person.getName())
// 顺便写个继承吧 var boy = function(){} boy.prototype = person; boy.prototype.say = function(){ console.log("my name is " + this.getName()); } var _boy = new boy(); _boy.setName("jack") _boy.say();
5, js 中的只读属性
// 只读属性 set get 是es5的中对象的特性 obj = { get x() {return 6}, get y() {return 7} }; console.log(obj.x) console.log(obj.y)
obj = {}; Object.defineProperty(obj, "x", {value:4, writable:false}); //只读属性 console.log(obj.x)
// 使用闭包实现 var fun = (function(){ var age = 27; return function(){ return age; } })(); console.log(fun())
开开心心编码,快快乐乐生活。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
教程:用强化学习玩转恐龙跳跳
DeepMind在2013年发表了一篇题为《用深度强化学习玩Atari》的文章,介绍了一种新的用于强化学习的深度学习模型,并展示了它仅使用原始像素作为输入来掌握Atari 2600计算机游戏难度控制策略的能力。在本教程中,我将使用Keras实现本文。我们将从增强学习的基础开始,然后深入代码中进行实践性的理解。 AI玩游戏 我在2018年3月初开始了这个项目,并取得了一些不错的成果。但是,只有CPU的系统是学习更多功能的瓶颈。强大的GPU极大地提升了性能。 在我们运行模型之前,我们需要了解许多步骤和概念。 步骤: 在浏览器(JavaScript)和模型(Python)之间构建双向接口 捕获和预处理图像 训练模型 评估 源代码:https://github.com/Paperspace/DinoRunTutorial.git 入门 要按照原样训练和玩游戏,
- 下一篇
SpringFramework核心技术一(IOC:基于Java的容器配置)
@Bean和@Configuration Spring新的Java配置支持中的中心构件是 - @Configuration注释类和@Bean注释方法。 一、基本概念:@Bean和@Configuration Spring新的Java配置支持中的中心构件是 - @Configuration注释类和@Bean注释方法。 该@Bean注释被用于指示一个方法实例,配置和初始化为通过Spring IoC容器进行管理的新对象。对于那些熟悉Spring的<beans/>XML配置的人来说,@Bean注释和<bean/>元素具有相同的作用。您可以在任何Spring中带@Component方法中使用@Bean,但是,它们通常与@Configurationbean一起使用。 使用注释类@Configuration表示它的主要目的是作为bean定义的来源。此外,@Configuration类允许通过简单地调用@Bean同一类中的其他方法来定义bean间依赖关系。最简单的@Configuration类可以读作如下: @Configuration public class AppConf...
相关文章
文章评论
共有0条评论来说两句吧...