创建JavaScript类的最佳方法是什么?

时间:2012-11-02 05:58:26

标签: javascript oop

  

可能重复:
  Use of ‘prototype’ vs. ‘this’ in Javascript?
  Object Oriented questions in Javascript

您能否请您推荐以下哪一项最佳或者是利弊?

方法1

function User() {

    this.name = "my name";
    this.save = function() {

    };
}

方法2

function User() {

    this.name = "my name";
}

User.prototype.save = function() {

}

4 个答案:

答案 0 :(得分:52)

来自Java和PHP的背景,我最初在JavaScript中使用整个“类”概念。以下是一些需要考虑的事项。

建筑

首先,因为您可能会将您的类定义为..

Customer = function () {}
Customer.prototype = new Person();

如果要在构造过程中定义属性和方法,最终会遇到各种代码的噩梦。原因是像Customer.prototype = new Person();这样的代码要求在Customer构造函数中调用Person以实现真正的继承。否则,您最终必须知道原始设置始终是什么。请看以下示例:

Person = function (name) {
    this.name = name;
    this.getName = function () {return this.name}
}
Customer = function (name) {
    this.name = name;
}
Customer.prototype = new Person();

现在我们要更新Person以设置它们是否为'new':

Person = function (name, isNew) {
    this.name = name;
    this.isNew = isNew;
    this.getName = function () {return (this.isNew ? "New " : "") + this.name; }
}

现在,在继承自Person的任何“类”上,必须更新构造函数以遵循表单。您可以通过执行以下操作来解决这个问题:

Customer = function () {
    Person.apply(this, arguments);
}

这将在新“客户”的范围内调用“人员”,使您无需了解人员构造。

速度

看看这些基准:http://jsperf.com/inherited-vs-assigned 基本上,我在这里要证明的是,如果你要创建这些对象 en masse ,那么最好的方法是在原型上创建它们。创建它们像:

Person = function (name) {
    this.name = name;
    this.getName = function () {return this.name}
}

非常慢,因为对于每个对象创建,它都会创建一个新函数 - 它不会简单地查找现有对象的原型链。相反,如果你只有几个对象被频繁调用,那么在本地定义它们有助于通过查找原型链来减少速度。

共享属性

这总是让我感动。假设您有以下内容:

Person = function () {
    this.jobs = {};
    this.setJob = function (jobTitle, active) {this.jobs[jobTitle] = active; }
}

Employee = function () {}
Employee.prototype = new Person();

var bob = new Employee();
bob.setJob('janitor', true);

var jane = new Employee();
console.log(jane.jobs);
猜猜是什么?简是一个看门人!可不是闹着玩的!这就是原因。由于您没有将this.jobs定义为实例化 Employee 的新对象,因此现在只需查找原型链,直到找到“作业”并按原样使用它。好玩,对吧?

所以,如果你想跟踪实例,这很有用,但是在大多数情况下你会发现它非常令人沮丧。您可以通过执行以下操作来解决这个问题:

Employee = function () { Person.apply(this); }

这迫使'人'创建一个新的'this.jobs'。

私有变量

由于JavaScript中没有任何真正的“私有”,因此获取私有变量的唯一方法是在构造函数中创建它们,然后在构造函数中初始化依赖它们的任何内容。

Person = function () {
    var jobs = {};
    this.setJob = function (jobTitle, active) {jobs[jobTitle] = active; }
    this.getJob = function (jobTitle) { return jobs[jobTitle]; }
}

但是,这也意味着必须在继承类的每个实例化上调用该构造函数。


建议

http://ejohn.org/blog/simple-javascript-inheritance/

这是一个超级基础类设置。这很简单。有用。并且它可以做到你需要它做90%的时间而不必处理JavaScript提供的所有疯狂:)

</rant>

答案 1 :(得分:10)

最好是一个非常主观的术语。

方法1提供了真正私有变量的可能性。例如:

function User() {
   var name = "fred";
   this.getName = function () { return name;};
}

方法2将使用更少的内存,因为所有用户对象共享一个保存功能。

'最佳'将取决于您的具体要求。

答案 2 :(得分:7)

JavaScript是一种“基于对象”的语言,而不是“基于类”的语言。共享行为,即类概念,通过链接原型来实现。

方法1不创建类。每次调用它时,都会按照定义创建属性和函数,并且不与其他“实例”共享。如果替换this.save,那么只有一个实例会改变行为。

方法2实现共享行为。因此,它是人们与类和实例相关联的。如果使用其他函数替换this.save,则所有派生实例将立即具有新行为。

如果“最佳”意味着没有内存消耗功能的重新定义和共享常见行为(这是基于类的编程倾向于等同于),方法2就是可行的方法。

答案 3 :(得分:5)

正如其他人所说,有两个主要区别:

  • 方法1将为User
  • 的每个实例创建一个新函数
  • 方法1将能够访问构造函数范围内的局部变量

以下是一个展示这些内容的示例:

function User() {

    var name = "my name";

    this.foo = function() {
        // one function per User instance
        // can access 'name' variable
    };
}

User.prototype.bar = function() {
    // one function shared by all User instances
    // cannot access 'name' variable
};

var a = new User();
var b = new User();

console.log(a.foo === b.foo); // false; each instance has its own foo()
console.log(a.bar === b.bar); // true; both instances use the same bar()