在我看来,这一切都是关于定义一个 Object-Literal 的,而我最近尝试定义该对象的“私有”属性时会遇到麻烦。这是正确的吗?
“私有属性”与使用对象进行命名空间无关。事实上,最初在回答这个问题时,我将其解读为“私有函数”,因为这会是相关的。
在 JavaScript 中有很多方法可以实现私有和半私有属性,但它们与您如何创建构造函数及其赋予对象的方法有关,而不是如何公开构造函数。 “命名空间”对象是关于如何公开构造函数的。
创建“私有”属性的一种常见模式是定义需要访问它们的方法在构造函数中,并在构造函数中创建“属性”局部变量(因此它们不是真正的属性),像这样:
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
无论您是在“命名空间”模式中还是单独这样做,都没有关系。
另一方面,私有函数会影响模式。我将在下面显示两者。
提供私有函数的一个相当常见的变体是使用函数来创建对象,这也让您有机会创建私有函数:
var TheNamespace = function() {
function privateFunction() {
}
function SuperObject() {
var privateInformation;
this.method = function() {
// This can access `privateInformation`, which is completely
// hidden from outside the constructor
};
}
SuperObject.prototype.otherMethod = function() {
// Can't access `privateInformation`, but has the advantage
// that the function is shared between instances
};
return {
SuperObject: SuperObject
};
}();
// usage
var s = new TheNamespace.SuperObject();
那 mySuperObjectInNS 还是构造函数吗? (对我来说,这似乎是另一回事,即使我可以从中实例化对象。
是的。构造函数是指任何希望您使用new 的函数。
命名空间是一种非常糟糕非常糟糕的方式还是可以?
使用对象作为伪命名空间是常见的做法。您还可以考虑各种 asynchronous module definition (AMD) 技术,这些技术在很大程度上使“命名空间”对象在很大程度上变得不必要。
你的评论:
你定义了一个自调用函数......它返回一个对象?
这不是一个 self 调用函数,它是一个 inline 调用函数,但是是的,它是一个返回对象的函数。
(如果是这样,我认为缺少括号)
不,我们不需要任何不存在的括号,因为您在其他地方看到的外部括号的唯一原因是告诉解析器单词function 开始一个表达式而不是声明;在上面我们不需要它,因为我们已经在赋值的右侧,所以遇到function 时不会有歧义。
由于你提出了这种方式,是不是更好的方式来定义ns?
“更好”是一个主观术语。它为您提供了一个范围,您可以在其中定义您所询问的私有函数。
而我也经常看到这个选项:var = {} | someNSName; 这是怎么回事?
如果您有多个文件可以将内容添加到“命名空间”(这很常见),那么您经常会在每个文件中看到这一点:
var TheNamespace = TheNamespace || {};
这样做是声明变量 if 它以前没有声明过,并为它分配一个空对象 if 它还没有一个。在加载的第一个文件中,会发生这种情况:
处理var 并创建一个新变量TheNamespace,其值为undefined。
处理TheNameSpace = TheNameSpace || {} 分配:由于undefined 是错误的,curiously-powerful || operator 会产生新的{},它被分配给TheNamespace.
当 next 文件加载时,会发生这种情况:
var 是空操作,因为变量已经存在。
处理TheNameSpace = TheNameSpace || {} 赋值:因为TheNamespace 有一个非null 对象引用,所以它是真实的,并且奇怪强大的|| 运算符导致对对象TheNamespace 的引用指。
也就是说,它根本没有效果。
这样您可以按任何顺序加载文件,或单独加载一个文件。
这是一个例子:
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Nifty = function() {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
return Nifty;
}();
thingy.js:
var TheNamespace = TheNamespace || {};
TheNamespace.Thingy = function() {
function privateFunction() {
}
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
return Thingy;
}();
该基本模式有很多变体,特别是如果一个文件可能会向TheNamespace 添加多个内容。这是一个相当简洁地支持这样做的方法:
var TheNamespace = function(exports) {
function privateFunction() {
}
function Nifty() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Nifty.prototype.otherMethod = function() {
// ...
};
exports.Nifty = Nifty;
function Thingy() {
var privateInformation;
this.method = function() {
// Can access `privateInformation` here
};
}
Thingy.prototype.otherMethod = function() {
// ...
};
exports.Thingy = Thingy;
}(TheNamespace || {});