JavaScript模块模式保护成员?
喂!这是我的第一个问题 我正在试验Doug Crockford和其他人提出的模块模式。到目前为止,我对它非常满意,但我有点不确定处理某种继承模式的最佳方式 我把它归结为一个使用猫和哺乳动物的裸体游戏,尽管我的实际意图是在画布上为基于瓷砖的游戏制作对象 但以下是我使用浏览器警报的裸体“动物”案例:JavaScript模块模式保护成员?,javascript,inheritance,Javascript,Inheritance,喂!这是我的第一个问题 我正在试验Doug Crockford和其他人提出的模块模式。到目前为止,我对它非常满意,但我有点不确定处理某种继承模式的最佳方式 我把它归结为一个使用猫和哺乳动物的裸体游戏,尽管我的实际意图是在画布上为基于瓷砖的游戏制作对象 但以下是我使用浏览器警报的裸体“动物”案例: var ZOO = ZOO || {}; // ZOO.mammal = function () { "use strict"; var voice = "squeak.mp3", // d
var ZOO = ZOO || {};
//
ZOO.mammal = function () {
"use strict";
var voice = "squeak.mp3", // default mammal sound
utter = function () {
window.alert(this.voice);
};
//
// public interface
return {
utter: utter,
voice: voice
};
};
//
ZOO.cat = function () {
"use strict";
// hook up ancestor
var thisCat = ZOO.mammal();
thisCat.voice = "miaw.mp3";
return thisCat;
};
//
var felix = ZOO.cat();
felix.utter();
这种方法让我烦恼的是,我不得不将语音
作为公共属性,以便cat可以修改它
我真正想要的是“受保护的”可见性(来自Java、ActionScript等),这样cat
就可以修改voice
,而没有任何人可以访问felix
来修改它
有解决方案吗?您可以通过将空白对象传递给基础“类”作为受保护属性的存储库来模拟受保护的可见性(对您自己和子对象可见)。这将允许您通过继承链共享属性,而无需将其公开
var ZOO = ZOO || {};
ZOO.mammal = function (protectedInfo) {
"use strict";
protectedInfo = protectedInfo || {};
protectedInfo.voice = "squeak.mp3";
// public interface
return {
utter: function () {
alert(protectedInfo.voice);
}
};
};
ZOO.cat = function () {
"use strict";
var protectedInfo = {};
// hook up ancestor
var thisCat = ZOO.mammal(protectedInfo);
protectedInfo.voice = "miaw.mp3";
return thisCat;
};
这里有一个回避不回答的问题: 有一些方法可以在Javascript中获得受保护的属性,但它们不一定非常惯用。如果我是你,我会首先强烈地考虑
\u voice
)的公共财产惯例表示隐私。它非常简单,是动态语言中的一个标准有一种变通方法可以模拟受保护的成员,将这些成员公开一段时间,然后再将其私有化。我不太喜欢这个,但这是一个“解决方案” 我只是引用这句话: 添加受保护的成员 将脚本拆分为多个模块是一种常见且方便的方法 练习。它使大型代码库更易于管理,并允许 在不总是需要模块的情况下节省带宽 但是如果我们想在不同的模块之间共享数据呢?如果我们 公开这些数据,我们将失去隐私的好处,但如果 我们将其设置为私有,它将仅对一个模块可用。我们 真正需要的是共享的私有成员,这些成员被称为 受保护 JavaScript本身没有受保护的成员,但我们可以 通过临时公开数据有效地创建它们。达到 首先,让我向您介绍两个关键函数-扩展和 私有化-我们将其定义为效用函数对象的一部分:
var utils = {
extend : function(root, props) {
for(var key in props) {
if(props.hasOwnProperty(key)) {
root[key] = props[key];
}
} return root;
},
privatise : function(root, prop) {
var data = root[prop];
try { delete root[prop]; } catch(ex) { root[prop] = null; }
return data;
}
};
extend函数只是向对象添加新属性,而
私有化功能复制属性,然后删除原始属性。我们
可以在一个模块中使用extend来创建对私有对象的公共引用
变量,然后在另一个模块中使用privatise将其复制回
一个私有变量并删除公共引用
这是第一个模块的示例,它有两个受保护的
成员(包括utils对象本身)和一个公共成员。到
保持代码示例简短,实用程序函数只是空的
shell,但它们与我在
刚才:
var MyModule = (function() {
var myProtectedData = 909;
var utils = {
extend : function(root, props) { },
privatise : function(root, prop) { }
};
this.myPublicData = 42;
return utils.extend(this, { myProtectedData : myProtectedData, utils : utils });
})();
你可以看到我们是如何使用显示模块模式的变体的,
不仅返回公共成员,还返回受保护的成员作为
好。现在我们有三位公众成员:
MyModule.myProtectedData、MyModule.utils和MyModule.myPublicData
下面是最后一个模块的示例,它使用私有化
函数将指定的公共成员复制回私有成员
变量,然后删除它们的公共引用:
var MyModule = (function() {
var myProtectedData = this.utils.privatise(this, 'myProtectedData');
var utils = this.utils.privatise(this, 'utils');
return this;
}).apply(MyModule);
完成后,受保护的成员将被锁定在其内部
对象,这两个模块都可以私下使用,但不再使用
可从外部获取
请注意,私有化函数依赖于具有单独的参数
对于对象和属性键,因为JavaScript中的对象是
通过引用传递。所以root是对MyModule的引用,当我们
从中删除由键指定的属性,我们将删除该属性
属性从引用的对象中删除
但如果是这样的话:
privatise : function(root) {
var data = root;
try { delete root; } catch(ex) { root = null; } return data;
}
var myProtectedData = this.utils.privatise(this.myProtectedData);
并这样称呼:
privatise : function(root) {
var data = root;
try { delete root; } catch(ex) { root = null; } return data;
}
var myProtectedData = this.utils.privatise(this.myProtectedData);
然后公众成员将不会被删除-功能将被删除
只需删除引用,而不是它引用的属性
试一试。。。catch构造对于较旧的IE版本也是必要的,
其中不支持删除。在这种情况下,我们取消了公众的权利
属性而不是删除它,这显然是不一样的,但是
其最终结果是否定该成员的公开声明
参考资料
我认为Douglas Crockford不同意你的观点:
到目前为止,我们看到的继承模式的一个弱点是我们没有隐私。对象的所有属性都是可见的。我们没有私有变量,也没有私有方法。有时这并不重要,但有时这很重要。令人沮丧的是,一些不知情的程序员采用了假装隐私的模式。如果他们有一处想要私有化的房产,他们会给它起一个奇怪的名字。。。。幸运的是,在模块模式的应用程序中,我们有一个更好的选择。
[Crockford 52]假装隐私不仅仅是“出于挫折而生”——它非常简单和严格,并且与原型继承JS native配合得很好