解决javascript继承中私有成员的潜在命名冲突

时间:2014-03-16 03:59:24

标签: javascript node.js oop

我在这里问的问题不是关于如何在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的模块模式。我知道,它当然不能解决我在这里问的问题。

有没有办法解决这个问题,或者我的问题只是出了点问题?

0 个答案:

没有答案