当前位置: 首页 > news >正文

[原]Java程序员的JavaScript学习笔记(4——闭包/getter/setter)


计划按如下顺序完成这篇笔记:

  1. 理念。
  2. 属性复制和继承。
  3. this/call/apply。
  4. 闭包/getter/setter。
  5. prototype。
  6. 面向对象模拟。
  7. jQuery基本机制。
  8. jQuery选择器。
  9. jQuery工具方法。
  10. jQuery-在“类”层面扩展。
  11. jQuery-在“对象”层面扩展。
  12. jQuery-扩展选择器。
  13. jQuery UI。
  14. 扩展jQuery UI。

这是笔记的第4篇,聊聊闭包/getter/setter,看看JavaScript中的变量作用域和实现封装的方法。


作者博客:http://blog.csdn.net/stationxp

作者微博:http://weibo.com/liuhailong2008

转载请取得作者同意



1、闭包

闭包是JavaScript一项简单实用的语言特性。通过闭包:
弥补了函数没有public/private等访问访问权限控制符的缺陷,保护了函数内部变量的安全。
使得函数对象在作为参数传递时,不仅仅传递运算逻辑,同时也传递了相关变量。
使得函数“类”的不同实例,独享自己的属性。
下面逐个来看。

1.1、保护私有变量

1.1.1、原理

闭包最主要的特性是:当函数作为返回值时,连同函数定义时的环境(包括函数外部,函数可以访问到的变量)一起返回,确保这些变量不因其依附的对象销毁而被销毁。
有点儿绕,具体什么意思呢?看下面的代码:
// 代码段1
 function UiObject() {
     var childCount = 0; // 函数内部变量,  
     return 0;
 }
 
 var funcReturnValue = UiObject();  // 调用函数,返回0
 console.log(UiObject.childCount);   // 输出:undefined,由于函数调用完成,内部变量已经被销毁
 
 childCount随着UiObject函数的调用结束而销毁,从另一个角度看,保护了函数内部的变量。
 在这个基础上,如果我们有一种办法可以确保函数的内部变量不被销毁,而且提供方法对其访问操作,也就实现了通过public方法访问 private 变量。
 代码如下:
 // 代码段2
 function UiObject() {
     var childCount = 0; // 函数内部变量
     function getChildCount(){
         childCount = 6;
         return childCount;
     }
     return getChildCount;
 }
 var funcReturnFObject = UiObject();  // 调用函数,返回 getChildCount 函数,返回值是一个闭包
 console.log(funcReturnFObject());   // 输出:6
 下面我们就看看,如果利用闭包的这一特性实现对私有属性的保护。
 
 

 1.1.2、语法

 在代码段2的基础上改进,代码段3展示的代码,可以同时提供多个方法,对私有属性访问。
 //代码段3
 function UiObject() {
     var childCount = 0; // 函数内部变量
     
     return {
         getChildCount : function (){
             return childCount;
         },
         setChildCount : function (cnt){
             childCount = cnt;
         }
     };
 }
 
 var o = UiObject();  // 调用函数,返回 getChildCount 函数,返回值是一个闭包
 o.setChildCount(6);
 console.log(o.getChildCount());   // 输出:6
 
 思考: 如果 var childCount = 0 ; 改为 this.childCount = 0; 呢?
 我们之前研究过this,“ this.childCount = 0; ”语句是将childCount附加为调用者的属性,this.childCount的将生命周期与调用者相同。这与闭包不冲突。
 
 代码段3还可以写成代码段4的形式。
 
 // 代码段4
 function UiObject() {
     var childCount =  0; // 函数内部变量
     this.setChildCount = function(cnt){
         childCount = cnt;
     };
     this.getChildCount = function(){
         return childCount;
     };
 }
 
 var ui = new  UiObject();          // 调用函数,返回retObj
 console.log(ui.childCount);       // 输出:undefined,由于函数调用完成,局部变量已经被销毁
 ui.setChildCount(3);                  // 由于闭包的作用,ui仍然保存着变量childCount,并对其操作
 console.log(ui.getChildCount()); // 输出:3
 
 “this.setChildCount = function(cnt){       childCount = cnt;   };” 这个语句相当于在UiObject内部定义了函数并“传递”了给ui对象。同样产生了闭包。
 

1.2、传递函数时,同时传递上下文

通过上面的例子,我们已经看到了这点特性。
在具体的应用场景中可对其大加利用。

1.3、不同实例,独享自己的变量

