The question I'm asking here is not about how to realize a private member on js object. It could be done as below
function MyClass(member){
var privateMember = member;
this.getPrivateMember = function(){
return privateMember;
};
}
my = new MyClass("newbie");
console.log(my.getPrivateMember());
But the problem is not all of the libraries implement their object as closures and it has performance issue as function member will be in every instance, not the prototype with only one copy.
See the sample code on 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 has formal implemention of inherit as util.inherits I read the source code of util and events. The code of util.inherits is
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
You know it just put the prototype of super constructor as the prototype of subconstrutor and certainly won't hide the private members of the super constructor. When we contruct the subconstructor as the sample code
function MyStream() {
events.EventEmitter.call(this);
}
all of the events.EventEmitter's members will be put in the instance of MyStream. You don't know what you will get unless you read the source code of events.EventEmitter. I read it and copy it here for the brevity
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;
You know a lot of js coders naming member with an underscore prefix as it should be private and better not be modified by others. But it's not the solution because you won't know what the underscore prefixed member will be. If you define your own pseudo-private member with the underscore, the super pseudo-private member may be the same name with yours. You will probably devastate the encapulation of superior. I emulate a situation as below
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!"
Excute the code and it will not output Received data: "It works!" unless you comment the line this._events = "This will override the super member and undermine the events list";
I thought the solution myself for some while only fix that maybe I could use the pattern as it was used in python. If you got a member of a class named YourClass with a prefix of __, just like __yourMember in python, the python compiler will change the name to __Classname_yourMember. All of the private member will be prefixed with __Classname. If the class name is unique, your private members will be unique too. Javascript doesn't have the compiling mechanism as python, so I should define it on my own. Change the former code as below
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!"
But it's odd to write code like this and I'm sure few of libaries written like this. How could I trust to use these libs as if they didn't break the libs they are inherting? You see the core source code of node.js is simple, but when you build a large scale project using node.js with a lot of third party lib, will you be bothered by the anxiety of private naming conflicts?
Maybe someone will say to use the module pattern of javascript. I know it and it of course will not solve the problem I ask here.
Is there any way to solve this or I just made something wrong for my question?