Define method without using prototype

- 1 answer

Ad

Is it possible to use the statement as shown below to define a method without the use of prototype?

Person.sayHello = function () {...}

On this example

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");
Ad

Answer

Ad

In short, no.

Person.sayHello = function () {...};

This line will add a function called "sayHello" to the Person class itself rather than to instances of the Person class. So, it can only be invoked by

Person.sayHello();

rather than by

var matt = new Person('Matt');
matt.sayHello();
// sayHello is not defined on matt

If you are familiar with Java or C#, adding a method to Person in this way is like creating a static method.

However, we can add a method to instances without adding a method to the prototype.

Method 1: Create the "sayHello" function in the constructor of Person

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

  this.sayHello = sayHello() {...};
};

This method has the disadvantage that a new function is created for every instance of Person. That is,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello != matt.sayHello;

Thus, this method can be hard on memory. However, it does allow for encapsulation (e.g. private state) via closures. In the following sample, it is impossible to modify the "count" variable outside of the Person class without calling the "sayHello" function.

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

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

  var count = 0;
};

Method 2: Create the "sayHello" function outside the constructor of Person and assign it within the constructor of Person

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

  this.sayHello = sayHello;
};

function sayHello() {...}

This method has the advantage of lower memory usage; there is only one instance of the sayHello function, and it is shared across instances of Person. That is,

var frank = new Person('Frank');
var matt = new Person('Matt');
// frank.sayHello == matt.sayHello;

This makes it similar to the prototype method. However, the assignment of the function to each instance still consumes more memory than the prototype method where the function is only assigned to the prototype object.

However, like the prototype method, this method does not allow for private state. All state must be accessed through public state exposed via the this keyword.


Update: Clarification of the difference in memory usage between method 1 and method 2.

Method 1 is like this:

var function1 = function() { console.log('Hello'); };
var function2 = function() { console.log('Hello'); };

The functions have the same behavior, but are not equal. JavaScript doesn't know they are functionally similar, so it creates two functions in memory to represent them.

Method 2 is like this:

var sayHello = function() { console.log('Hello'); };
var function1 = sayHello;
var function2 = sayHello;

Now function1 and function2 are actually the same function because they both simply hold a reference to sayHello.


Update: Example usage of a module pattern to avoid adding "sayHello" to the global scope in method 2.

This module defines the Person class in a module defined by an anonymous closure (a self executing function) and exports it to the global scope. Because "sayHello" is defined in the closure of the module and is not exported, it is not added to the global scope.

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

      this.sayHello = sayHello;
    };

    function sayHello() {...}

    return Person;
}());
Ad
source: stackoverflow.com
Ad