我在这里问的问题不是关于如何在js对象上实现私有成员。 它可以如下完成
function MyClass(member){
var privateMember = member;
this.getPrivateMember = function(){
return privateMember;
};
}
my = new MyClass("newbie");
console.log(my.getPrivateMember());
但问题不是所有的库都将它们的对象实现为闭包,而且它有性能问题,因为函数成员将在每个实例中,而不是只有一个副本的原型。
请参阅http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
上的示例代码var util = require("util");
var events = require("events");
function MyStream() {
events.EventEmitter.call(this);
}
util.inherits(MyStream, events.EventEmitter);
MyStream.prototype.write = function(data) {
this.emit("data", data);
}
var stream = new MyStream();
console.log(stream instanceof events.EventEmitter); // true
console.log(MyStream.super_ === events.EventEmitter); // true
stream.on("data", function(data) {
console.log('Received data: "' + data + '"');
})
stream.write("It works!"); // Received data: "It works!"
node.js正式实现了inherit作为util.inherits 我阅读了util和events的源代码。 util.inherits的代码是
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
你知道它只是把超级构造函数的原型作为subconstrutor的原型,当然不会隐藏超级构造函数的私有成员。 当我们将子构造函数构造为示例代码
时function MyStream() {
events.EventEmitter.call(this);
}
所有events.EventEmitter的成员都将被放入MyStream的实例中。 除非你阅读了events.EventEmitter的源代码,否则你不知道会得到什么。 为了简洁起见,我将其阅读并复制到此处
function EventEmitter() {
this.domain = null;
if (exports.usingDomains) {
// if there is an active domain, then attach to it.
domain = domain || require('domain');
if (domain.active && !(this instanceof domain.Domain)) {
this.domain = domain.active;
}
}
this._events = this._events || {};
this._maxListeners = this._maxListeners || defaultMaxListeners;
}
exports.EventEmitter = EventEmitter;
你知道很多js编码器使用下划线前缀命名成员,因为它应该是私有的,最好不要被其他人修改。但它不是解决方案,因为你不会知道下划线前缀成员是什么。如果使用下划线定义自己的伪私有成员,则超伪私有成员可能与您的名称相同。你可能会破坏上级的包装。 我模仿以下情况
var util = require("util");
var events = require("events");
var _ = require("underscore");
function MyStream() {
events.EventEmitter.call(this);
this._events = "";
}
util.inherits(MyStream, events.EventEmitter);
_.extend(MyStream.prototype, {
write: function(data){
this._events = "This will override the super member and undermine the events list";
this.emit("data", data);
},
// on: function(){
// console.log("my on");
// events.EventEmitter.prototype.on.apply(this, arguments);
// },
constructor: MyStream
});
var stream = new MyStream();
console.log(stream instanceof events.EventEmitter); // true
console.log(stream instanceof MyStream); // true
stream.on("data", function(data) {
console.log('Received data: "' + data + '"');
})
stream.write("It works!"); // Received data: "It works!"
执行代码并且不会输出已接收的数据:“它有效!”除非你对该行发表评论this._events =“这将覆盖超级成员并破坏事件列表”;
我认为解决方案本身只有一些,但只是修复,也许我可以使用python中使用的模式。 如果你有一个名为YourClass的类的成员,前缀为__,就像python中的__yourMember一样,python编译器会将名称更改为__Classname_yourMember。所有私有成员都将以__Classname为前缀。如果类名是唯一的,那么您的私有成员也将是唯一的。 Javascript没有python的编译机制,所以我应该自己定义它。 更改以前的代码如下
var util = require("util");
var events = require("events");
var _ = require("underscore");
function MyStream() {
events.EventEmitter.call(this);
this.__MyStream = {
_events: "",
_maxListeners: 0
}
}
util.inherits(MyStream, events.EventEmitter);
_.extend(MyStream.prototype, {
write: function(data){
this.__MyStream._events = "This will not override the super member but it's odd";
this.emit("data", data);
},
// on: function(){
// console.log("my on");
// events.EventEmitter.prototype.on.apply(this, arguments);
// },
constructor: MyStream
});
var stream = new MyStream();
console.log(stream instanceof events.EventEmitter); // true
console.log(stream instanceof MyStream); // true
stream.on("data", function(data) {
console.log('Received data: "' + data + '"');
})
stream.write("It works!"); // Received data: "It works!"
但编写这样的代码很奇怪,我确信很少有像这样编写的库。我怎么能相信使用这些库,就好像它们没有破坏它们所包含的库一样? 你看到node.js的核心源代码很简单,但是当你使用带有很多第三方库的node.js构建一个大型项目时,你是否会被私人命名冲突的焦虑困扰?
也许有人会说使用javascript的模块模式。我知道,它当然不能解决我在这里问的问题。
有没有办法解决这个问题,或者我的问题只是出了点问题?