JavaScript 函数闭包的应用
闭包的应用: 定义JS模块
具有特定功能的js文件,将所有的数据和功能都封装在一个函数内部(私有的)
只向外暴露一个包信n个方法的对象或函数,模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
// 自定义模块
function coolModule() {
// 私有的数据
var msg = 'atguigu'
var names = ['I', 'Love', 'you']
//私有的操作数据的函数
function doSomething() {
console.log(msg.toUpperCase())
}
function doOtherthing() {
console.log(names.join(' '))
}
//向外暴露包含多个方法的对象,如果一个方法就直接将这个方法return即可
return {
doSomething: doSomething,
doOtherthing: doOtherthing
}
}
<body>
<script type="text/javascript" src="05_coolModule.js"></script>
<script type="text/javascript">
var module = coolModule()
module.doSomething()
module.doOtherthing()
</script>
</body>
// 自定义模块2
(function (window) {
//私有的数据
var msg = 'atguigu'
var names = ['I', 'Love', 'you']
//操作数据的函数
function a() {
console.log(msg.toUpperCase())
}
function b() {
console.log(names.join(' '))
}
window.coolModule2 = {
doSomething: a,
doOtherthing: b
}
})(window)
<body>
<script type="text/javascript" src="05_coolModule2.js"></script>
<script type="text/javascript">
coolModule2.doSomething()
coolModule2.doOtherthing()
</script>
</body>
模仿块级作用域
JavaScript 没有块级作用域的概念,那么可以模拟像java中将很多变量私有化封装起来,保护数据,防止数据泄漏,封装细节,这样安全性和可控性更高
function box(count) {
for (var i=0; i<count; i++) { //块级作用域(JS中没有这个东西)
}
alert(i); //i 不会因为离开了 for 块就失效
}
box(2); //结果是2,还是可以访问的
function box(count) {
for (var i=0; i<count; i++) { //块级作用域(JS中没有这个东西)
}
var i; //就算重新声明,也不会前面的值
alert(i); //i 不会因为离开了 for 块就失效
}
box(2); //结果是2,还是可以访问的
以上两个例子,说明 JavaScript 没有块级语句的作用域,if () {} for () {}等没有作用域,如果有,出了这个范围 i 就应该被销毁了。就算重新声明同一个变量也不会改变它的值。
JavaScript 不会提醒你是否多次声明了同一个变量;遇到这种情况,它只会对后续的声明视而不见(如果初始化了,当然还会执行的)。使用模仿块级作用域可避免这个问题。
模仿块级作用域(私有作用域)
/*
(function () {
//这里是块级作用域
})();
*/
function box(count) {
(function () {
for (var i = 0; i<count; i++) {
alert(i);//只能在这里i才是有效的才是能访问的
}
})();
alert(i); //这里i已经出了作用域 报错,无法访问
}
box(2);
使用了块级作用域(私有作用域)后,匿名函数中定义的任何变量,都会在执行结束时被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。
一般来说,我们都应该尽可能少向全局作用域中添加变量和函数。在大型项目中,多人开发的时候,过多的全局变量和函数很容易导致命名冲突,引起灾难性的后果。
如果采用块级作用域(私有作用域),每个开发者既可以使用自己的变量,又不必担心搞乱全局作用域。
(function () {
var box = [1,2,3,4];
alert(box);
})();
alert(box);//box 出来就不认识了
在全局作用域中使用块级作用域可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链了。
私有变量
JavaScript 没有私有属性的概念;所有的对象属性都是公有的。不过,却有一个私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。
function box() {
var age = 100; //私有变量,外部无法访问,只能返回
}
而通过函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量。而利用这一点,可以创建用于访问私有变量的公有方法。
function Box(){
this.age = 100; //可以访问,公有的
this.run = function(){ //可以访问,公有的
return "运行中....";
}
}
var box = new Box();
alert(box.age);
alert(box.run());
function Box() {
var age = 100; //私有变量
function run() { //私有函数
return '运行中...';
}
this.get = function () { //对外公共的特权方法
return age + run();
};
}
var box = new Box();
alert(box.get());
可以通过构造方法传参来访问私有变量。
function Person(value) {
var user = value; //这句其实可以省略
this.getUser = function () {
return user;
};
this.setUser = function (value) {
user = value;
};
}
var box = new Person("hua");
alert(box.getUser());
box.setUser(4);
alert(box.getUser());
但是对象的方法,在多次调用的时候,会多次创建。
function Person(value) {
var user = value; //这句其实可以省略
this.getUser = function () {
return user;
};
this.setUser = function (value) {
user = value;
};
}
var box = new Person("hua");
alert(box.getUser());
var box2 = new Person("kkk");
alert(box.getUser());//结果还是hua,说明setUser方法没有共享
可以使用静态私有变量来避免这个问题。
静态私有变量
通过块级作用域(私有作用域)中定义私有变量或函数,同样可以创建对外公共的特权方法。
(function () {
var age = 100; //私有变量
function run() {
return '运行中...';
}
//function Box(){} //构造方法,在函数里写构造函数不支持,因为私有作用域里的函数,外部无法访问,所以要做成全局的,如下
Box = function (value){ //全局构造方法
age = value;
};
Box.prototype.getAge = function () { //原型方法,只生成一个地址
return age + run();
};
Box.prototype.setAge = function(value){
age = value;
}
})();
var box1 = new Box(23);
alert(box1.getAge());
var box2 = new Box(43);
alert(box2.getAge());
box2.setAge(76);
alert(box1.getAge());//使用box2设置了age的值,再使用box1获取age的时候变成了box2设置的值,说明共享了
使用了 prototype 导致方法共享了,而 age也就变成静态属性了。(所谓静态属性,即共享于不同对象中的属性)。
模块模式
之前采用的都是构造函数的方式来创建私有变量和特权方法。那么对象字面量方式就采用模块模式来创建。
var box = function () {
var age = 100;
function run() {
return '运行中...';
}
return { //直接返回对象
go : function () {
return age + run();
}
};
}();
//上面的直接返回对象的例子,也可以这么写:
var box = function () {
var age = 100;
function run() {
return '运行中...';
}
var obj = { //创建字面量对象
go : function () {
return age + run();
}
};
return obj; //返回这个对象
}();
字面量的对象声明,其实在设计模式中可以看作是一种单例模式,所谓单例模式,就是永远保持对象的一个实例。
function Desk() {};
var box = function () {
var age = 100;
function run() {
return '运行中...';
}
var desk = new Desk(); //可以实例化特定的对象
desk.go = function () {
return age + run();
};
return desk;
}();
alert(box.go());
增强的模块模式,这种模式适合返回自定义对象,也就是构造函数。
JavaScript 函数闭包的应用的更多相关文章
- javascript函数闭包(closure)
一,首先感受下javascript函数的闭包 二,闭包 1,定义:闭包就是能够读取其他函数内部变量的函数,由于在javascript语言中,只有在函数内部的子函数才能够读取局部变量,因此可以把闭包简单 ...
- Javascript函数闭包详解(通俗易懂
许多书上闭包过于复杂讲解难懂,自己理解了一下并总结啦~ 讲闭包之前,需要先明白以下几个概念. 总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域. 1.执行上下文(executi ...
- JavaScript 函数闭包
在函数中定义函数,这些定义的内部函数可以访问它们所在的外部函数中所有局部变量.参数以及声明的其它内部函数.当这样的内部函数在包含它们的外部函数之外被调用时就会形成闭包. 在没有class机制只有函数的 ...
- JavaScript函数——闭包
闭包 概念 只有函数内部的子函数才能读取局部变量,所以闭包可以理解成"定义在一个函数内部的函数".在本质上,闭包是将函数内部和函数外部连接起来的桥梁 例子 function out ...
- Javascript函数闭包及案例详解
什么情况下会形成闭包,什么是闭包 闭包(Closure):函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包 可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员 下面来看一个 ...
- JavaScript碎片—函数闭包(模拟面向对象)
经过这几天的博客浏览,让我见识大涨,其中有一篇让我感触犹深,JavaScript语言本身是没有面向对象的,但是那些大神们却深深的模拟出来了面向对象,让我震撼不已.本篇博客就是在此基础上加上自己的认知, ...
- JavaScript碎片———函数闭包(模拟面向对象)
经过这几天的博客浏览,让我见识大涨,其中有一篇让我感触犹深,JavaScript语言本身是没有面向对象的,但是那些大神们却深深的模拟出来了面向对象,让我震撼不已.本篇博客就是在此基础上加上自己的认知, ...
- javaScript函数与闭包
js中函数也是对象,具有一切对象的特征,可以作为表达式给变量赋值,可以作为函数的形参,或者函数的返回值,函数内可以嵌套函数等等,函数内以声明方式定义的函数是局部函数,用表达式声明的函数则由赋值变量的性 ...
- JavaScript 函数作用域和闭包
函数作用域和闭包 词法作用域 它们在定义它们的作用域里运行,而不是在执行的作用域运行,但是只有在运行时,作用域链中的属性才被 定义(调用对象),此时,可访问任何当前的绑定. 调用对象 ...
随机推荐
- Python爬虫入门教程 3-100 美空网数据爬取
美空网数据----简介 从今天开始,我们尝试用2篇博客的内容量,搞定一个网站叫做"美空网"网址为:http://www.moko.cc/, 这个网站我分析了一下,我们要爬取的图片在 ...
- List-ArrayList集合基础增强底层源码分析
List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...
- C语言实现二叉树的创建&遍历
算法思想(重点是递归的使用) 利用扩展先序遍历序列创建二叉链表 采用类似先序遍历的递归算法,首先读入当前根结点的数据,如果是'.'则将当前 树根置为空,否则申请一个新结点,存入当前根结点的数据,分别 ...
- 【API知识】一种你可能没见过的Controller形式
前言 这里分享一下我遇到的一个挺有意思的Controller形式,内容涉及@RequestMapping注解的原理. 实际案例 一.基本描述 项目甲中有多个模块,其中就有模块A和B.(这里的模块指的是 ...
- 深入浅出解读 Java 虚拟机的差别测试技术
本文分享基于字节码种子生成有效.可执行的字节码文件变种,并用于 JVM 实现的差别测试.本文特别提出用于修改字节码语法的classfuzz技术和修改字节码语义的classming技术.上述变种技术系统 ...
- python常用脚本以及问题跟踪
1.时间操作//获取当前时间 格式是%Y-%m-%d %H:%M:%ScurrTime = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time. ...
- 微服务实战(二):使用API Gateway
微服务实战(一):微服务架构的优势与不足 微服务实战(二):使用API Gateway 微服务实战(三):深入微服务架构的进程间通信 微服务实战(四):服务发现的可行方案以及实践案例 微服务实践(五) ...
- [零] JavaIO入门简介 程序设计语言 为什么需要IO库
本文旨在引申出来Java IO的概念含义,作为学习JavaIO一个起步的了解知识点 部分内容引自<计算机操作系统第三版> 操作系统的文件管理 "在现代计算机系统中,要用到 ...
- 痞子衡嵌入式:一表全搜罗常见移动通信标准(1-5G, GSM/GPRS/CDMA/LTE/NR...)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是移动通信标准. 移动无线网络已经成为我们生活.学习.娱乐不可缺少的必备品,而移动无线通信技术本身也在不断地更新换代.从1986年诞生第一 ...
- 大数据利器Hive
序言:在大数据领域存在一个现象,那就是组件繁多,粗略估计一下轻松超过20种.如果你是初学者,瞬间就会蒙圈,不知道力往哪里使.那么,为什么会出现这种现象呢?在本文的开头笔者就简单的阐述一下这种现象出现的 ...