简体   繁体   中英

In javascript, Is there a perfect way to define class

I am looking for a perfect way to define class. "perfect" here means:`

  1. create instances will not create copies of methods.
  2. public function could easily(not to much hassle) access private variable

For example, way 1:

function Foo1() {
  var private1;
  this.publicMethod1 = function() {//create instance will create copy of this function}
}

will not meet rule No.1 above.

Another example, way 2:

 function Foo2() {
      var private2;

    }
 Foo2.prototype.Method2 = function() {//cannot access private2}

will not meet rule No.2 above.

So is it possible to meet both rules? Thanks.

In JavaScript it's more about conventions. Private properties or methods are defined with a underscore first like _private . With a few helpers you can make classes easily. I find this setup easy enough, all you need is a helper inherits to extend classes, and instead of using multiple arguments you pass in an object props and simply call "super" on the inherited classes with arguments . For example, using a module pattern:

Function.prototype.inherits = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

var Person = (function PersonClass() {

  function Person(props) {
    this.name = props.name || 'unnamed';
    this.age = props.age || 0;
  }

  Person.prototype = {
    say: function() {
      return 'My name is '+ this.name +'. I am '+ this.age +' years old.';
    }
  };

  return Person;

}());

var Student = (function StudentClass(_super) {

  Student.inherits(_super);      

  function Student(props) {
    _super.apply(this, arguments);
    this.grade = props.grade || 'untested';
  }

  Student.prototype.say = function() {
    return 'My grade is '+ this.grade +'.'; 
  };

  return Student;

}(Person));

var john = new Student({
  name: 'John',
  age: 25,
  grade: 'A+'
});

console.log(JSON.stringify(john)); //=> {"name":"John","age":25,"grade":"A+"}
console.log(john.say()); //=> "My grade is A+"

About the private variable "issue" just stick to convention for instance properties and use closures when needed for everything else private.

function Foo3() {
    this.private = {};
}

Foo3.prototype.set_x = function (x) {
    this.private.x = x;
};

To make a long story short: no, it is not. You cannot extend the prototype with methods that could access private variables. At least if these private variables are made private via a closure .

Though, it is a convention in javascript that you mark your private fields with an underscore, for example _myPrivateField . These would be still public, but i have seen this solution being used in many libraries and i also prefer that style to meet your first rule.

A basic example is below:

Foo = function(id)
{
    // private instances.
    var _id;
    var _self = this;

    // constructor
    _id = id;

    // private method
    function _get()
    {
        return _id;
    };

    // public function
    _self.set = function(id)
    {
        _id = id;
    };
    _self.get = function()
    {
        return _get();
    };
};

var bar = Foo(100);
console.log( bar.get() );
bar.set(1000);
console.log( bar.get() );

I would recommend you use prototype .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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