解决javascript继承中私有成员的潜在命名冲突
这里我要问的问题不是如何在js对象上实现私有成员。 可以按如下方式进行解决javascript继承中私有成员的潜在命名冲突,javascript,node.js,oop,Javascript,Node.js,Oop,这里我要问的问题不是如何在js对象上实现私有成员。 可以按如下方式进行 function MyClass(member){ var privateMember = member; this.getPrivateMember = function(){ return privateMember; }; } my = new MyClass("newbie"); console.log(my.getPrivateMember()); var util = r
function MyClass(member){
var privateMember = member;
this.getPrivateMember = function(){
return privateMember;
};
}
my = new MyClass("newbie");
console.log(my.getPrivateMember());
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作为util.inherits正式实现了inherit
我阅读了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
}
});
};
你知道它只是把超级构造函数的原型作为子构造函数的原型,当然不会隐藏超级构造函数的私有成员。
当我们将subconstructor构造为示例代码时
function MyStream() {
events.EventEmitter.call(this);
}
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编码人员使用下划线前缀命名成员,因为它应该是私有的,最好不要被其他人修改。但这不是解决方案,因为您不知道带下划线前缀的成员是什么。如果使用下划线定义自己的伪私有成员,则超级伪私有成员可能与您的同名。你可能会摧毁superior的营地。
我模拟如下一种情况
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!"
执行代码,它将不会输出收到的数据:“它工作!”除非您对此行进行注释。\u events=“这将覆盖超级成员并破坏事件列表”
有一段时间,我自己认为解决方案只能解决这个问题,也许我可以使用python中使用的模式。
如果您得到一个名为YourClass的类的成员,其前缀为uuuuuu,就像python中的uuuu yourMember一样,python编译器会将名称更改为uuu Classname u yourMember。所有私有成员都将以_Classname作为前缀。如果类名是唯一的,那么您的私有成员也将是唯一的。
Javascript没有python那样的编译机制,所以我应该自己定义它。
将前一代码更改如下
function MyClass(member){
var privateMember = member;
this.getPrivateMember = function(){
return privateMember;
};
}
my = new MyClass("newbie");
console.log(my.getPrivateMember());
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!"
但是写这样的代码是很奇怪的,我相信很少有图书馆是这样写的。我怎么能相信使用这些LIB,就好像它们没有打破它们所拥有的LIB一样?
您可以看到node.js的核心源代码很简单,但是当您使用node.js和大量第三方库构建一个大型项目时,您是否会担心私有命名冲突
也许有人会说使用javascript的模块模式。我知道,这当然不能解决我在这里提出的问题
有没有办法解决这个问题,或者我的问题出了问题?Javascript不是传统的面向对象语言。我知道。标题可能不准确,因此我将其更改为使用类名作为私有变量的前缀不是一个坏主意,但手动这样做是不正确的。这就是为什么您应该有一个构建系统,它通过代码转换为您实现这一点。或者您使用node.js已经支持的es6符号:致命缺陷?不,数百万JS开发人员使用原型继承,过得很好。我想你什么都不担心。也很有趣: