JavaScript中的私有/静态属性介绍


Posted in Javascript onJuly 26, 2012

•模拟块级作用域
大家都知道在JavaScript中没有块级作用域的概念,我们可以通过使用闭包来模拟实现块级作用域,看下面的示例:

(function () { 
for (var i = 0; i < 10; i++) { 
//Do Nothing 
} 
alert(i); //输出10 
})();

第6行可以访问到for循环块中的变量i,如果我们稍微修改以上代码,把for循环块放置在闭包中,情况就不一样了:
(function () { 
(function () { 
for (var i = 0; i < 10; i++) { 
//Do Nothing 
} 
})(); 
alert(i); //Error: 'i' is undefined 
})();

在第8行访问变了i时,出现错误,实现了我们想要的块级作用域。
•私有属性
在JavaScript中没有块级作用域的概念,同样也没有私有属性的概念,但是存在私有变量。如果我们想把一些数据封装隐藏起来要怎么做呢?想必大家可能已经想到了,可以通过使用闭包+私有变量的方式来实现对象的私有属性。
<1>.实例私有属性
实例私有属性的特点就是每个对象都会包含独立的属性,对象和对象之间没有共享。为了实现这个目标,可以在构造函数中增加一个私有变量,然后定义公共方法来访问这个私有变量,就如同其他OO语言的setter和getter一样,下列示例就实现了实例的私有属性:
//实例私有变量 
function MyObject(name) { 
//定义私有变量 
//注意:此处没有用this.name,如果使用this.name变成公共属性了 
var privateName = name; 
//定义私有熟悉 
var privateFunction = function () { 
return "Private Function"; 
} 
//公共方法访问私有熟悉 
MyObject.prototype.getName = function () { 
return privateName; 
} 
MyObject.prototype.getFunction = function () { 
return privateFunction(); 
} 
} 
var moGyy = new MyObject("gyy"); 
alert(moGyy.getName()); //输出gyy 
alert(moGyy.getFunction()); //输出Private Function 
var moCyy = new MyObject("cyy"); 
alert(moCyy.getName()); //输出cyy 
alert(moCyy.getFunction()); //输出Private Function

在上面的示例中创建的两个对象moGyy和moCyy的getName返回不同的值,同时如果想调用私有方法同样也需要公共接口。上面的示例中两个公共函数之所以能访问私有变量,是因为两个公共函数都是闭包,而闭包的作用域链中包含了包含函数的变量对象,因此在进行变量查找时,顺着作用域链可以访问包含函数中的私有变量。在上面的示例中把公共方法添加到MyObject的原型中,目的是防止每次创建对象都创建功能一样的两个函数实例。
<2>.静态私有属性
在有些情况下我们可能希望数据全局共享,那么可能就会用到静态属性,我们还是希望这个属性为私有的,那么怎样实现静态私有属性呢?首先这个私有应该在构造函数的外部,为了把构造函数外部的变量和构造函数结合为一体,可以使用闭包把私有变量和构造函数都包含在其作用域中,为了在闭包外面访问内部的构造函数,可以使用一个全局的变量来引用构造函数,如下代码示例:
//静态私有变量和实例私有变量 
(function () { 
//定义私有变量 
var staticPrivateValue = ""; 
//构造函数,把构织函数赋值给一个全局的变量 
MyObject = function (name) { 
//定义实例变量 
this.name = name; 
}; 
//定义两个公共方法用于访问私有变量,再一次把公共方法添加到原型中 
MyObject.prototype.getPrivateValue = function () { 
return staticPrivateValue; 
} 
MyObject.prototype.setPrivateValue = function (value) { 
staticPrivateValue = value; 
} 
})(); 
var mo = new MyObject("jeff-gyy"); 
mo.setPrivateValue("gyycyy"); //设置私有属性的值 
alert(mo.getPrivateValue()); //输出gyycyy 
alert(mo.name); //输出jeff-gyy 
var mo1 = new MyObject("jeff-cyy"); 
alert(mo1.getPrivateValue()); //输出gyycyy 
alert(mo1.name); //输出jeff-cyy

从上面的代码来看mo1调用getPrivateValue函数返回的值就是mo设置的值"gyycyy",为什么会这样呢?首先我们定义了一个匿名函数并立即调用函数,函数包含了私有变量staticPrivateValue,那么为MyObject定义的两个原型方法其实通过闭包的作用域链可以访问在包含函数的私有变量,也就是getPrivateValue和setPrivateValue两个函数的作用域链中都包含了匿名函数的变量对象,我们知道作用域链中包含的变量对象其实就是一个指针,所以创建的两个对象通过公共方法房屋私有变量时,其实访问的都是匿名函数的变量对象中的staticPrivateValue,因此实现变量实例间共享的目的。从传统OO语言的角度来看我们实现的静态属性其实并不是真正意义上的静态,只是实现了静态属性实例共享的特点。
<3>.模块模式和增强模块模式
还有一种全局共享数据的方式就是singleton, 可以使用模块模式来实现Object类型的单例模式,也可以使用增强模块模式实现自定义类型的单例模式,如下示例:
//自定义构造函数 
var mo = new function () { 
//私有变量 
var privateValue = ""; 
//普通模块模式 
return { 
publicValue: "public", 
//访问私有变量 
getPrivateValue: function () { 
return privateValue; 
}, 
setPrivateValue: function (value) { 
privateValue = value; 
} 
} 
}(); 
mo.setPrivateValue("private value"); 
alert(mo.getPrivateValue()); 
alert(mo.publicFunction());

