15

I am struggling with a Javascript question for some time now and I was not able to find an explanation on the web. I guess it is because I do not enter the right keywords which might also be related to why I am struggling with this at all.

My basic assumption is that it is possible to alter objects:

> var x = {'n': 2};
> x['n']
2
> x['n'] = 3;
3

pheww that worked. But still (functions are objects, too):

> var addn = function(a) {
    var n = 2;
    return n + a;
}

> addn(3);
5
> addn['n'] = 3;
3
> addn(3);
5

This time I was not able to change 'n'. Is there a way to fix this while keeping the functional flavor? As opposed to going fully OO. A related question I have would be how to maintain dependencies of functions for the purpose of for example testing - again w/o going OO? Of cause I am looking for a solution but if possible I would also like to understand which mechanism in Javascript makes me struggling.

Cheers,

Mark

Disclaimer: By mentioning OO I do not intent to say anything against OO. And I do not intent to say anything against VI or Emacs either. If I somehow hurt your feelings please skip this one.

RobertPitt
  • 56,863
  • 21
  • 114
  • 161
moin moin
  • 2,263
  • 5
  • 32
  • 51

8 Answers8

17

Private variables in a function scope, and a property of an object are 2 very different things. var n inside that function is completely inaccessible from outside that function.

So after that code runs, addn.n == 3, but the different value set to var n is initialized every time the funciton runs. Due to the quirks of javascript, a function can't really access it own properties very easy. Instead this pattern would be better achieved by passing in an argument function(n, a)

Or use an object to achieve something similar.

var adder = {
  n: 0,
  addn: function(a) {
    return this.n + a;
  }
};

adder.n = 5;
adder.addn(2); // 7
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
9

If I understand your question correctly, you can give a name to your anonymous function and access the function object's properties through that:

var addn = function func(a) {
  return func.n + a;
};

addn['n'] = 3;
addn(3); // returns 6
casablanca
  • 69,683
  • 7
  • 133
  • 150
  • You can access a single property on an anonymous function without keeping a reference to it by enclosing it in parens, ie. `(function () { }).prototype` – Cory Gross Jul 27 '13 at 08:39
2

Object properties and local variables are largely unrelated:

  • var n declares a variable that is scoped to the function it's in (i.e. it is not visible outside of that function (except via closure)).

  • addn['n'] adds a property named n to addn and is equivalent to addn.n

Wayne
  • 59,728
  • 15
  • 131
  • 126
1

First, you are not changing the function variable by doing this:

addn['n'] = 3;

The function you defined does not have any name (also known as "anonymous function"). You are simply assigning that function to a variable called addn. A variable does not have any property- it is simply a container (Unless the variable refers to an array). So addn['n'] returns nothing.

As user casablanca noted, you can name your function as func and then access (and modify) its properties as func.<propertyname>.

bruhhhhh
  • 121
  • 5
1

Since JavaScript has function scope, you can use a function to store the value of n like so:

var addn = (function(n) {
  return function(x) {
    n += x;
    return n;
  }
}(2);

addn(3) // 5
addn(3) // 8
Allain Lalonde
  • 91,574
  • 70
  • 187
  • 238
1

It's best to forget completely about the traditional OO concept of "objects" in Javascript-land, and to think instead in terms of closures. I strongly recommend reading this tutorial by John Resig, the creator of jQuery.

Luke Dennis
  • 14,212
  • 17
  • 56
  • 69
  • from the tutorial you mentioned: ` var num = 10; function addNum(myNum){ return num + myNum; } num = 15; assert( addNum(5) == 20, "Add two numbers together, one from a closure." ); ` I think this is one approach but there is one thing I do not like about it is that 'num' is not part of the 'addn' object any more. – moin moin Mar 01 '11 at 18:21
1

Every function has a scope, basically where/how the function gets called. When a function gets called, it creates a new function execution context pushes it on the call stack; nothing in that context exists until that line/statement is read by the language, which won't happen until the function gets called.

What you were doing was assigning a value to the PROPERTY of the function, not accessing the variable n in that scope.

You cannot access an inner scope from an outer scope because the inner scope does not exist to the outer BUT you can access an outer scope from an inner scope because the outer scope exists to the inner scope.

Also, here is a bit of an FYI.

JavaScript is prototype based; not class based. EVERYTHING in JavaScript is an object, even functions. Read this to learn more about why that is (it's a good post on Quora) - https://www.quora.com/Why-is-function-an-object-in-Javascript

ryanwaite28
  • 1,804
  • 2
  • 24
  • 40
0

Basically, everything in Javascript is an object. If you said

var a=3;
a['n']=4;

references to 'a' would still return 3, but a also has a member 'n' which has value 4. So when you say addn['n'] = 3 you are adding a new member to addn, and not affecting the function in any way.

I strongly recommmend reading How good c habits can encourage bad javascript habits. In describing all the things you can do wrong, it's a great intro to the way objects work in Javascript.

Jamie Treworgy
  • 23,934
  • 8
  • 76
  • 119
  • why downvote: Not everything in JavaScript is an object. For example, in your own example, `a` is a "number" which is a "primitive" data type and is not an object. The reason you can add properties to it? Because JavaScript will create a temporary "Number" (wrapper class of "number") behind the scenes for you when you do `a['n']` and then disposes it as soon as that line is done. This can be useful for being able to use wrapper classes' methods on primitives, but that doesn't make primitives objects. See https://stackoverflow.com/a/56541867/9868445 & https://stackoverflow.com/a/9110389/9868445 – aderchox May 17 '21 at 06:27