CuriousDeveloper
CuriousDeveloper

Reputation: 899

How to pass by reference or emulate it

I have two IFFE:

var Helper = (function () {
    return {
        number: null,
        init: function (num) {
            number = num;
        }
    }
})();

var Helper2 = (function () {
    return {
        options: {
            number: [],
        },
        init: function(num){
            this.options.number = num;
        },
        getData: function () {
            return this.options.number;
        }
  }
})();


Helper2.init(Helper.number);
console.log(Helper2.getData());
Helper.init(5);
console.log(Helper2.getData());

What I want is

Helper2.init(Helper.number);
console.log(Helper2.getData()); // null
Helper.init(5);
console.log(Helper2.getData()); // 5

what I get is

Helper2.init(Helper.number);
console.log(Helper2.getData()); // null
Helper.init(5);
console.log(Helper2.getData()); // null

What techniques can be done to have it pass by reference, if it can?

JSBIN: https://jsbin.com/gomakubeka/1/edit?js,console

Edit: Before tons of people start incorporating different ways to have Helper2 depend on Helper, the actual implementation of Helper is unknown and could have 100's of ways they implement the number, so Helper2 needs the memory address.

Edit 2: I suppose the path I was hoping to get some start on was knowing that arrays/objects do get passed by reference, how can I wrap this primitive type in such a way that I can use by reference

Upvotes: 0

Views: 69

Answers (3)

zero298
zero298

Reputation: 26909

I don't think you're going to be able to get exactly what you want. However, in one of your comments you said:

Unfortunately interfaces aren't something in javascript

That isn't exactly true. Yes, there's no strong typing and users of your code are free to disregard your suggestions entirely if you say that a function needs a specific type of object.

But, you can still create an interface of sorts that you want users to extend from in order to play nice with your own code. For example, you can tell users that they must extend from the Valuable class with provides a mechanism to access a value computed property which will be a Reference instance that can encapsulate a primitive (solving the problem of not being able to pass primitive by reference).

Since this uses computed properties, this also has the benefit of leveraging the .value notation. The thing is that the .value will be a Reference instead of the actual value.

// Intermediary class that can be passed around and hold primitives
class Reference {
  constructor(val) {
    this.val = val;
  }
}

// Interface that dictates "value"
class Valuable {
  constructor() {
    this._value = new Reference();
  }
  get value() {
    return this._value;
  }
  set value(v) {
    this._value.val = v;
  }
}

// "Concrete" class that implements the Valuable interface
class ValuableHelper extends Valuable {
  constructor() {
    super();
  }
}

// Class that will deal with a ValuableHelper
class Helper {
  constructor(n) {
    this.options = {
      number: n
    }
  }
  getData() {
    return this.options.number;
  }
  setData(n) {
    this.options.number = n;
  }
}

// Create our instances
const vh = new ValuableHelper(),
  hh = new Helper(vh.value);

// Do our stuff
console.log(hh.getData().val);
vh.value = 5;
console.log(hh.getData().val);
hh.setData(vh.value);
vh.value = 5;

Upvotes: 0

Cody Fortenberry
Cody Fortenberry

Reputation: 200

Passing by reference in JavaScript can only happen to objects. The only thing you can pass by value in JavaScript are primitive data types.

If on your first object you changed the "number:null" to be nested within an options object like it is in your second object then you can pass a reference of that object to the other object. The trick is if your needing pass by reference to use objects and not primitive data types. Instead nest the primitive data types inside objects and use the objects.

I altered you code a little bit but I think this works for what you were trying to achieve.

var Helper = function (num) { 
    return {
        options: {
            number: num
        },
        update: function (options) {
            this.options = options;
        }
    }
};

var Helper2 = function (num) {
    return {
        options: {
            number: num,
        },
        update: function(options){
            this.options = options;
        },
        getData: function () {
            return this.options.number;
        }
  }
};

var tempHelp = new Helper();
var tempHelp2 = new Helper2();
tempHelp2.update(tempHelp.options);
tempHelp.options.number = 5;
console.log(tempHelp2.getData());

Upvotes: 1

Mouser
Mouser

Reputation: 13304

First of all why doesn't it work:

helper is a self activating function that returns an object. When init is called upon it sets an number to the Helper object.

Then in Helper2 you pass an integer (Helper.number) to init setting the object to null. So you're not passing the reference to Helper.number. Only the value set to it.

You need to pass the whole object to it and read it out.

An example:

var Helper = (function () {
    return {
        number: null,
        init: function (num) {
            this.number = num; //add this
        }
    }
})();

var Helper2 = (function () {
    return {
        options: {
            number: [],
        },
        init: function(obj){
            
            this.options = obj; //save a reference to the helper obj.
        },
        getData: function () {
            if (this.options.number)
            {
                return this.options.number;
            }
        }
  }
})();


Helper2.init(Helper);  //store the helper object
console.log(Helper2.getData());
Helper.init(5);
console.log(Helper2.getData());

Upvotes: 0

Related Questions