如何制作特权JS方法?

时间:2016-10-15 16:21:47

标签: javascript oop

我希望能够调用使用私有数据的子函数。目前我有这个:

var myFunction4 = function() {
  this.secret1 = 0;
  this.secret2 = 0;
  var that = this;

  this.iterate1 = function(){
    return that.secret1++;
  }

  this.iterate2 = function(){
    return that.secret2++;
  }

  this.addSecrets = function(){
    return that.secret1 + that.secret2;
  }

  return {
      iterate1: this.iterate1,
      iterate2: this.iterate2,
      addSecrets: this.addSecrets,
  }
};

关于这一点的坏处是,要调用其中一种方法,我必须这样做:

myFunction4().iterate1();

每次我想访问某个方法时都执行myFunction4()。这不仅效率低下,而且每次都会重置secret1,因此我无法重复它。我尝试过使用new运算符,但这会暴露secret1secret2,并且会影响深度嵌套函数的能力。

var myFunction3 = function() {
  this.secret1 = 0;
  this.secret2 = 0;

  this.iterate1 = function(){
    return this.secret1++;
  }

  this.iterate2 = function(){
    return this.secret2++;
  }

  this.addSecrets = function(){
    return this.secret1 + this.secret2;
  }
};
var f3 = new myFunction3();
f3.secret1; // exposes the secret!

有关更多示例,请参阅console logs at the bottom of this JSFiddle

如何使用私有和公共变量/方法保留其值并且不需要多次调用?

6 个答案:

答案 0 :(得分:4)

While the other answers are absolutely fine and correct, there is one more issue to consider when emulating OOP behaviour in javascript.

The function execution context issue will bite us hard when we will try to use a public method as a e.g. async. callback.

The magical this will point to a different object then we expect in the OOP world.

Of course there are ways to bind the context but why to worry about this after we define the 'class' in a non OOP js ;)

Here is a simple solution to this: Do not use this. Let the closure refactor this out ;)

var myFunction4 = function() {
  // we could inherit here from another 'class' (object)
  // by replacing `this` with e.g. `new SuperClass()`
  var that = this;

  // 'private' variables
  var secret1 = 0;
  var secret2 = 0;

  // 'public' variables
  that.somePublicVar = 4;

  // 'private' methods
  var somePrivateMethod = function(){         
     secret2 = 77;
     that.somePublicVar = 77;
  }

  // 'public' methods
  that.iterate1 = function(){
    return secret1++;
  }

  that.iterate2 = function(){
    return secret2++;
  }

  that.addSecrets = function(){
    return secret1 + secret2;
  }

  return that;
};

var f = new myFunction4();
console.log( f.iterate1() );    // 0
console.log( f.iterate1() );    // 1
console.log( f.secret1 );       //undefined
console.log( f.somePublicVar );       //4

答案 1 :(得分:2)

试试(关闭力量!):

var myFunction3 = function() {
  var secret1 = 0;
  var secret2 = 0;

  this.iterate1 = function(){
    return secret1++;
  }

  this.iterate2 = function(){
    return secret2++;
  }

  this.addSecrets = function(){
    return secret1 + secret2;
  }
};
var f3 = new myFunction3();

现在只有方法暴露

编辑版:

如果你不想每次调用子方法时都执行main函数,你可以改变你的方法并使用IIFE的强大功能(立即调用的函数表达式)

   var myFunction4 = (function() {
       var secret1 = 0;
       var secret2 = 0;

       var iterate1 = function(){
           return secret1++;
       }

       var iterate2 = function(){
           return secret2++;
       }

       var addSecrets = function(){
           return secret1 + secret2;
       }

       return {
           iterate1: iterate1,
           iterate2: iterate2,
           addSecrets: addSecrets
       }
 }());

然后你可以使用它:

myFunction4.iterate1();
myFunction4.iterate2();
myFunction4.addSecrets();

希望这有助于你

