javascript闭包浅析

news/2024/5/20 4:07:40

    //闭包
	var myObjectNew = (function () {
		var value = 0;
		return {
			increment: function (inc) {
				value += typeof inc === 'number' ? inc : 1;
            },
			getValue: function () {
				return value;
            }
		}
    }());

	var quo = function (status) {
		return {
			get_status: function () {
				return status;
            }
		}
    };

	var myQuoNew = quo('amazed');
	console.log('status=' + myQuoNew.get_status());



当我们调用quo时,它返回包含get_status方法的一个新对象。该对象的一个引用保存在myQuo中。即使quo已经返回了,但get_status方法仍然享有访问quo对象的status属性的特权。get_status方法并不是访问该参数的一个副本,它访问的就是该参数本身。这是可能的,因为该函数可以访问它被创建时所处的上下文环境。这被称为闭包。

理解内部函数能访问外部函数的实际变量而无须复制是很重要的


    //糟糕的例子
	//构造一个函数,用错误的方式给一个数组中的节点设置事件处理程序。
	//当点击一个节点时,按照预期,应该弹出一个对话框显示节点的序号。
	//但它总是会显示节点的数目
	var add_the_handlers = function (nodes) {
		var i;
		for (i = 0; i < nodes.length; i++) {
			nodes[i].onclick = function (e) {
				alert(i);
            }
		}
    };


add_the_handlers函数的本意是想传递给每个处理器一个唯一值(i)。但它未能达到目的,因为事件处理器函数绑定了变量i本身,而不是函数在构造时的变量i的值。


    //改良后的例子
    var add_the_handlers_new = function (nodes) {
		var helper = function (i) {
			return function (e) {
				alert(i);
            }
        }
        var i;
        for (i = 0; i < nodes.length; i++) {
            nodes[i].onclick = helper(i + 1);
        }
    };


避免在循环体中创建函数,它可能只会带来无谓的计算,还会引起混淆,正如上面那个糟糕的例子。我们可以先在循环之外创建一个辅助函数,让这个辅助函数再返回一个绑定了当前i值的函数,这样就不会导致混淆了。



复制下面的文件到html文件里即可运行查看效果!


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        .button{
            font-family:"Arial";border:0;
            vertical-align:middle;margin:8px;line-height:18px;font-size:18px;
            width:140px;height:36px;line-height:18px;font-size:18px;
        }
    </style>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
</head>
<body>
    <div style="margin-top: 20px">
        <input type="button" class="button" value="按钮1">
        <input type="button" class="button" value="按钮2">
        <input type="button" class="button" value="按钮3">
        <input type="button" class="button" value="按钮4">
        <input type="button" class="button" value="按钮5">
    </div>

    <script type="text/javascript">
        var add_the_handlers_new = function (nodes) {
            var helper = function (i) {
                return function (e) {
                    alert(i);
                }
            }
            var i;
            for (i = 0; i < nodes.length; i++) {
                nodes[i].onclick = helper(i + 1);
            }
        };

        add_the_handlers_new($('.button'));
    </script>
</body>
</html>

闭包的好处有:
1.缓存
2.面向对象中的对象
3.实现封装,防止变量跑到外层作用域中,发生命名冲突
4.匿名自执行函数,匿名自执行函数可以减小内存消耗

闭包的坏处:
1.内存消耗
通常来说,函数的活动对象会随着执行期上下文一起销毁,但是,由于闭包引用另外一个函数的活动对象,因此这个活动对象无法
被销毁,这意味着,闭包比一般的函数需要更多的内存消耗。尤其在IE浏览器中需要关注。由于IE使用非原生javascript对象实现
DOM对象,因此闭包会导致内存泄露问题。
2.性能问题
使用闭包时,会涉及到跨作用域访问,每次访问都会导致性能损失。
因此在脚本中,最好小心使用闭包,它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中,然后直
接访问局部变量,来减轻对执行速度的影响。

内存泄露
1.定义:一块被分配的内存既不能使用,也不能回收。从而影响性能,甚至导致程序崩溃。
2.起因:JavaScript的垃圾自动回收机制会按一定的策略找出那些不再继续使用的变量,释放其占有的内存。然而由于一些原因
导致在这种机制下内存管理器不能正确解读javascript变量的生命周期,从而没有释放其内存,而也没有再被使用。循环引用是
导致以上情况的主要原因之一。

解决方法:常用的解决方法就是在JavaScript代码段运行完之时将形成循环引用的JavaScript对象手动设置为空,切断引用。



附加:一个朋友给了实现这个功能又不用闭包的方法

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <style>  
        .button{  
            font-family:"Arial";border:0;  
            vertical-align:middle;margin:8px;line-height:18px;font-size:18px;  
            width:140px;height:36px;line-height:18px;font-size:18px;  
        }  
    </style>  
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>  
</head>  
<body>  
    <div style="margin-top: 20px">  
        <input type="button" class="button" value="按钮1">  
        <input type="button" class="button" value="按钮2">  
        <input type="button" class="button" value="按钮3">  
        <input type="button" class="button" value="按钮4">  
        <input type="button" class="button" value="按钮5">  
    </div>  
  
    <script type="text/javascript">  
        var add_the_handlers_new = function (nodes) {   
            for (var i = 0; i < nodes.length; i++) {  
                nodes[i].onclick = function() {
                    var index = $(this).index();
                    alert(index + 1);
                };  
            }  
        };  
  
        add_the_handlers_new($('.button'));  
    </script>  
