0
var steve = function() {
  var bob = {};
  bob.WayCoolTest = function () {console.log('done deal');};
  return bob;
}
window["steve"]["WayCoolTest"]

running this in chrome console, my test app, anywhere results with undefined. I do not understand why, can someone explain why this does not work and help me fix it. Thank you very much!!

2
  • you can't access function local variables from the outside Commented Nov 14, 2013 at 22:17
  • I was on my phone earlier when I answered. I updated my answer - kinda wrote a book, lol. It should give you a lot of insight. Commented Nov 14, 2013 at 23:42

4 Answers 4

4

Using window is usually redundant - let me demonstrate:

var foo = '123';

alert(foo); //123
alert(window.foo) //123
alert(window['foo']) //123

It is evident which is more convenient. There is a circumstance in which the use of window makes sense, but that circumstance is almost always because of poor architecture. Using window allows us to access a variable global variable - funny wording :) This should clear it up:

var foo = '123';
var bar = 'abc';

var prop;
if (blah) { //some condition here
  prop = 'foo';
}
else {
  prop = 'bar';
}

Now...how can we use prop to get the value of a corresponding variable?

console.log(window[prop]); //123 or abc - bracket notation lets us use variable property names

This sort of thing is very common within objects, but not with window. The reason is that we should be avoiding global variables (properties of window) as much as possible. Therefore, any logic that needs a variable property name should be inside of an object, dealing with objects - NOT window. Now window can be out of the picture.

It is usually bad practice to create functions inside of other functions. That would mean that each time you call function A, you recreate function B. Most of the time, people do that because they don't know better, not because they need to.

It appears to me that you intended to give steve a property called WayCoolTest, both being functions. That can be done.

var steve = function() {
  console.log("I'm Steve!");
}
steve.WayCoolTest = function() {
  console.log("I'm a Way Cool Test!");
}

steve(); //I'm Steve!
steve.WayCoolTest(); //I'm a Way Cool Test!

This works because functions are objects in javascript. Therefore, you can add properties to them.

Let's step it up!
To emphasize good practices, I'm going to wrap this example in an object testApp (it acts like a namespace..we're using that instead of window).
I will create a property of testApp called steve, which will be a function. Rather than creating steve directly as a function, I will use an IIFE (immediately invoked function expression), which is a function that will return something to be set as steve.
Inside the IIFE, I will create the function for steve and also attach WayCoolTest to it, as demonstrated in the previous example, then that function is returned and assigned to steve.

var testApp = {
  steve : (function() {
    var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
      console.log("I'm Steve!");
    }
    steve.WayCoolTest = function() {
      console.log("I'm a Way Cool Test!");
    }
    return steve;
  }());
};

testApp.steve(); //I'm Steve;
testApp.steve.WayCoolTest(); //I'm a Way Cool Test!

Now, let's consider another variation.

var testApp = {
  steve : (function() {
    var steve = function() { //the name here doesn't matter, just being consistent, since this will be the value of the property `steve`.
      console.log("I'm Steve!");
      WayCoolTest(); //Steve can use this, but nothing else can! Encapsulation.
    }
    var WayCoolTest = function() { //THIS PART!! No longer a property of "steve"
      console.log("I'm a Way Cool Test!");
    }
    return steve;
  }());
};

testApp.steve(); //I'm Steve! I'm a Way Cool Test
testApp.steve.WayCoolTest(); //undefined, of course

That is very useful if for example steve is a complicated function and you want to break it up into some other small functions that only steve will know about.

Sign up to request clarification or add additional context in comments.

Comments

1

To complement the other answers, your code would work this way:

var steve = function() {
    var bob = {};
    bob.WayCoolTest = function () {console.log('done deal');};
    return bob;
}
window["steve"]()["WayCoolTest"]();

or

var steve = (function() {
    var bob = {};
    bob.WayCoolTest = function () {console.log('done deal');};
    return bob;
})();
window["steve"]["WayCoolTest"]();

or, the dirtiest way...

steve=(function() {
    var bob = {};
    bob.__defineGetter__("WayCoolTest", function () {console.log('done deal');});
    return bob;
})();
window["steve"]["WayCoolTest"];

4 Comments

the first way you mentioned, why would it work that way with the parens at the end?
@gh9 It is a function you need to invoke it to get the object set in bob, other wise it will just give you the function reference, you need invocation and (a return inside the function give the object of your interest)
the two pairs of parens are needed because of this: the first one invokes the steve function (which is referenced by a global variable), the second one invokes the WayCoolTest function, which is an item of the object returned by the steve function. You have two functions, and have to call both.
As @PSL said, if you have a variable which holds a reference to a function, you will need the parens syntax to invoke this function. If you don't use parens, you'll be accessing only a reference to this function, not calling it.
1

Assuming steve is in the global scope and you dont seem to use steve as a constructor you can use immediate function and return the new object that you have created inside of it.

var steve = (function () {
    var bob = {};
    bob.WayCoolTest = function () {
        console.log('done deal');
    };
    return bob;
})();

window["steve"]["WayCoolTest"]();

If it is in a closure then you would have to either remove var for hoisting to happen so it becomes a part of window or set it to the window object as a property.

  window.steve = (function () {
        var bob = {};
        bob.WayCoolTest = function () {
            console.log('done deal');
        };
        return bob;
    })();

2 Comments

cool that worked, why did the parenthesis at the end do the trick?
@gh9 It immediately invokes the function as you don't seem to need it as a constructor, i used Immediate function.
1

If you declare using var it doesn't get associated with the global window scope. It's instead a local variable. Also bob is not a property on the steve object they way you have it set up

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.