0

I have an anonymous function expression encapsulated in a variable, and I want to encapsulate scoping at runtime, is this possible?

var humanWidth = 0;
var maleWidth = (function(){ return humanWidth; }());
humanWidth = 170;
alert(maleWidth);      // Should return 170, but returning 0 instead

Not sure if I am using the terminology correctly, please edit if necessary.

This is an example, humanWidth could be calculated way later and not defined when maleWidth is defined.

Bill Software Engineer
  • 7,362
  • 23
  • 91
  • 174
  • 1
    Put `humanWidth` before `maleWidth`. Your function gets executed instantly. `humanWidth` is not yet available. – putvande Dec 10 '14 at 21:30
  • Then it wouldn't be scoped at runtime, this is an example, but humanWidth could be way down the script and not defined when maleWidth is defined. – Bill Software Engineer Dec 10 '14 at 21:30
  • What do you mean by "*runtime*"? As opposed to what? And whose execution are you referring to? – Bergi Dec 10 '14 at 21:58
  • @Bergi, Runtime as in when maleWidth is called on line-3, as oppose to when maleWidth is defined on line-1, so what's the difference? On line-1 humanWidth has not been defined yet, not line-3 humanWidth has. – Bill Software Engineer Dec 10 '14 at 22:00
  • You are not *calling* `maleWidth` in line 3 (4), as it is not a function. You are *accessing* it, or *evaluating* the variable reference. The variable only stores a value, nothing more, which is `undefined` (`0`) as that is what was assigned to in line 1 (2) - the result of evaluating `(function(){ return humanWidth; }())` (== `humandwidth` == `undefined` (`0`), at the time of the assignment). – Bergi Dec 10 '14 at 22:37
  • I guess that's why I am asking if it's possible to do this. In C# you can do this with properties. – Bill Software Engineer Dec 10 '14 at 22:52
  • @YongkeBillYu: Javascript can do this with properties (object members) as well, but not with variables. – Bergi Dec 11 '14 at 01:00

2 Answers2

2

Move the function call () from the 1st to 3rd line:

var maleWidth = (function(){ return humanWidth; });
var humanWidth = 170;
alert(maleWidth()); 
Matt
  • 20,108
  • 1
  • 57
  • 70
  • That's neat! But can I use maleWidth as a variable? – Bill Software Engineer Dec 10 '14 at 21:32
  • 2
    OK, I tried it, it actually just return the function as string. – Bill Software Engineer Dec 10 '14 at 21:34
  • Maybe I don't understand your question. `maleWidth` is a variable that is set to a function. (Bottom line: copy and paste this code into your console and it gives the intended result.) – Matt Dec 10 '14 at 21:36
  • Op wants to call `maleWidth` instead of `maleWidth()` to invoke the function. – putvande Dec 10 '14 at 21:38
  • 1
    @YongkeBillYu I think I understand what you are asking. The only way to change the value of a variable is to change it. I know that sounds tautological, but if you want something dynamic, then that is what a function is for. What are the constraints of your problem where this solution isn't feasible? – Matt Dec 10 '14 at 21:48
  • Yes, you got what I am asking. It's actually not much of a problem but more of syntax sugar and code organization. I want to define humanWidth after maleWidth where maleWidth = humanWidth, and I was just wondering if this is possible to do. Or do I NEED to define humanWidth before maleWidth. – Bill Software Engineer Dec 10 '14 at 21:51
  • 1
    @YongkeBillYu Yes, you NEED to define humanWidth before maleWidth if you want maleWidth to be a simple string (instead of a function, for example). Otherwise JavaScript would be extremely difficult to debug if one could setup these kind of side-effects where changing one variable invisibly changes another... – Matt Dec 10 '14 at 21:54
1

In JavaScript primitive types, such as integers and strings, are passed by value, whereas objects are passed by reference. In order to achieve your desired functionality, you need to use property of an object:

var humanWidth = {value: 0};
var maleWidth = humanWidth;
humanWidth.value = 170;
alert(maleWidth.value);      // Returns 170!

Update: If you want to use anonymous function with an expression, not just an "alias" for the same value, try this:

var humanWidth = {value: 0};
var maleWidth =  new function() {
  Object.defineProperty(this, "value", {
    get: function() {
      return humanWidth.value * 2;
    }
  });
};
humanWidth.value = 170;
alert(maleWidth.value);      // Returns 340!

Update 2: Probably more elegant and less confusing solution (wihout new function()):

var data = {humanWidth: 0};
Object.defineProperty(data, "maleWidth", {
    get: function() {
      return this.humanWidth * 2;
    }
  }
);
data.humanWidth = 170;
alert(data.maleWidth);      // Returns 340!

Note that this time, unlike the previous two, both humanWidth and maleWidth are properties of one object (called data).

alutom
  • 221
  • 1
  • 4
  • [Please never use `new function(){…}`](http://stackoverflow.com/q/10406552/1048572). Just put `var maleWidth = Object.defineProperty({}, "value", {get:…})` – Bergi Dec 11 '14 at 00:59
  • @Bergi I see your point, `new function() {}` might be confusing. I added another solution without it. – alutom Dec 11 '14 at 01:29
  • Wow, this is actually really impressive, the defineProperty function is definitely the closest to what I wanted to achieve, and with a slight workaround using object, it is definitely doable. Thanks! – Bill Software Engineer Dec 11 '14 at 04:44