</body>  
</html>

附加二:如果用ES6也可以

    <!DOCTYPE html>    
    <html lang="en">    
    <head>    
        <meta charset="UTF-8">    
        <style>    
            .button{    
                font-family:"Arial";border:0;    
                vertical-align:middle;margin:8px;line-height:18px;font-size:18px;    
                width:140px;height:36px;line-height:18px;font-size:18px;    
            }    
        </style>    
        <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>    
    </head>    
    <body>    
        <div style="margin-top: 20px">    
            <input type="button" class="button" value="按钮1">    
            <input type="button" class="button" value="按钮2">    
            <input type="button" class="button" value="按钮3">    
            <input type="button" class="button" value="按钮4">    
            <input type="button" class="button" value="按钮5">    
        </div>    
        
        <script type="text/javascript">    
            var add_the_handlers_new = function (nodes) {     
                for (let i = 0; i < nodes.length; i++) {    
                    nodes[i].onclick = function() {  
                        alert(i + 1);  
                    };    
                }    
            };    
        
            add_the_handlers_new($('.button'));    
        </script>    
    </body>    
    </html>  





备注:欢迎加入web前端求职招聘qq群:668352707


转载于:https://www.cnblogs.com/xutongbao/p/9924991.html


http://www.niftyadmin.cn/n/4487354.html

相关文章

Python之爬虫-- XML与XPath

XML XML(EXtensibleMarkupLanguage) 学习文档&#xff1a; http://www.w3school.com.cn/xml/index.asp案例1概念&#xff1a;父节点&#xff0c;子节点&#xff0c;先辈节点&#xff0c;兄弟节点&#xff0c;后代节点 案例1&#xff1a; <?xml version"1.0"…

浅析手机消息推送设计

摘要: 消息是提醒用户有更新的内容&#xff0c;可能短信、邮件、好友申请和日程安排。消息的作用在于主动提醒用户&#xff0c;不需要主动刷新程序或者网页去检查更新&#xff0c;比如Android的sina微博&#xff0c;必须手动刷新程序才能更新微博或者查看好友申请。这种做法可以…

Python之爬虫-- etree和XPath实战

下面代码是在网站上找到的一个例子&#xff0c;空闲的时候可以自己调试。 # -*- coding:utf-8 -*- """ 爬虫 创业邦 创业公司信息爬取 网页url http://www.cyzone.cn/vcompany/list-0-0-1-0-0/0 爬取页面中的创业公司&#xff0c;融资阶段&#xff0c;创业领…

Brackets Sequence POJ - 1141 (区间dp)

Brackets Sequence POJ - 1141 题意&#xff1a;给一个括号序列&#xff0c;问最少添加多少个括号似的原序列匹配&#xff0c;并输出新序列。 用dp[i][j]表示i到j最少添加几个括号&#xff0c;flag[i][j]表示i和j之间需要添加括号的位置。 1 #include<cstdio>2 #include…

Wincc flexable的数据记录的组态

Wincc flexable的数据记录的组态 1.数据记录就是将PLC采集的数据记录下来如下&#xff0c;注意只有TP270和OP270以上的HMI设备才有数据记录 2.练习展示 3.开始创建数据记录 4.组态数据记录 5.组态变量的记录属性。将数据记录和变量绑定起来 1&#xff09;新建连接和变量 2)组态…

Android getWidth和getMeasuredWidth的正解

http://hi.baidu.com/ljlkings/blog/item/fa2a59803f839a82f603a6b2.html?timeStamp1305190390481 一。也許很多童鞋對getWidth()和getMeasuredWidth()的用法有很多的不解&#xff0c;這兩者之間有什麼樣的不同呢&#xff0c;網上也有各種不同的版本&#xff0c;但大多數都大同…

基础备忘:多态的实现(重载、虚函数、抽象类)

1.函数重载 由静态联编支持的多态性称为编译时的多态性或静态多态性&#xff0c;也就是说&#xff0c;确定同名操作的具体操作对象的过程是在编译过程中完成的。在C中&#xff0c;可以用函数重载和运算符重载来实现编译时的多态性。 2.虚函数 由动态联编支持的多态性称为运行…

一些不错的Android专栏地址

几个不错的Android专栏地址: 第三极: http://disanji.net/category/android-doc/ moandroid: http://www.moandroid.com/?page_id1176 maxlen的专栏: http://mobile.csdn.net/a/20110209/291511.html 魏祝林的专栏: http://blog.csdn.net/Android_Tutor/ duguguiyu的深入A…