不使用原型定义方法

Fra*_*Lee -1 javascript

是否可以使用如下所示的语句来定义方法而不使用prototype

Person.sayHello = function () {...}
Run Code Online (Sandbox Code Playgroud)

在这个例子中

var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");
Run Code Online (Sandbox Code Playgroud)

Mat*_*ill 5

简而言之,不。

Person.sayHello = function () {...};
Run Code Online (Sandbox Code Playgroud)

此行将向 Person 类本身而不是向 Person 类的实例添加一个名为“sayHello”的函数。所以,它只能被调用

Person.sayHello();
Run Code Online (Sandbox Code Playgroud)

而不是通过

var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt
Run Code Online (Sandbox Code Playgroud)

如果您熟悉 Java 或 C#,以这种方式向 Person 添加方法就像创建静态方法一样。

但是,我们可以向实例添加方法,而不向原型添加方法。

方法一:在Person的构造函数中创建“sayHello”函数

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello() {...};
};
Run Code Online (Sandbox Code Playgroud)

此方法的缺点是为 Person 的每个实例创建一个新函数。那是,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;
Run Code Online (Sandbox Code Playgroud)

因此,这种方法可能很难记忆。然而,它确实允许通过闭包进行封装(例如私有状态)。在下面的示例中,如果不调用“sayHello”函数,就不可能在 Person 类外部修改“count”变量。

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello() {
    count++;
    console.log("Hello has been said " + count + "times".
  };

  var count = 0;
};
Run Code Online (Sandbox Code Playgroud)

方法2:在Person的构造函数外部创建“sayHello”函数,并在Person的构造函数内部对其进行赋值

var Person = function (firstName) {
  this.firstName = firstName;

  this.sayHello = sayHello;
};

function sayHello() {...}
Run Code Online (Sandbox Code Playgroud)

该方法的优点是内存占用较低;sayHello 函数只有一个实例,并且在 Person 的实例之间共享。那是,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;
Run Code Online (Sandbox Code Playgroud)

这使得它类似于原型方法。然而,将函数分配给每个实例仍然比原型方法消耗更多的内存,原型方法只将函数分配给原型对象。

但是,与原型方法一样,此方法不允许私有状态。所有状态都必须通过this关键字公开的公共状态来访问。


更新:澄清方法 1 和方法 2 之间的内存使用差异。

方法1是这样的:

var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };
Run Code Online (Sandbox Code Playgroud)

这些函数具有相同的行为,但不相等。JavaScript 不知道它们在功能上相似,因此它在内存中创建两个函数来表示它们。

方法2是这样的:

var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;
Run Code Online (Sandbox Code Playgroud)

现在 function1 和 function2 实际上是同一个函数,因为它们都只保存对 sayHello 的引用。


更新:使用模块模式来避免将“sayHello”添加到方法 2 中的全局范围的示例。

该模块在由匿名闭包(自执行函数)定义的模块中定义了 Person 类,并将其导出到全局范围。因为“sayHello”是在模块的闭包中定义的并且未导出,所以它不会添加到全局范围中。

var Person = (function () {
    function Person(firstName) {
      this.firstName = firstName;

      this.sayHello = sayHello;
    };

    function sayHello() {...}

    return Person;
}());
Run Code Online (Sandbox Code Playgroud)