JavaScript:向原型方法添加命名空间

时间:2014-05-30 19:49:34

标签: javascript namespaces prototype

我有一个商业应用程序,它具有使用原型链的现有JavaScript对象结构。通过向对象原型添加更多方法,我成功地扩展了这个API。但是,我意识到最好在我的方法前面添加一个命名空间,以防应用程序供应商决定在将来的版本中命名一个与我的方法相同的新方法。

如果我有一个名为State的现有对象,我会添加一个名为getPop的方法,如下所示:

State.prototype.getPop = function(){return this.pop;};

var Washington = new State('Washington',7000000);

Washington.getPop(); //returns 7000000

我想要做的是在我的自定义方法之前添加一个名为'cjl'的命名空间,以避免名称冲突,这样我就可以这样调用它:

Washington.cjl.getPop();

我试过了:

State.prototype.cjl = {};
State.prototype.cjl.getPop = function(){return this.pop;};

问题是这个。它不指向实例,而是指向'cjl'对象。

我尝试了各种方法,包括使用.bind(),但它们似乎都没有用。我终于在这里找到了答案:Is it possible to organise methods on an object's prototype into namespaces?这可以使用Object.defineProperty()方法。问题是商业应用程序仅在IE中的兼容模式下工作,它不支持非DOM元素的Object.defineProperty()方法。

还有另一种方法可以实现这一目标吗?我不想要调用多个函数,这是某些技术的结果,例如:

Washington.cjl().getPop();

3 个答案:

答案 0 :(得分:1)

您可以通过以下方式命名空间,阅读您的注释我看到您无法更改原始构造函数,因此您必须使用自己的原始替换原始文件并将原始文件保存在闭包中。

每个状态实例都有自己的cjl实例但只有对当前State实例的引用,所有cjl函数都是共享的,因为它们只存在一次:

<强> [UPDATE] 忘了在myState的原型链中获取State.prototype。

//the original constructor
function State(name, pop){
  this.name=name;this.pop=pop;
}
State.org="original constructor";

//original constructor is available through
//  closure and window.State is replaced with
//  your constructor having the cjl namespace
(function(State){
  //cjl namespace
  function cjl(stateInstance){
    this.stateInstance=stateInstance;
  };
  //cjl functions
  cjl.prototype.getPopInThousands=function(){
    //do not use this, instead use this.stateInstance
    return this.stateInstance.pop/1000;
  }
  function myState(){
    //apply State constructor
    State.apply(this,arguments);
    //create a clj instance, all methods
    //  are on cjl.prototype so they're shared
    this.cjl = new cjl(this);
  }
  //inherit from State (use polyfil for older browsers)
  myState.prototype = Object.create(State.prototype);
  //replace window.State with your constructor
  window.State=myState;
}(State))

var s = new State("Wasington", 7000000);
console.log(s.cjl.getPopInThousands());
//non standard, name
console.log("constructor name",s.constructor.name);
console.log("constructor tostring",s.constructor.toString());

有关构造函数和原型的更多信息,请访问:https://stackoverflow.com/a/16063711/1641941

我必须同意朋友和cookie,在修复函数名称之前可能是更好的解决方案但是如果你想对名为Country的对象使用相同的方法,那么你可以考虑使用之前的代码,因为你可以重新使用cjl对象。

答案 1 :(得分:0)

不要在函数外部定义State.prototype.cjl,而是尝试在构造函数中设置cjl“namespace”。

function State(){
    var thisObject = this;

    this.cjl = {
        getPop: function(){
            return thisObject.pop;
        }
    };
}

然后你可以Washington.cjl.getPop();

答案 2 :(得分:0)

尝试:

var State = function(name, pop) {
  this.name = name;
  this.pop = pop;
};

State.prototype.cjl = function(method) {
  return this.cjlDefs[method].apply(this, Array.prototype.slice.call(arguments, 1) );
};

State.prototype.cjlDefs = {
  getPop: function() {return this.pop;}
};


var Washington = new State('Washington', 80000);
console.log( Washington.cjl('getPop') );

https://jsfiddle.net/ghbjhxyh/

如果您愿意,可以使用其他形状:

var State = function(name, pop) {
  this.name = name;
  this.pop = pop;
};

State.prototype.cjl = function(method) {
  this.cjlDefs.obj = this;
  return this.cjlDefs;
};

State.prototype.cjlDefs = {
  assertObj: function() { /* Make sensible assertion */ },
  getPop: function() { this.assertObj(); return this.obj.pop; }
};

var Washington = new State('Washington', 75000);
console.log( Washington.cjl().getPop() ); // 75000

https://jsfiddle.net/7vjrz2mn/