Sajjan Sarkar
Sajjan Sarkar

Reputation: 4198

jQuery Extend copying over previous closures

Description

In my example I am trying to define a simple class (called Car) with a private member and a public getter. I also have another object that I would like to to map into an instance of my class. I am using jQuery.extend() to achieve this and it works well except if the member is private (not tied to this). I am guessing this is because the getter function has closed over the values defined at the object creation time.

I would still like to be able to re-close the function over the member after the .extend() so it will reflect the new value, can any one help me achieve this?

I have also tried extending the passed in reference to a {} object and then using that blank object as the target like so:

function mapToObject(template, json) {
    var b = $.extend(true,{}, template);
  return $.extend(true, b, json);
}

This also doesnt break the previous closure.

My code:

// simple class with private member
function Car() {
  var noOfWheels = 2;
  this.honk = function() {
    alert(noOfWheels);
  }
}
// method which converts JSON object to a more typed class object
function mapToObject(template, json) {
  return $.extend(true, template, json);
}

// sample Object , in reality coming from AJAX response
var t = {
  noOfWheels: 5
};
// i want to map t to an instance of Car
var r = mapToObject(new Car, t);// closing here during new Car, i think
r.honk(); // this alerts 2 not 5 because of closure!

Fiddle:

https://jsfiddle.net/sajjansarkar/samj3pjq/2/

[EDIT]My Solution based on DrFlink's answer:

// one class
function Car(options) {
  var settings = $.extend({
    noOfWheels: 2
  }, options || {});
  this.honk = function() {
    alert(settings.noOfWheels);
  }
}
// another class
function Lemon(options) {
  var settings = $.extend({
    color: null
  }, options || {});
  this.getColor = function() {
    alert(settings.color);
  }
}
// function to map any json to a template class instance
function ObjectMapperFactory(template, json) {
  if (!jQuery.isArray(json)) {
    return new template(json);
  } else {
    var returnArray = [];
    $(json).each(function() {
      returnArray.push(new template(this))
    });
    return returnArray;
  }
}

//test 1
var carJSON = {
  noOfWheels: 5
};
var c = ObjectMapperFactory(Car, carJSON);
c.honk();
//test2 -different class and also testing array
var lemonJSON = [{
  color: "yeller"
},{
  color: "red"
}];

var c = ObjectMapperFactory(Lemon, lemonJSON);
c[0].getColor();
c[1].getColor();

UPDATED FIDDLE:

https://jsfiddle.net/sajjansarkar/samj3pjq/3/

Upvotes: 0

Views: 95

Answers (1)

Dr.Flink
Dr.Flink

Reputation: 572

Why do you want to do it that way? Perhaps this will be simpler:

// simple class with private member
var Car = function(options) {
  var settings = $.extend({
    noOfWheels: 2
  }, options || {});

  // Public method - can be called from client code
  this.honk = function(){
    alert(settings.noOfWheels);
  };

  // Private method - can only be called from within this object
  var myPrivateMethod = function(){
    alert('This is private!');
  };
};

// sample Object
var t = {
  noOfWheels: 4
};

var I = new Car(t);
var J = new Car({
  noOfWheels: 6
});

I.honk();
J.honk();

Upvotes: 1

Related Questions