Pierre Smith
Pierre Smith

Reputation: 465

prototype vars not being overwritten by constructor

I'm trying to allow for default settings to be overwritten by the init function but for some reason the it's only using the local settings can anyone please explain why and how I can fix this.

var obj = (function() {
  var settings = {
    height : 10,
    width : 20
  };

  function init(settings) {
    this.settings = settings
    setObj()
  }

  function setObj() {
    if (settings.height == 0) {
      console.log('good height')
    } else {
      console.log('bad height')
    }
  }
  return {
    init : init,
  }
})()

var settings = {
    height : 0,
    width : 20
  };
obj.init(settings);

Upvotes: 2

Views: 92

Answers (3)

Antonio Pavicevac-Ortiz
Antonio Pavicevac-Ortiz

Reputation: 7729

I am uncertain as to what you are trying to do, however your question is a great example to help people understand modules and the revealing module pattern.

At present when you execute the IIFE the only value it returns to your obj variable/Module is an anonymous object with a method which is init.

return {  // <-- anonymous object returned with all its properties available!
    init : init 
}

So the methods bound to that returned object are now available to the module's namespace i.e. obj. Everything else is private i.e. var settings (object), the setObj, (function object)

Think what might be confusing is this part:

function init(settings) {
    this.settings = settings
    setObj()
} 

When you call init this will add a new property to obj Module. That is because when you invoke:

obj.init(settings);

The thiskeyword points to the returned object which was assigned to the obj namespace/Module.

To prove it after invoking the IFFE but before invoking initon your Module, run:

console.dir(obj);

Calling console.dir(object) will log an interactive listing of an object's properties, like > a miniature version of the DOM tab

Essentially you'll get all the properties on obj. At this point it's only init.

So to reiterate, your init will not overwrite the settings variable, the one in the IIFE assigned to obj, that one is inaccessible (unless you use a public method to update it). Your init adds a property to the object returned by the IIFE.

I added a function to your Module called checkSettings and changed your init function. I created checkSettings so you could see the settings obj before you run init and after, essentially so you could see the changes first hand. And my init just overwrites the properties if the names match.

var obj = (function() {

  var settings = {
      height : 10,
      width : 20
  };

  function init(objProps) {
      for (var p in objProps) {
          if(settings.hasOwnProperty(p)) {
              settings[p] = objProps[p];
          }
      }
      setObj()
   }

  function checkSettings(){
     console.log('The following properties and values are on settings object');     

     for(var p in settings) {
        if(settings.hasOwnProperty(p)) {
          console.log(p + ' ' + settings[p]); 
        }
     }
  }

  function setObj() {
    if (settings.height == 0) {
      console.log('good height')
    } else {
      console.log('bad height')
    }
  }
  return {
    init : init,
    checkSettings : checkSettings
  }
})()

Hope this was helpful!

Upvotes: 0

Rafique Ahmed
Rafique Ahmed

Reputation: 117

The init function is a closure here, even after IIFE executes , init has reference to local variable. So first it checks whether height property of settings object is available locally and grabs the value. But when we use this keyword is used it refers to settings of init function which has the reference to global settings object. Please correct me if I am wrong.

  var obj = (function() {
  var settings = {
    height : 10,
    width : 20
  };

  function init(settings) {
    this.settings = settings;

    setObj();
  }

  function setObj() {
    if (this.settings.height == 0) {  // use this.settings here. The code works fine.
      console.log('good height')
    } else {
      console.log('bad height')
    }
  }
  return {
    init : init,
  }
})();

var settings = {
    height : 0,
    width : 20
  };


obj.init(settings);

Upvotes: 0

Akshay
Akshay

Reputation: 805

instead of var use this.settings

var obj = (function() {
  this.settings = {
    height : 10,
    width : 20
  };

  function init(settings) {
    this.settings = settings
    setObj()
  }

  function setObj() {
    if (settings.height == 0) {
      console.log('good height')
    } else {
      console.log('bad height')
    }
  }
  return {
    init : init,
  }
})()

var settings = {
    height : 0,
    width : 20
  };
obj.init(settings);

Upvotes: 1

Related Questions