答案 2 :(得分:1)

我通常只使用工厂模式来创建对象,除非我绝对需要具有原型继承的性能优势。

使用工厂模式也意味着您不必在不同的环境中处理this不断变化的值。



var factory = function() {
  // internal private state
  var state = {
    secret1: 0,
    secret2: 0
  }

  function iterate1(){
    return state.secret1++;
  }

  function iterate2(){
    return state.secret2++;
  }

  function addSecrets(){
    return state.secret1 + state.secret2;
  }
  
  function __privateMethod() {
    // this is private because it's not on the returned object
  }
  // this is the public api
  return {
    iterate1,
    iterate2,
    addSecrets
  }
}

// create a secret module
var secret = factory()

console.log(
  secret.iterate1(), // 0
  secret.iterate2(), // 0
  secret.addSecrets(), // 2
  secret.secret1, // undefined
  secret.secret2 // undefined
)

// you can even create more with the same factory
var secret2 = factory()




答案 3 :(得分:1)

根据您的第二个片段,我从您的解释中理解的是,您需要在实例化对象中使用sharedPrivate。您无法使用经典对象创建模式(如构造函数,工厂或模块)执行此操作。这可以通过在构造函数的原型中使用闭包下的私有变量来实现,这样每次创建对象时都不会重置它,同时为实例化的对象提供访问,修改和私有共享的必要方法。

function SharedPrivate(){
  var secret = 0;
  this.constructor.prototype.getSecret = function(){return secret}
  this.constructor.prototype.setSecret = function(v){ secret = v;}
  this.constructor.prototype.incrementSecret = function(){secret++}
}

var o1 = new SharedPrivate();
var o2 = new SharedPrivate();

console.log(o1.getSecret()); // 0
console.log(o2.getSecret()); // 0
o1.setSecret(7);
console.log(o1.getSecret()); // 7
console.log(o2.getSecret()); // 7
o2.incrementSecret()
console.log(o1.getSecret()); // 8

获得类似结果的另一种方法是

function SharedPrivate(){
var secret = 0;
return {getS : function(){return secret},
        setS : function(v){secret = v},
        incS : function(){secret++}
       };
}
sharedProto = SharedPrivate();       // secret is now under closure to be shared
var o1 = Object.create(sharedProto); // sharedProto becomes o1.__proto__
var o2 = Object.create(sharedProto); // sharedProto becomes o2.__proto__

o1.setS(7);             // o1 sets secret to 7
console.log(o2.getS()); // when o2 access it secret is still 7
o2.incS();              // o2 increments the secret
console.log(o1.getS()); // o1 can access the incremented value

答案 4 :(得分:1)

为什么不尝试显示模块模式

var myFunction4 = function() {
  var secret1 = 0,
  secret2 = 0,

  iterate1 = function(){
    return secret1++;
  },

  iterate2 = function(){
    return secret2++;
  },

  addSecrets = function(){
    return secret1 + secret2;
  };

  // public functions and properties
  return {
      iterate1: iterate1,
      iterate2: iterate2,
      addSecrets: addSecrets,
  }
}();

myFunction4.iterate1(); // is available
myFunction4.secret2; // is private and not available outside of myFunction4

希望有所帮助

答案 5 :(得分:1)

基本模式:

var myFunction = function() {
  var that = this;
  var secret1 = 0;
  var secret2 = 0;  // private
  this.public1 = 0; // public

  this.iterate1 = function(){
    return secret1++;
  }

  this.iterate2 = function(){
    return secret2++;
  }

  this.addSecrets = function() { // public
    return privateMethod();
  }

  var privateMethod = function() { // private
     return secret1 + secret2;
  }

  return this;  // return function itself!
};

var myFn = new myFunction();
myFn.public1 // 0
myFn.secret1 // undefined
myFn.addSecrets(); 

我建议你阅读Addy Osmani的优秀Learning JavaScript Design Patterns