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 相关文章推荐
event.srcElement 用法笔记e.target
Dec 18 Javascript
Wordpress ThickBox 点击图片显示下一张图的修改方法
Dec 11 Javascript
js 优化次数过多的循环 考虑到性能问题
Mar 05 Javascript
JavaScript中链式调用之研习
Apr 07 Javascript
getJSON调用后台json数据时函数被调用两次的原因猜想
Sep 29 Javascript
js实现点击后将文字或图片复制到剪贴板的方法
Aug 04 Javascript
bootstrap警告框使用方法解析
Jan 13 Javascript
vue-cli webpack 引入swiper的操作方法
Sep 15 Javascript
vue-cli3+typescript初体验小结
Feb 28 Javascript
ES6数组与对象的解构赋值详解
Jun 14 Javascript
layui关闭层级、简单监听的实例
Sep 06 Javascript
Vue自定义铃声提示音组件的实现
Jan 22 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
Laravel如何使用数据库事务及捕获事务失败后的异常详解
2017/10/23 PHP
javascript与CSS复习(《精通javascript》)
2010/06/29 Javascript
SeaJS入门教程系列之完整示例(三)
2014/03/03 Javascript
JS模拟按钮点击功能的方法
2015/12/22 Javascript
AngularJS数据源的多种获取方式汇总
2016/02/02 Javascript
Javascript实现的SHA-256加密算法完整实例
2016/02/02 Javascript
JavaScipt选取文档元素的方法(推荐)
2016/08/05 Javascript
jquery——九宫格大转盘抽奖实例
2017/01/16 Javascript
bootstrap datepicker插件默认英文修改为中文
2017/07/28 Javascript
js函数柯里化的方法和作用实例分析
2020/04/11 Javascript
JS猜数字游戏实例讲解
2020/06/30 Javascript
vue实现移动端拖动排序
2020/08/21 Javascript
Vue-cli打包后如何本地查看的操作
2020/09/02 Javascript
解决Antd 里面的select 选择框联动触发的问题
2020/10/24 Javascript
python实现根据用户输入从电影网站获取影片信息的方法
2015/04/07 Python
Python 内置函数complex详解
2016/10/23 Python
ansible作为python模块库使用的方法实例
2017/01/17 Python
python安装cx_Oracle模块常见问题与解决方法
2017/02/21 Python
OpenCV实现人脸识别
2017/04/07 Python
Android分包MultiDex策略详解
2017/10/30 Python
Python语言的变量认识及操作方法
2018/02/11 Python
BP神经网络原理及Python实现代码
2018/12/18 Python
利用python Selenium实现自动登陆京东签到领金币功能
2019/10/31 Python
详解Python中的format格式化函数的使用方法
2019/11/20 Python
PyQt5 closeEvent关闭事件退出提示框原理解析
2020/01/08 Python
HTML5手指下滑弹出负一屏阻止移动端浏览器内置下拉刷新功能的实现代码
2020/04/10 HTML / CSS
英国领先的亚洲旅游专家:Wendy Wu Tours
2018/01/21 全球购物
快时尚眼镜品牌,全国连锁眼镜店:LOHO眼镜生活
2018/10/08 全球购物
捷克玩具商店:Bambule
2019/02/23 全球购物
捷克母婴用品购物网站:Feedo.cz
2020/12/28 全球购物
消防战士优秀事迹材料
2014/02/13 职场文书
学习普通话的体会
2014/11/07 职场文书
工作汇报开头与结尾怎么写
2014/11/08 职场文书
保送生自荐信范文
2015/03/26 职场文书
周末问候语大全
2015/11/10 职场文书
苹果可能正在打击不进行更新的 App
2022/04/24 数码科技