4

Consider the following piece of code:

var Animal = function(name) {
  return {
    name: name,
    speak: function() { return "My name is " + name; }
  };
};

var cat = Animal("Kitty");

My question is: what is the difference, in terms of performance, conventions, or best practices, between the code above and the following code:

var Animal = function(name) {
  this.name = name,
  this.speak = function() { return "My name is " + name; }
};

var cat = new Animal("Another Kitty");

Which one is preferable? What are some use cases for the new keyword?

Rafay
  • 23,785
  • 4
  • 20
  • 27
  • 1
    Here's a decent starting point that can get your hamster wheels rolling: [Ian Bicking - "new" only makes Javascript OO harder](http://www.ianbicking.org/blog/2013/04/new-considered-harmful.html) – Sunny Patel Jun 27 '16 at 18:38
  • Please limit your question to objective differences. There is a specific off-topic reason for questions which are primarily opinion-based, which is what your question appears to be in its current state. – Heretic Monkey Jun 27 '16 at 18:38
  • The first one creates a plain object, the second one creates an `Animal` instance ("inherits" from `Animal.prototype`). *"Which one is preferable?"* Depends on who you ask. Some people try to avoid `new` at all cost. – Felix Kling Jun 27 '16 at 18:38
  • 1
    Possible duplicate of [What is the 'new' keyword in JavaScript?](http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript) – Sunny Patel Jun 27 '16 at 18:38
  • Rafay while this question may be closed as a duplicate thank you for asking it. Duplicates are useful too, as they add new keywords to find the same information. – DavidS Jun 27 '16 at 18:39

2 Answers2

2

They are completely different when you consider prototypes (and everything they control, like inheritance). For example:

var SimpleAnimal = function(name) {
  return {
    name: name,
    speak: function() { return "My name is " + name; }
  };
};

var RealAnimal = function(name) {
  this.name = name,
  this.speak = function() { return "My name is " + name; }
};

var simpleCat = SimpleAnimal("Kitty");
var realCat = new RealAnimal("Another Kitty");

console.log(simpleCat instanceof SimpleAnimal, realCat instanceof RealAnimal); // simple is not an instance of the constructor
console.log(simpleCat.constructor, realCat.constructor); // because it uses the object literal constructor

This lack of prototype (and inheritance) means your object won't receive any methods defined on the class prototype:

var SimpleAnimal = function(name) {
  return {
    name: name,
    speak: function() {
      return "My name is " + name;
    }
  };
};

SimpleAnimal.prototype.roar = function() {
  console.log("roar!");
};

var RealAnimal = function(name) {
  this.name = name,
    this.speak = function() {
      return "My name is " + name;
    }
};

RealAnimal.prototype.roar = function() {
  console.log("roar!");
};

var simpleCat = SimpleAnimal("Kitty");
var realCat = new RealAnimal("Another Kitty");

try { simpleCat.roar(); } catch (e) { console.error(e); }
realCat.roar();
ssube
  • 47,010
  • 7
  • 103
  • 140
1

The first version returns a simple Object, the second one creates a new Animal.

The first version is good for small data objects. They can store different values, and that's pretty much it. They don't need a lot of memory.

The second one is for bigger objects. You can attach prototypes to them and use the "this" keyword to reach the object's properties. Because every object has the same properties, they take up considerably more space, than the first method.

Let's take the following and create a vector object. With the first method, you would do something like this:

function createVector(x, y) {
    return {
        x: x,
        y: y
    };
}

//Add to vectors together
function add(vec1, vec2) {
    return {x: vec1.x + vec2.x, y: vec1.y + vec2.y};
}

add(createVector(1, 1), createVector(1, 2)); //return {x: 2, y: 3}

This can be pretty useful, but what if you want to have multiple types of vectors (3 dimensional, 4 dimensional, etc...)? You would need to give a separate name for the adder functions, wich is not very nice. This is where the second method comes in. It can separate functions into different namespaces:

function Vector2(x, y) {
    this.x = x;
    this.y = y;
}

//Add vectors together:
Vector2.prototype.add = function(vec) {
    this.x += vec.x;
    this.y += vec.y;
};

new Vector2(1, 1).add(new Vector2(1, 2)); //{x: x, y: y}

This way, you can create multiple vector types and each of them could have a separate add function without interfering with each other.

You should use both of them based on what you want to achieve.

Bálint
  • 4,009
  • 2
  • 16
  • 27