在JavaScript中构建"类"的现代方法是什么?

Fra*_*urd 22 javascript

如何构建一个"类"(带有属性和方法),将在其上创建大量实例?

Jus*_*son 23

在现代的方法是使用class,如ES6介绍.

class Movie {
    constructor(name) {
        this.name = name;
        // The "_" prefix is commonly used to denote "private" members.
        this._id = +new Date();
    }

    getName() {
        return `${this.name} ${this._id}`;
    }

    setName(name) {
        this.name = name;
    }
}

const movie = new Movie('Beerfest');

console.log(movie.getName());
Run Code Online (Sandbox Code Playgroud)

上面的示例提供了与2010年原始示例等效的接口.


2010年的原始答案:

在"现代"JavaScript中,有三种流行的方法来定义对象.

第一种方法是经典方法,因其简单性而仍然很受欢迎; 但是,MDC不赞成采用第二种方法,因为每次创建对象实例时都必须重新定义每个函数.

// Constructor, methods and members all rolled up into one definition
var Movie = function(name) {
    this.name = name;
    // Note that private members can be created using the closure property
    var _id = +(new Date());

    this.getName = function() {
        return this.name + " " + _id;
    };

    this.setName = function(name) {
        this.name = name;
    };
};

var m = new Movie("Beerfest");
Run Code Online (Sandbox Code Playgroud)

第二种方法是第一种方法的变体,并且可以与第一种方法互换使用.通过prototype属性向现有对象添加新方法也很有用.这种形式不支持私人成员和方法.

// Constructor is separate from its methods
var Movie = function(name) {
    this.name = name;
}

Movie.prototype.getName = function() {
    return name;
};

Movie.prototype.setName = function(name) {
    this.name = name;
};

var m = new Movie("Kill Bill");
Run Code Online (Sandbox Code Playgroud)

第三种方法是使用模块模式,这使得可以在不必使用new运算符的情况下实例化对象.

var Movie = function (name) {
    var _id = +(new Date());
    var privateMethod = function() { alert(_id); };

    // All methods and members defined here are public
    return {
        name: name,
        getName: function() {
            return this.name + " " + _id;
        },
        setName: function(name) {
            this.name = name;
        }
    };
};

var m = Movie("Stackoverflow: the movie");
Run Code Online (Sandbox Code Playgroud)

请注意,在第一种和第三种方法中,您可以使用私有访问成员和方法.但请注意,要this在私有方法中使用,必须发生一些事情.


oyv*_*ndn 10

// I like this pattern..

// class
function Person(name, birthdate) {
  this._name = name;
  this._birthdate = birthdate;
  /* should not do this
  * this.getAge = function() {
  * }
  * as the method will be constructed
  * for each instance, better to let it
  * be inherited from prototype, see below
  */
}

// class methods
Person.prototype.getBirthdate = function() {
  return this._birthdate;
}

// same as above, function as a method
Person.prototype.getAge = function() {
  var currentDate = new Date();
  // age in millis
  return currentDate - this._birthdate;
}

// the get age method can be a "static"
// method on the constructor function if you pass the
// person object
Person.getAge = function(person) {
  var currentDate = new Date();
  // age in millis
  //no reference to this
  return currentDate - person.getBirthdate();
}

// you could use it like this

myPerson = new Person("Steve", new Date("1980-01-01"));
// returns age in millis
myPerson.getAge();
// returns age in millis
Person.getAge(myPerson);
Run Code Online (Sandbox Code Playgroud)

您还可以使用匿名函数来模拟私有和公共

var PersonFactory = (function() {
  // private area, no one can alter
  // the person cache
  var _cache = {}

  // public area
  return {
    // returns a person born now
    getPerson: function(name) {
      if(_cache[name]) {
        return _cache[name];
      }
      else {
        _cache[name] = new Person(name, new Date());
        return _cache[name];
      }
    }
  }
})();

var p = PersonFactory.getPerson("Leif");
p.getAge();
p = PersonFactory.getPerson("Leif");
// should be the same age / obj
p.getAge();
Run Code Online (Sandbox Code Playgroud)

我不喜欢这种模式.下划线警告_myVariable应该足以让lib的用户不使用这些变量/方法.由于我的Java背景,我在第一次发现它时使用了它.它使得使用原型继承很困难并且可能导致内存泄漏.