我们已经知道了,函数在传递过程中,会产生一个闭包。对于同一方法产生的闭包,是相同的,还是为每次传递创建了不同的拷贝呢?
看下面的代码:
//代码段5
 function UiObject() {
     var childCount = 0; // 函数内部变量
     
     return {
         getChildCount : function (){
             return childCount;
         },
         setChildCount : function (cnt){
             childCount = cnt;
         }
     };
 }
 
 var ui1 = UiObject();
 var ui2 = UiObject();
 
 ui1.setChildCount(1);
 ui2.setChildCount(2);
 
 console.log(ui1.getChildCount()); // output : 1
 console.log(ui2.getChildCount()); // output : 2
 
 每次生成闭包是不同的拷贝。
 
 思考:对比Java,加深理解。
 
 

2、getter/setter


JavaScript
 //代码段6
 var uiPanel ={
     _type  : 'Panel',
     _width : -1,
     _height: -1,
     
     get type(){ return this._type;},
     
     get width(){ return this._width; },
     set width(v){this._width = v;},
     
     get height(){ return this._height; },
     set height(v){this._height = v;}
 };
 
uiPanel.type = 'TextField';          // does not work
console.log('type:'+uiPanel.type); // ouput :         type:Panel
 
 uiPanel.width = 800;                 //
 console.log('width:'+uiPanel.width); // ouput :         width:800

语法上越发有面向对象的范儿了。
除了在定义时通过set/set关键字控制属性的读写权限。还可以在运行期通过 Object.defineProperty()函数动态添加属性,并提供更精细的控制。
代码如下(以下代码均未经实验):
var o = {};
Object.defineProperty(o,'propName',{
            value:1,  //属性的值,也可以通过   get:function(){retun x;}的方法设定
            writeable:true,//是否可以通过o.propName  = newValue ; 的方法设置属性的值
            enumerable:false,//是否可以通过被枚举
            configurable:true//是否可以通过defineProperty配置
    });
另外,还有一系列API可以完成对属性的配置、检测。如下:
Object.getOwnPropertyDescriptor{{x:1},"x"}
Object.keys(obj);    // 获得对象上所有可枚举的“实例属性”
Object.getOwnPropertyNames(obj) ;//获得对象上所有的“实例属性”
obj.hasOwnProperty(‘id’); //只要该对象obj拥有属性id, 无论id是否可枚举,都返回true


3、小结

当大多数人已经习惯了面向对象的思维和方法,语言就要从特性方面予以满足,这不合理,也不美。但世界就是如此不完美。

JavsScript天生丽质,非要把她改造成机甲战士,那以后谁来负责倾国倾城呢?

ECMAScript 5不是革命性创新,也不是救命稻草这个世界本来可以更好的。




作者:stationxp 发表于2014-10-17 3:40:37 原文链接
阅读:384 评论:0 查看评论

转载于:https://www.cnblogs.com/liuhailong2008/p/4055297.html

相关文章:

  • Dijkstra算法
  • 几种不错的编程字体
  • byte[]数组的正则表达式搜索 z
  • File类基本操作之OutputStream字节输出流
  • 全限定名
  • vsftpd基于pam_mysql的认证和hash编码的方式配置虚拟用户
  • Java中char转为16进制
  • 人脸识别算法初次了解
  • Python编程笔记(第三篇)【补充】三元运算、文件处理、检测文件编码、递归、斐波那契数列、名称空间、作用域、生成器...
  • Linux Memory Hotplug
  • 25个增强iOS应用程序性能的提示和技巧
  • 20165306 课下作业(第十周)
  • tortoise svn连接问题
  • 又一款基于BCH开发出来的社交软件BlockPress
  • 企业CIO如何做好免费ERP系统的选型
  • ➹使用webpack配置多页面应用(MPA)
  • CODING 缺陷管理功能正式开始公测
  • CSS实用技巧
  • input实现文字超出省略号功能
  • Less 日常用法
  • nfs客户端进程变D,延伸linux的lock
  • Vue全家桶实现一个Web App
  • 缓存与缓冲
  • 记一次用 NodeJs 实现模拟登录的思路
  • 解决iview多表头动态更改列元素发生的错误
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 面试遇到的一些题
  • 那些年我们用过的显示性能指标
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 【干货分享】dos命令大全
  • (function(){})()的分步解析
  • (ibm)Java 语言的 XPath API
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (篇九)MySQL常用内置函数
  • (三)c52学习之旅-点亮LED灯
  • (算法二)滑动窗口
  • (转载)深入super,看Python如何解决钻石继承难题
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Core 通过 Ef Core 操作 Mysql
  • .Net 路由处理厉害了
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .Net6使用WebSocket与前端进行通信
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?
  • @JoinTable会自动删除关联表的数据
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • [ C++ ] STL---string类的使用指南
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [codeforces] 25E Test || hash
  • [ERROR] 不再支持目标选项 5。请使用 7 或更高版本