简体   繁体   English

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

[英]JavaScript: Adding a Namespace to Prototype Methods

I have a commercial application that has an existing JavaScript object structure using prototype chains. 我有一个商业应用程序,该应用程序具有使用原型链的现有JavaScript对象结构。 I have had success extending this API by adding more methods to the prototypes of objects. 通过在对象原型中添加更多方法,我成功扩展了此API。 However, I realize that it would be best to add a namespace in front of my methods in case the application vendor decides to name a new method the same as one of my methods in a future release. 但是,我意识到最好是在我的方法前添加一个名称空间,以防应用程序供应商决定命名一个新方法,使其与将来版本中的一个方法相同。

If I have an existing object called State, I would add a method called getPop like so: 如果我有一个名为State的现有对象,则可以添加一个名为getPop的方法,如下所示:

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

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

Washington.getPop(); //returns 7000000

What I want to do is add a namespace called 'cjl' before my custom method to avoid name collision so that I can call it like so: 我想做的是在自定义方法之前添加一个名为“ cjl”的命名空间,以避免名称冲突,这样我就可以这样调用它:

Washington.cjl.getPop();

I tried: 我试过了:

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

The problem is this . 问题是这样的 It doesn't point to the instance but instead points to the 'cjl' object. 它不指向实例,而是指向'cjl'对象。

I tried various methods, including using .bind() but none of them seemed to work. 我尝试了各种方法,包括使用.bind(),但似乎都没有用。 I finally found an answer here: Is it possible to organise methods on an object's prototype into namespaces? 我终于在这里找到答案: 是否可以将对象原型上的方法组织到名称空间中? This works using the Object.defineProperty() method. 使用Object.defineProperty()方法可以工作。 The problem is the commercial application only works in compatibility mode in IE which doesn't support the Object.defineProperty() method for non-DOM elements. 问题在于商业应用程序仅在IE中的兼容模式下工作,该模式不支持非DOM元素的Object.defineProperty()方法。

Is there another way to accomplish this? 还有另一种方法可以做到这一点吗? I don't want to have to call multiple functions, which is the result of some techniques, eg: 我不想调用多个函数,这是某些技术的结果,例如:

Washington.cjl().getPop();

You could namespace in the following way, reading your comments I see that you can't change the original constructor so you'll have to replace the original with your own and save the original in a closure. 您可以通过以下方式命名空间,阅读您的评论,我看到您无法更改原始构造函数,因此必须将其替换为自己的原始构造函数并将其保存在闭包中。

Every state instance will have it's own cjl instance but that only has a reference to current State instance, all the cjl functions are shared as they exist only once: 每个状态实例都有其自己的cjl实例,但仅具有对当前State实例的引用,所有cjl函数均被共享,因为它们仅存在一次:

[UPDATE] Forgot to get State.prototype in myState's prototype chain. [更新]忘记在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());

More on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941 有关构造函数和原型的更多信息,请参见: https : //stackoverflow.com/a/16063711/1641941

I have to agree with friend and cookie that pre fixing the function names may be the better solution but if you want to use the same methods for an object named Country then you may think of using the previous code as you can re use the cjl object. 我必须同意朋友和Cookie的观点,即预先确定函数名称可能是更好的解决方案,但是如果您想对名为Country的对象使用相同的方法,那么您可能会考虑使用前面的代码,因为可以重新使用cjl对象。

Instead of defining State.prototype.cjl outside of the function, try to set the cjl "namespace" inside the constructor function. 与其在函数外定义State.prototype.cjlcjl在构造函数内设置cjl “命名空间”。

function State(){
    var thisObject = this;

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

Then you can do Washington.cjl.getPop(); 然后,您可以执行Washington.cjl.getPop(); .

Try: 尝试:

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/ https://jsfiddle.net/ghbjhxyh/

Or another shape if you prefer: 或其他形状,如果您喜欢:

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/ https://jsfiddle.net/7vjrz2mn/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM