JavaScript中的私有成员


Posted in Javascript onSeptember 18, 2006

JavaScript是世界上是被误解得最厉害的编程语言。有些人认为它不具备“信息隐藏”的能力,因为JavaScript的对象没有私有变量和方法。这是误解。JavaScript对象可以拥有私有成员,下面我们来看看怎么做。(SharkUI.com注:JavaScript并不是真正拥有私有、公有等等OOP的特性,这篇译文中提到的这些私有、公有、特权等特性,是利用JavaScript的其他特性(参看本文的“闭包”一节)“模拟”出来的。感兴趣的话可以搜索相关的文章来看,当然也可以不管这些,就当它是真正的OOP来用。Have fun!)

对象

JavaScript是建立在对象之上的。数组(Array)是对象,函数(Function)是对象,对象(Objects)当然也是对象。那什么是对象呢?对象是一组“名称:值”对(name-value pair)的集合。名称是字符串,值却可以是字符串、数值、布尔或对象(包括数组和函数)。对象通常是用哈希表来实现的,以便可以快速地取值。

如果值是一个函数,我们就可以把它当作一个“方法”。当对象的一个方法被执行,变量this就被设为对象本身。如此,方法就可以通过this变量来访问对象的实例。

对象可以通过“构造器(constructor)”来创建。构造器是一个拥有初始化对象的函数。构造器提供了类似其他语言中的“类(class)”所提供的特性和功能,包括静态变量和方法。

公有

对象的所有成员都是公有成员。任何函数都可以访问、修改或者删除这些成员,当然也可以添加新的成员。给对象添加成员的两种主要方法:

通过构造器

这种方法一般用来初始化对象实例的公有变量。构造器的this变量被用来给对象添加成员:

function Container(param) {
  this.member = param;
}

构造一个新的对象:

var myContainer = new Container('abc');

然后,公有变量 myContainer.member 就拥有了值 'abc'。

通过原型(prototype)

这种方法通常用来添加公有方法。在对象本身搜寻一个成员但没有找到时,就使用构造器的原型(prototype)成员。这种原型机制实现了面向对象所谓的 “继承(inheritance)”,同时也节省了内存。给创建自同一个构造器的所有的对象加上一个方法,只需要给构造器的prototype增加一个函数:

Container.prototype.stamp = function (string) {
  return this.member + string;
}

然后我们就可以调用这个方法:

myContainer.stamp('def')

返回'abcdef'。

私有

私有(Private)成员是由构造器创建的。通常构造器中用var声明的变量和函数参数成为私有成员。

function Container(param) {
  this.member = param;
  var secret = 3;
  var self = this;
}

这个构造器创建了三个私有的实例变量:param,secret和self。

function Container(param) {
  function dec() {
   if (secret > 0) {
     secret -= 1;
     return true;
   } else {
     return false;
   }
  }

  this.member = param;
  var secret = 3;
  var self = this;
}

私有方法dec会检查实例变量secret,如果它大于0,自减1并返回true;如果它小于0,返回false。这样就实现了由这个架造器所创建对象的dec函数只能用三次的功能。

按惯例,我们创建了一个私有变量self。私有方法可以通过它来访问到对象本身。但这只是一种权宜之计,因为《ECMAScript Language Specification》中有一个错误,使得内部函数的this变量被设置成一个错误值。

公有方法(SharkUI.com注:即上文说的通过prototype创建的方法)是无法调用私有方法的,所以为了能使用私有方法,我们需要引入特权方法(privileged method)。

特权

一个特权方法可以访问私有变量和方法,而它本身可以被公有方法和外界访问。你可以删除或替换一个特权方法,但不能修改它,也不能强制它放弃自己的密秘(SharkUI.com注:原文如此,可能是指它的特权,关于这点请高手指教)。

特权方法是在构造器内部通过this来创建的。

function Container(param) {
  function dec() {
   if (secret > 0) {
     secret -= 1;
     return true;
   } else {
     return false;
   }
  }

  this.member = param;
  var secret = 3;
  var self = this;

  this.service = function () {
   if (dec()) {
     return self.member;
   } else {
     return null;
   }
  };
}

service是一个特权方法。前三次调用myContainer.service()将返回'abc',之后将返回null。service通过调用私有方法dec来访问私有变量secret。对于其他对象和方法来说,可以访问到service,但不能直接访问到私有的成员。

闭包

这种公有、私有和特权成员模式的存在是由于JavaScript的内在机制:闭包。这意味着一个内部函数永远可以访问它外部函数的变量和参数,即使外部函数已经返回。这是JavaScript语言非常强大的一个特性。目前还没有关于JavaScript编程的书籍展示了如何来利用它,它们甚至都没有提到这一点。

私有和特权成员只能在对象初始化的时候创建,而公有成员可以被随时添加进来。

模式

公有
function Constructor(...) {
  this.membername = value;
}
Constructor.prototype.membername = value;
私有
function Constructor(...) {
  var self = this;
  var membername = value;
  function membername(...) {...}
}

