在JavaScript中,我可以使用这样的顶级对象开始编写“库”或功能集合:
window.Lib = (function()
{
return {
// Define Lib here.
//
};
})();
我还可以在Lib
中添加一些用于创建与之相关的对象的函数:
window.Lib = (function()
{
return {
ObjectA: function()
{
var _a = 5;
return {
getA: function(){ return _a; }
};
},
ObjectB: function()
{
var _b = 2;
var _c = 1;
return {
getB: function(){ return _b; }
};
}
};
})();
将使用如下:
var thing = Lib.ObjectA();
var thing2 = Lib.ObjectA();
var thing3 = Lib.ObjectB();
我可以使用上面创建的每个方法中的方法来获取在_a
中定义的ObjectA()
或_b
内定义的ObjectB()
的值:
alert(thing.getA()); // 5
alert(thing3.getB()); // 2
我想要实现的目标是:
我想要访问属性_c
(在ObjectB()
中定义),但仅在Lib
范围内。我怎么能这样做?我的意思是,我希望在我在Lib()
返回的对象中定义的任何函数中使属性可读,但我不想在那之外公开这些值。
代码示例:
window.Lib = (function()
{
return {
ObjectA: function(){ ... },
ObjectB: function(){ ... },
assess: function(obj)
{
// Somehow get _c here.
alert( obj.getInternalC() );
}
};
})();
哪个会这样:
var thing = Lib.ObjectB();
alert( thing.getInternalC() ) // error | null | no method named .getInternalC()
Lib.assess(thing); // 1
希望这是有道理的。
答案 0 :(得分:2)
所以你想要每个实例受保护的属性?也就是说,ObjectA
,ObjectB
等创建的实例的属性,但是 可以访问库中的代码,而不是代码外的代码?
您目前无法在JavaScript中正确执行 ,但您可以使用private name objects在下一版本中执行 。 (请参阅下面的“几乎要做”,以了解ES5中现在可以做的类似事情。)
很容易创建由Lib
中的所有代码共享的数据,而不是每个实例属性,如下所示:
window.Lib = (function()
{
var sharedData;
// ...
})();
在那里定义的所有功能(您的ObjectA
等)都可以访问那个从外部无法访问的sharedData
变量。但不是每个实例,ObjectA
,ObjectB
等创建的每个对象都没有自己的副本。
如果您的代码将在具有ES5的环境中运行(因此,任何现代浏览器,“现代”不包括IE8或更早版本),您可以隐藏但实际上不是私人财产,通过Object.defineProperty
。这类似于私有名称对象在ES.next中的工作方式,但不是真正的私有:
window.Lib = (function() {
// Get a random name for our "c" property
var c = "__c" + Math.round(Math.random() * 1000000);
// Return our library functions
return {
ObjectA: function() {
// Create an object with a couple of public proprties:
var obj = {
pub1: "I'm a public property",
pub2: "So am I"
};
// Add our obscured "c" property to it, make sure it's
// non-enumerable (doesn't show up in for-in loops)
Object.defineProperty(obj, c, {
enumerable: false, // false is actually the default value, just emphasizing
writable: true,
value: "I'm an obscured property"
});
// Return it
return obj;
},
ObjectB: function(){ /* ... */ },
assess: function(obj) {
// Here, we access the property using the `c` variable, which
// contains the property name. In JavaScript, you can access
// properties either using dotted notation and a literal
// (`foo.propName`), or using bracketed notation and a string
// (`foo["propName"]`). Here we're using bracketed notation,
// and our `c` string, which has the actual property name.
display( obj[c] );
},
alter: function(obj, value) {
// Similarly, we can change the value with code that has
// access to the `c` variable
obj[c] = value;
}
};
})();
并像这样使用它:
// Create our object
var o = Lib.ObjectA();
// Play with it
display("pub1: " + o.pub1); // displays "pub1: I'm a public property"
display("c: " + o.c); // displays "c: undefined" since `o` has no property called `c`
Lib.assess(o); // displays "I'm an obscured property"
// Note that our obscured property doesn't show up in for-in loops or Object.keys:
var propName, propNames = [];
for (propName in o) {
propNames.push(propName);
}
display("propNames: " + propNames.join(","));
display("Object.keys: " + Object.keys(o).join(","));
// Our Lib code can modify the property
Lib.alter(o, "Updated obscured property");
Lib.assess(o);
Lib.ObjectA
返回的对象有一个属性,每次加载Lib
时,其名称都会更改,而且不可枚举(不会显示在for-in
循环中)。获得它的唯一方法是知道它的名称(再次,每次创建Lib
时更改 - 例如,每个页面加载)。 Lib
中的代码知道属性名称是什么,因为它位于所有c
代码共享的Lib
变量中。由于您可以使用括号表示法和字符串访问属性,因此我们可以使用instance[c]
来访问该属性。
你看到这些是如何模糊不清的。 Lib
之外的代码在枚举对象中的属性时看不到隐藏的属性,并且它们不知道我们为其分配的半随机名称,因此找不到该属性。当然,您可以通过使用调试器进行检查来找到它,但调试器可以做很多事情。
事实上,这是私有属性在ES.next中的工作方式,除了c
不是字符串,它将是一个私有名称对象。
答案 1 :(得分:1)
好吧,你只需“声明 <{>} 中的那些变量
Lib
请注意,我删除了伪构造函数的自动调用。这意味着,您需要为多个实例创建多个window.Lib = (function()
{
var _c = 42;
return {
};
});
调用,每个实例都有自己的唯一值。
Lib()
如果您只想从所有子上下文(函数)中获得共享访问,您可以使用您已经执行的相同模式(仅移动 var 声明到父上下文,如上所示。)