模块模式使用匿名函数来封装内部实现,就上面的示例匿名函数中包含了私有变量privateValue,返回的对象中的公共函数通过闭包的作用域链访问包含函数中的私有变量,由于定义的匿名函数被立即调用,因此变量mo引用的是返回的对象。上面的单例模式返回的是一个Object对象,可以使用增强模块模式实现自定义类型的单例模式:
//增强模块模式 
//自定义构造函数 
function MyObject(name) { 
this.name = name; 
}; 
//自定义构造函数 
var mo = new function () { 
//私有变量 
var privateValue = ""; 
//增强模块模式 
var o = new MyObject("gyycyy"); 
o.publicValue = "public"; 
//访问私有变量 
o.getPrivateValue = function () { 
return privateValue; 
} 
o.setPrivateValue = function (value) { 
privateValue = value; 
} 
return o; 
}(); 
mo.setPrivateValue("private value"); 
alert(mo.getPrivateValue()); 
alert(mo.publicFunction());

以上代码示例实现了MyObject的单例模式。
最后需要提一点的是使用闭包有利也有弊,由于闭包作用域链引用包含函数的变量对象,因此会占用额外的内存,而且进行变量查找是也需要通过作用域链,因此会消耗查找时间,闭包越深情况更严重。另外在IE(早些版本)中由于垃圾回收机制使用引用计数,因此可能会出现循环引用的情况,导致内存泄露,如下示例:
function assignHandler(){ 
var element = document.getElementById("someElement"); 
element.onclick = function(){ 
alert(element.id); 
}; 
}

在上面的代码中创建了一个闭包作为element的事件,该闭包引用了包含函数assingHandler的变量对象,而恰恰是对变量对象的引用使得element引用计数至少为1,因此element不会被回收,导致内存泄露。修改的方法大家可以想想。
Javascript 相关文章推荐
论坛特效代码收集(落伍转发-不错)
Dec 02 Javascript
javascript 设置文本框中焦点的位置
Nov 20 Javascript
使用jquery hover事件实现表格的隔行换色功能示例
Sep 03 Javascript
解析Javascript小括号“()”的多义性
Dec 03 Javascript
Js与下拉列表处理问题解决
Feb 13 Javascript
jQuery 写的简单打字游戏可以提示正确和错误的次数
Jul 01 Javascript
JavaScript制作淘宝星级评分效果的思路
Jun 23 Javascript
HTML5 实现的一个俄罗斯方块实例代码
Sep 19 Javascript
详解如何构建一个Angular6的第三方npm包
Sep 07 Javascript
JS实现的Object数组去重功能示例【数组成员为Object对象】
Feb 01 Javascript
微信小程序上传多图到服务器并获取返回的路径
May 05 Javascript
jQuery开发仿QQ版音乐播放器
Jul 10 jQuery
13 个JavaScript 性能提升技巧分享
Jul 26 #Javascript
了解一点js的Eval函数
Jul 26 #Javascript
基于jquery实现的一个选择中国大学的弹框 (数据、步骤、代码)
Jul 26 #Javascript
javascript小组件 原生table排序表格脚本(兼容ie firefox opera chrome)
Jul 25 #Javascript
浅谈javascript的原型继承
Jul 25 #Javascript
基于jquery的多功能软键盘插件
Jul 25 #Javascript
基于jQuery判断两个元素是否有重叠部分的代码
Jul 25 #Javascript
You might like
法兰绒滤网冲泡
2021/03/03 冲泡冲煮
9个PHP开发常用功能函数小结
2011/07/15 PHP
深入PHP nl2br()格式化输出的详解
2013/06/05 PHP
关于PHP自动判断字符集并转码的详解
2013/06/26 PHP
分享常见的几种页面静态化的方法
2015/01/08 PHP
php如何把表单内容提交到数据库
2019/07/08 PHP
javascript Demo模态窗口
2009/12/06 Javascript
谷歌浏览器调试JavaScript小技巧
2014/12/29 Javascript
js实现ifram取父窗口URL地址的方法
2015/02/09 Javascript
JS+CSS实现模仿浏览器网页字符查找功能的方法
2015/02/26 Javascript
jQuery使用slideUp方法实现控制元素缓慢收起
2015/03/27 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
JS实现黑客帝国文字下落效果
2015/09/01 Javascript
JQUERY的AJAX请求缓存里的数据问题处理
2016/02/23 Javascript
jQuery 选择同时包含两个class的元素的实现方法
2016/06/01 Javascript
JavaScript函数中关于valueOf和toString的理解
2016/06/14 Javascript
基于js对象,操作属性、方法详解
2016/08/11 Javascript
关于微信jssdk实现多图片上传的一点心得分享
2016/12/13 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
vue之组件内监控$store中定义变量的变化详解
2019/11/08 Javascript
微信小程序自定义yPicker组件实现省市区三级联动功能
2020/10/29 Javascript
利用Python循环(包括while&amp;for)各种打印九九乘法表的实例
2017/11/06 Python
python3 发送任意文件邮件的实例
2018/01/23 Python
对python模块中多个类的用法详解
2019/01/10 Python
python 使用pandas计算累积求和的方法
2019/02/08 Python
python中通过selenium简单操作及元素定位知识点总结
2019/09/10 Python
python3实现在二叉树中找出和为某一值的所有路径(推荐)
2019/12/26 Python
pytorch 求网络模型参数实例
2019/12/30 Python
浅谈keras中的keras.utils.to_categorical用法
2020/07/02 Python
css3实现平移效果(transfrom:translate)的示例
2020/11/13 HTML / CSS
html特殊符号示例 html特殊字符编码对照表
2014/01/14 HTML / CSS
管理站站长岗位职责
2013/11/27 职场文书
骨干教师考核方案
2014/05/09 职场文书
励志演讲稿500字
2014/08/21 职场文书
党员民主生活会材料
2014/12/15 职场文书
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
2022/04/19 Java/Android