注:这句代码:

function membername(...) {...}

事实上是以下代码的简略写法

var membername = function membername(...) {...};
特权
function Constructor(...) {
  this.membername = function (...) {...};
}

后记

Douglas Crockford的这篇文章为我们写出更优美的JavaSciprt程序奠定了基础,为我们创建出更合理的面向对象应用和框架带来了可能。在这篇译文快要完成的时候,惊诧的发现作者网站上出现了一个本文中文版的链接。好事!有越来越多的中国人开始关注这些“边边角角”的技术。虽然做了重复工作,但一样希望各位能从这篇文章中有所收益。也希望有更多的人能投入到原创和翻译前端技术文章中来,在多数人浮躁的时候,我们需要更多基础性的工作。一周一篇不多,一年一篇不少,只要开始了就行!

Javascript 相关文章推荐
Javascript实现仿WebQQ界面的“浮云”兼容 IE7以上版本及FF
Apr 27 Javascript
jQuery瀑布流插件Wookmark使用实例
Apr 02 Javascript
javascript中in运算符用法分析
Apr 28 Javascript
jQuery UI设置固定日期选择特效代码分享
Aug 27 Javascript
基于javascript实现文字无缝滚动效果
Mar 22 Javascript
浅析在javascript中创建对象的各种模式
May 06 Javascript
浅谈Vue.js 1.x 和 2.x 实例的生命周期
Jul 25 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
Apr 18 Javascript
vue-cli中安装方法(图文详细步骤)
Dec 12 Javascript
解析原来浏览器原生支持JS Base64编码解码
Aug 12 Javascript
微信小程序移动拖拽视图-movable-view实例详解
Aug 17 Javascript
JavaScript DOM常用操作代码汇总
Jul 03 Javascript
javascript的事件描述
Sep 08 #Javascript
由浅到深了解JavaScript类
Sep 08 #Javascript
js常用函数 不错
Sep 08 #Javascript
Javascript 不能释放内存.
Sep 07 #Javascript
一些有关检查数据的JS代码
Sep 07 #Javascript
Mozilla中显示textarea中选择的文字
Sep 07 #Javascript
showModelessDialog()使用详解
Sep 07 #Javascript
You might like
PHP5.0对象模型探索之抽象方法和抽象类
2006/09/05 PHP
WIN98下Apache1.3.14+PHP4.0.4的安装
2006/10/09 PHP
php Http_Template_IT类库进行模板替换
2009/03/19 PHP
ThinkPHP模板引擎之导入资源文件方法详解
2014/06/18 PHP
PHP面向对象精要总结
2014/11/07 PHP
php实现的美国50个州选择列表实例
2015/04/20 PHP
浅谈php中urlencode与rawurlencode的区别
2016/09/05 PHP
jquery控制listbox中项的移动并排序
2009/11/12 Javascript
jQuery 打造动态渐变按钮 详细图文教程
2010/04/25 Javascript
Javascript拓展String方法小结
2013/07/08 Javascript
toggle一个div显示或隐藏且可扩展成自定义下拉框
2013/09/12 Javascript
javascript的日期对象、数组对象、二维数组使用说明
2014/12/22 Javascript
微信小程序 开发经验整理
2017/02/15 Javascript
Angular指令之restict匹配模式的详解
2017/07/27 Javascript
mui 打开新窗口的方式总结及注意事项
2017/08/20 Javascript
Vue渲染函数详解
2017/09/15 Javascript
vue.js项目打包上线的图文教程
2017/11/16 Javascript
AngularJS对动态增加的DOM实现ng-keyup事件示例
2018/03/12 Javascript
微信小程序实现简单跑马灯效果
2020/05/26 Javascript
微信小程序实现搜索指定景点周边美食、酒店
2019/05/18 Javascript
[02:43]2014DOTA2国际邀请赛 官方Alliance战队纪录片
2014/07/14 DOTA
Python版的文曲星猜数字游戏代码
2013/09/02 Python
Python实现比较两个文件夹中代码变化的方法
2015/07/10 Python
Linux下将Python的Django项目部署到Apache服务器
2015/12/24 Python
python的多重继承的理解
2017/08/06 Python
浅谈Scrapy框架普通反爬虫机制的应对策略
2017/12/28 Python
python flask实现分页的示例代码
2018/08/02 Python
Python unittest 简单实现参数化的方法
2018/11/30 Python
Python selenium根据class定位页面元素的方法
2019/02/26 Python
Pycharm创建文件时自动生成文件头注释(自定义设置作者日期)
2020/11/24 Python
Tostadora意大利:定制T恤
2019/04/08 全球购物
网络安全方面的面试题
2015/11/04 面试题
文明班集体申报材料
2014/05/23 职场文书
员工生日活动方案
2014/08/24 职场文书
Apache Pulsar结合Hudi构建Lakehouse方案分析
2022/03/31 Servers
element tree树形组件回显数据问题解决
2022/08/14 Javascript