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 相关文章推荐
Ucren Virtual Desktop V2.0
Nov 07 Javascript
TreeView 用法(有代码)(asp.net)
Jul 15 Javascript
jQuery删除节点的三个方法即remove()detach()和empty()
Dec 27 Javascript
详解JavaScript基于面向对象之继承
Dec 13 Javascript
JavaScript几种数组去掉重复值的方法推荐
Apr 12 Javascript
移动适配的几种方案(三种方案)
Nov 25 Javascript
AngularJs表单验证实例代码解析
Nov 29 Javascript
websocket+node.js实现实时聊天系统问题咨询
May 17 Javascript
Vue.js devtool插件安装后无法使用的解决办法
Nov 27 Javascript
使用mock.js随机数据和使用express输出json接口的实现方法
Jan 07 Javascript
Vue 中文本内容超出规定行数后展开收起的处理的实现方法
Apr 28 Javascript
微信小程序报错: thirdScriptError的错误问题
Jun 19 Javascript
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
Smarty中的注释和截断功能介绍
2015/04/09 PHP
PHP中让json_encode不自动转义斜杠“/”的方法
2017/02/28 PHP
php 替换文章中的图片路径,下载图片到本地服务器的方法
2018/02/06 PHP
javascript之ESC(第二类混淆)
2007/05/06 Javascript
jQuery对表单元素的取值和赋值操作代码
2011/05/19 Javascript
JS 去前后空格大全(IE9亲测)
2013/07/15 Javascript
Jquery chosen动态设置值实例介绍
2013/08/08 Javascript
在JS中解析HTML字符串示例代码
2014/04/16 Javascript
javascript实现html页面之间参数传递的四种方法实例分析
2015/12/15 Javascript
JavaScript小技巧整理篇(非常全)
2016/01/26 Javascript
node模块机制与异步处理详解
2016/03/13 Javascript
轻松实现js弹框显示选项
2016/09/13 Javascript
深入学习jQuery中的data()
2016/12/22 Javascript
利用node.js实现反向代理的方法详解
2017/07/24 Javascript
js实现前端图片上传即时预览功能
2017/08/02 Javascript
JS兼容所有浏览器的DOMContentLoaded事件
2018/01/12 Javascript
vue+axios 前端实现登录拦截的两种方式(路由拦截、http拦截)
2018/10/24 Javascript
详细教你微信公众号正文页SVG交互开发技巧
2019/07/25 Javascript
python实现超简单的视频对象提取功能
2018/06/04 Python
Python进阶之全面解读高级特性之切片
2019/02/19 Python
基于keras 模型、结构、权重保存的实现
2020/01/24 Python
Python实现Keras搭建神经网络训练分类模型教程
2020/06/12 Python
意大利文具和办公产品在线商店:Y-Office
2020/02/27 全球购物
小学生学习感言
2014/03/10 职场文书
班长演讲稿范文
2014/04/24 职场文书
项目建议书模板
2014/05/12 职场文书
求职信格式要求
2014/05/23 职场文书
工作批评与自我批评范文
2014/10/16 职场文书
2015年事业单位工作总结
2015/04/27 职场文书
远程教育集中轮训基层干部培训班学习心得体会
2016/01/09 职场文书
简短的人生哲理(38句)
2019/08/13 职场文书
nginx限制并发连接请求数的方法
2021/04/01 Servers
Go语言 go程释放操作(退出/销毁)
2021/04/30 Golang
如何开发一个渐进式Web应用程序PWA
2021/05/10 Javascript
JavaWeb 入门:Hello Servlet
2021/07/16 Java/Android
golang语言指针操作
2022/04/14 Golang