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 相关文章推荐
Apply an AutoFormat to an Excel Spreadsheet
Jun 12 Javascript
强大的jquery插件jqeuryUI做网页对话框效果!简单
Apr 14 Javascript
firefox下jQuery UI Autocomplete 1.8.*中文输入修正方法
Sep 19 Javascript
ajax跨域调用webservice的实现代码
May 09 Javascript
基于Bootstrap3表格插件和分页插件实例详解
May 17 Javascript
JS图片定时翻滚效果实现方法
Jun 21 Javascript
BootStrap中关于Select下拉框选择触发事件及扩展
Nov 22 Javascript
js控制文本框禁止输入特殊字符详解
Apr 07 Javascript
vue实现裁切图片同时实现放大、缩小、旋转功能
Mar 02 Javascript
vue+elementUI实现简单日历功能
Sep 24 Javascript
Openlayers实现地图全屏显示
Sep 28 Javascript
Vue-router编程式导航的两种实现代码
Mar 04 Vue.js
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
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
一个简单的PHP入门源程序
2006/10/09 PHP
php写的简易聊天室代码
2011/06/04 PHP
PHP面向对象详解(三)
2015/12/07 PHP
PHP redis实现超迷你全文检索
2017/03/04 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
javascript 文档的编码问题解决
2009/03/01 Javascript
js控制CSS样式属性语法对照表
2012/12/11 Javascript
javascript 函数声明与函数表达式的区别介绍
2013/10/05 Javascript
如何将网页表格内容导入excel
2014/02/18 Javascript
jquery获得同源iframe内body下标签的值的方法
2014/09/25 Javascript
node.js中的Socket.IO使用实例
2014/11/04 Javascript
jQuery插件EnPlaceholder实现输入框提示文字
2015/06/05 Javascript
基于JavaScript实现移动端TAB触屏切换效果
2015/10/20 Javascript
学习JavaScript设计模式(策略模式)
2015/11/26 Javascript
React.js入门实例教程之创建hello world 的5种方式
2016/05/11 Javascript
js字符串截取函数slice、substring和substr的比较
2016/05/17 Javascript
Bootstrap Img 图片样式(推荐)
2016/12/13 Javascript
nodejs 图片预览和上传的示例代码
2017/09/30 NodeJs
JS 中document.write()的用法和清空的原因浅析
2017/12/04 Javascript
JavaScript代码实现txt文件的上传预览功能
2018/03/27 Javascript
封装一下vue中的axios示例代码详解
2020/02/16 Javascript
Laravel 如何在blade文件中使用Vue组件的示例代码
2020/06/28 Javascript
[01:30]DOTA2上海特锦赛现场采访 Loda倾情献唱
2016/03/25 DOTA
Python使用QQ邮箱发送Email的方法实例
2017/02/09 Python
小白如何入门Python? 制作一个网站为例
2018/03/06 Python
python实现一个简单的并查集的示例代码
2018/03/19 Python
基于YUV 数据格式详解及python实现方式
2019/12/09 Python
python报错: 'list' object has no attribute 'shape'的解决
2020/07/15 Python
基督教婚礼主持词
2014/03/14 职场文书
公司合作协议书范本
2014/04/18 职场文书
大学生村官演讲稿
2014/04/25 职场文书
小学生十佳少年事迹材料
2014/08/20 职场文书
个人先进事迹总结
2015/02/26 职场文书
祝福语集锦:给妹妹结婚的祝福语
2019/12/18 职场文书
第四次工业革命,打工人与机器人的竞争
2022/04/21 数码科技