Search code examples
javascriptjavascript-objects

Javascript - How to create new instance of functions


I know that, we can create the new instance of functions by the following approach. But my question is there any other way to achieve the same?

var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

var person1 = new Person('Alice');
var person2 = new Person('Bob');

// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"

Since, some time in case of new declaration fails, i am not getting the error too..

Especially, in javascript oops concept requires the different approach.

Some times, I am confusing without even calling the new key words it all works fine.. what is the different between using the new keyword and without using that?

example :

var setColor = function (color) {
   return color;
}

var x = setColor('red');
var y = setColor('blue');

console.log(y);
console.log(x);

Solution

  • The new [Function] keyword does many things, but the main things it does are:

    • Creates a new object
    • Uses [Function]'s prototype as the parent prototype for the new object
    • Executes the contents of [Function], using this as a reference to the new object

    If you call such a function without new, the this reference will be determined the way it would usually be determined when calling a function, and quite often this would be the global object.

    One thing you can do to help catch these mistakes more easily is to use strict mode:

    "use strict";
    
    var Person = function (firstName) {
      this.firstName = firstName;
      console.log('Person instantiated');
    };
    
    var person1 = Person('Alice');
    

    If the above code were executed, this would be null instead of the global object, and you would get an error right away instead of having the properties assigned to the global object (and having hard-to-catch bugs).

    A way to avoid these kinds of mistakes with new altogether is to simply have the function return a new object instead of being a constructor:

    var person = function (firstName) {
      console.log('person instantiated');
      return {
          firstName: firstName
      };
    };
    
    var person1 = person('Alice');
    var person2 = person('Bob');
    

    If you do this, it doesn't matter whether you use new or not, because the function doesn't use this.

    Edit There was a question below about prototypes. If you are unfamiliar with prototypes, this is a feature that allows you to specify properties and methods that will be shared between all instances of an object:

    "use strict";
    
    var Person = function (firstName) {
      this.firstName = firstName;
      console.log('Person instantiated');
    };
    
    Person.prototype.getMyName = function () {
        return this.firstName;
    };
    
    var person1 = new Person('Alice');
    console.log(person1.getMyName());
    

    If you do this, then all instances created with new Person() will share the getMyName method.

    The new-less option I detailed later on does not provide this automatic prototype extension, but there are alternatives:

    Option 1 - don't use a prototype:

    var person = function (firstName) {
      console.log('person instantiated');
      return {
          firstName: firstName,
          getMyName: function () {
              return this.firstName;
          }
      };
    };
    

    Option 2 - Use Object.create() to extend the prototype:

    var person = function (firstName) {
      console.log('person instantiated');
      var person = Object.create(person.prototype);
      person.firstName = firstName;
    
      return person;
    };
    

    Option 3 - Use Object.assign() method to copy the contents of the prototype to a new object:

    var person = function (firstName) {
      console.log('person instantiated');
    
      return Object.assign({
          firstName: firstName
      }, person.prototype);
    };