Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object.create isn't creating a new object using the module pattern

Tags:

javascript

If I create multiple objects using Object.create() on an object literal, I get multiple unique objects that don't share property values. However, when I use Object.create() on an object returned from a module, it looks like they share the same reference? Why is that?

#1 Module:

var objModule = (function () {
  var name = "module 1";
  var setName = function( strName ) {
    name = strName;
  };
  var getName = function() {
    return name;
  };

  return {
    setName: setName,
    getName: getName
  };
}());

var objModule2 = Object.create(objModule);
objModule2.setName("module 2");

console.log(objModule.getName()); // WRONG prints "module 2"
console.log(objModule2.getName()); // prints "module 2"

#2 Literal:

var objLiteral = {
  name : "literal 1"
};
var objLiteral2 = Object.create(objLiteral);
objLiteral2.name = "literal 2";

console.log(objLiteral.name); // prints "literal 1"
console.log(objLiteral2.name); // prints "literal 2"

EDIT

#3 Module "Constructor":

var module = function () {
  var name = "module 1";
  var setName = function( strName ) {
    name = strName;
  };
  var getName = function() {
    return name;
  };

  return {
    setName: setName,
    getName: getName
  };
};

var objModule1 = module();
var objModule2 = module();
objModule2.setName("module 2");

console.log(objModule1.getName()); // prints "module 1"
console.log(objModule2.getName()); // prints "module 2"

EDIT

If I use the module like a constructor (as suggested by @Matt Browne) and create 2 objects, the result is like using an object literal. What I'd like to understand is why does module example #1 behave differently than module example #3?

EDIT 2

As @ben336 explained, the code:

var objModule2 = Object.create(objModule); 

will set the objModule2's prototype to objModule. That doesn't happen in example #3, so those two objects don't share the same closure property.

like image 736
Rick Jolly Avatar asked Jan 13 '23 14:01

Rick Jolly


2 Answers

Example 1

The first argument of Object.create specifies the prototype object for the new object being created. Since in your first example you're setting your existing object to be the prototype of your new object, when you call the functions they're modifying the variable you've stored in a closure, which is then accessed by both your existing object and the new one.

The 2 key things to understand here are:

  1. This code

    var objModule = function () {
      var name = "module 1";
      var setName = function( strName ) {
        name = strName;
      };
      var getName = function() {
        return name;
      };
    
      return {
        setName: setName,
        getName: getName
      };
    }();
    

    creates a closure with the functions getName and setName holding access to the name variable.

  2. those functions are properties of objModule, and when you call Object.create you set objModule to be the prototype of objModule2, and it gains access to those functions as well.

Since the 2 objects share those functions, and they have access to the closure created by the module rather than storing the name property locally on either object, when you call the set function with one object, it will update the closure and thus update both objects.

Example 2

In the second example you're also setting the object to be the prototype of the new object, but you're declaring a property on the local object which overrides the property on the prototype.

like image 163
Ben McCormick Avatar answered Jan 16 '23 03:01

Ben McCormick


objModule2.setName refers to the same function as objModule.setName, but with a different this. (Object.create doesn't copy anything)
Calling it will set the same local variable.

objLiteral2.name = "literal 2" creates a new property on objLiteral2, which shadows the inherited objLiteral.name.

like image 32
SLaks Avatar answered Jan 16 '23 04:01

SLaks