这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
本文给大家简单介绍了在一个项目中涉及到的 javascript 使用闭包模拟对象的私有属性和方法,这里记录下来,分享给大家。
最近因为做了一个项目,其中涉及到了 js 私有方法,这个概念在其语言里面是很常见的,很多语言都有 private 这个关键字,只要在一个类的前面加上 private 就表示申明了一个私有方法,但是 javascript 在面向对象的方面没有那么多的特征,他没有专门的 private 关键字,。要做到这一点就必须使用 js 自己的一些特性来变相的完成。
首先 javascript 里面有一个高级特性叫闭包,简单的说 js 的闭包可以理解成是一种现象或者特性,一般出现在两个函数嵌套的情况下,看例子:
- function a(){
- var eg = 1;
- return function(){
- alert(eg);
- }
- }
- var c = a();
a 函数里返回了一个函数,返回的函数被全局作用域下的 c 接受了,此时因为返回的函数调用了 a 函数里面的 eg 变量,并且被全局作用域下的变量 c 引用,此时下形成闭包,a 函数的内存空间不会被收回,这个闭包的理解其实和 js 的垃圾回收机制有关,js 的垃圾回收其实是靠引用来计算的,比如我们申明了一个函数,这个函数就会有一个引用指向他自己,当函数运行结束的时候销毁引用,js 如果发现没有引用的函数就会销毁这个函数的内存空间,函数也就没有了。我们上面的例子中首先 a 函数运行,给 eg 赋值 1,然后返回一个匿名函数,到此 a 函数运行完了,按照原有的理论,此时 a 函数应该被销毁,但是此时他返回了一个函数,这个函数被全局下的变量 c 引用,c 是不会被销毁的,除非我们手动销毁,而且这个返回的函数引用了 a 函数的变量 eg,js 引擎会认为 eg 依然是有用的,因为他仍然在被使用,因此包含 eg 这个局部变量的函数 a 也不会被销毁。
闭包的理解可能不是一下讲的通的,这里其实还涉及到一个作用域的问题,我记得以前有人说返回的这个函数被 c 接收了,c 是在全局作用下的,为什么调用 c 的时候会弹出 a 函数里面的 eg, 难道不应该是全局作用域下的 eg 吗?而且 js 的函数作用于是局部的,外部不能访问。其实这里有一个理论,记住就可以,js 里的函数作用域取决于函数定义的位置,而不是函数调用的位置,也就是说,函数在什么地方定义的,他的作用域就决定了,不管他在什么地方调用,作用域都不会改变,返回的这个匿名函数是在 a 函数里面定义的,所以他的上级作用域就是这个 a 函数,而不是全局作用域。
这里要说的私有方法其实和闭包是有关系的,私有方法在其他语言里面是不被访问到的,除非有专门的接口,js 的局部作用域里面的东西在正常情况下也是不能被外部访问到,但是上面例子显示了,通过闭包的方式可以访问到,这样我们就可以利用这个特性,看例子:
- var book = (function(){
- var page = 100;
- return function(){
- this.auther = 'dava';
- this.price = 200;
- this._page = function(){
- alert(page);
- }
- }
- })();
- var a = new book();
- a.auther//"dava"
- a.price// 200
- a.page//"wrong"
- a._page()// 100
这里例子用了一个函数自动执行,一上来就执行了一个匿名函数,并且在匿名函数里面定义了一个局部变量 page, 然后又返回了一个匿名函数,并且被全局作用域下的 book 变量接收,此时使用 new 调用 book 就会生成一个新对象 a。其中 auther 属性和 price 属性可以直接通过对象访问,因为这些属性都是 new 的时候直接定义在返回的对象身上的, 而 page 属性则没有,因此不能反回,但此时如果我想访问 page 属性,那就得依靠闭包了,返回的函数在外层的匿名函数里面,因此在返回的函数身上定义了一个方法叫_page,这个方法弹出了 page 属性,按照 js 作用域的关系,当前作用域找不到 page,就会到上层作用域去寻找,这样就找到了。通过这种方式我们就把私有方法和公有方法区分开了。
来源: http://www.phperz.com/article/17/0513/331431.html