Scope problem nesting Javascript Objects - javascript

I am writing some Javascript code using jQuery to display specially formatted widgets in a browser. I've had success, but now I'm working on refactoring my code for two reasons.
(1) I wish to be able to easily use the widget more than once and have a Javascript object referring to each one.
(2) I wish to do it the right way so that my code is totally reusable and doesn't little the global namespace with all sorts of objects and functions.
I'm having a scoping problem and I wish to fix the problem and improve my understanding of Javascript scope. I've condensed this problem down to a tiny code snippet that illustrates what I'm doing:
function getMyObject() {
var theObject = {
doThis: function () { },
doThat: function () { },
combinations: {
doThisTwice: function () { doThis(); doThis(); },
doThatTwice: function () { doThat(); doThat(); }
}
};
return theObject;
}
var myObject = getMyObject();
myObject.combinations.doThisTwice();
I've declared a function that returns an object.
However, when I try to execute the function combinations.doThisTwice(), the program throws an error saying that doThis() is out of scope. How do I refer to the function doThis in the scope of combinations.doThisTwice?
Update: Thank you kindly for the answer to my question: Replace doThis() with theObject.doThis() inside the function doThisTwice(). This works, but I don't understand why.
I would have thought that the name theObject would not be valid until the end of the object declaration. I think I must misunderstand some fundamental aspect of Javascript... probably because of the C-like syntax.

You need to do:
function getMyObject() {
var theObject = {
doThis: function () { },
doThat: function () { },
combinations: {
doThisTwice: function () { theObject.doThis(); theObject.doThis(); },
doThatTwice: function () { theObject.doThat(); theObject.doThat(); }
}
};
return theObject;
}
var myObject = getMyObject();
myObject.combinations.doThisTwice();
You reference 'theObject' from an outer scope to call the functions in an inner object.

doThis is not defined in the functions scope, so it will traverse up the scope chain, but not find it.
You can reference it by
theObject.doThis();
However, more readable might be if you define your function like this:
function getMyObject() {
function doThis() {};
function doThat() {};
var theObject = {
doThis: doThis,
doThat: doThat,
combinations: {
doThisTwice: function () { doThis(); doThis(); },
doThatTwice: function () { doThat(); doThat(); }
}
};
return theObject;
}
But in this case, whenever you change doThis from the outside, doThisTwice will still reference the original function.

In doThisTwice, use theObject.doThis(); instead of doThis();

Related

Javascript function & nested functions

Purpose: I need to call sub function within main one;
Function declaration:
var MainFunction = function () {
function NestedFunc1(){
console.warn("NestedFunc1");
};
function NestedFunc2(){
console.warn("NestedFunc2");
};
}
Functions call:
MainFunction.NestedFunc1();
MainFunction.NestedFunc2();
What am I doing wrong?
10x;
you can make it public via a property then
function MainFunction () {
this.nestedFunc1 = function(){
console.warn("NestedFunc1");
};
this.nestedFunc2 = function(){
console.warn("NestedFunc2");
};
}
now you can invoke this function outside by doing
var malObj = new MainFunction();
malObj.nestedFunc1();
However, if you want to still invoke it like MainFunction.NestedFunc1() then make it
var MainFunction = {
NestedFunc1:function (){
console.warn("NestedFunc1");
},
NestedFunc2:function (){
console.warn("NestedFunc2");
}
}
The issue is that both of those functions are isolated within a function scope. Think of them as private functions.
One (of many) solutions could be to define MainFunction as a plain ol' object that has some functions as attributes:
var MainFunction = {
NestedFunction1: function () { .. },
NestedFunction2: function () { .. }
};
Notice that a comma is needed to separate the functions because of the way we are defining them. You then just call
MainFunction.NestedFunction1();
Also note that this pattern is fine as long as you don't wish to have other "private" functions inside that object.

Javascript function undefined?

I am fairly new to javascript and jquery. I thought i had learned enough to do this, but apparently not. I think the code is fairly self explanatory.
The problem is that ArrowDir is apparently undefined. It looks defined to me, but I'm sure I'm missing something obvious.
function ArrowDir(){
var up = function(){
$("#arrow").attr('src','up_arrow.jpg');
};
var down = function(){
$("#arrow").attr('src','down_arrow.jpg');
};
}
$(function () {
if($("#toggle").onclick){
ArrowDir().down();
};
});
I've tried assigning the function as a variable, var ArrowDir = function(), but it doesn't seem to make a difference
You can't access the up and down values in the manner that you've written. You'd need to simply call down() from within the ArrowDir body, unless you've added those functions to the ArrowDir return value:
ArrowDir() {
var up = ...;
var down = ...;
return {
up: up,
down: down
};
}
Alternatively, if you're not using ArrowDir for anything other than encapsulating the up and down functions, you should just declare ArrowDir as an object, and call ArrowDir.up() and ArrowDir.down():
var ArrowDir = {
up: function () {
...
},
down: function () {
...
}
}
Assuming the missing quote after "#toggle is a typo, I'm not sure how you expect your code to work.
Here's how it runs, in prose:
Define a function ArrowDir.
When ready, attach a click handler
When clicked, call ArrowDir
In ArrowDir, define two local variables up and down, each with a function to do something.
There is no return statement, so return nothing
Call the down method of the "nothing" object. ERROR
See?
Try adding return {up:up,down:down}; to the end of your ArrowDir function.
You can create the object this way. In your function you are creating them insdied the scope of itself. SO it is not accessible outside.
function ArrowDir() {
}
ArrowDir.prototype.up = function () {
$("#arrow").attr('src', 'up_arrow.jpg');
};
ArrowDir.prototype.down = function () {
$("#arrow").attr('src', 'down_arrow.jpg');
}
and access it as
$(function () {
if($("#toggle").onclick){
var arrow = new ArrowDir(); // call the constructor to create a new instance
arrow.down(); // invoke the method
};
});
ArrowDir().down() here's your problem. Just because you define a variable in the ArrowDir function doesn't make it a method/property of it. You have to use Prototype Inheritance.
EDIT:
//Something like this:
ArrowDir.prototype.down = function() {
//Do stuff
}
Now you can call ArrowDir.down().
Doing this extends the properties (things it can do) of the object ArrowDir. You're adding a method to it.
The var up and down you have defined inside ArrowDir are not accessible outside the scope of that function.
The simplest way you could fix this, if this is a one-time kind of function, is just to put the up/down behavior in your jQuery function, like this:
$(function () {
if($("#toggle").onclick){
$("#arrow").attr('src','up_arrow.jpg');
} else {
$("#arrow").attr('src','down_arrow.jpg');
}
});
If you just want to namespace these functions for reusability you could make an object literal instead:
ArrowDir = {
up: function(){
$("#arrow").attr('src','up_arrow.jpg');
},
down: function(){
$("#arrow").attr('src','down_arrow.jpg');
}
};
Then you can call: ArrowDir.up() or ArrowDir.down() elsewhere.
For what it's worth, if your goal is just to namespace these functions for reusability, I would say the object literal syntax makes more sense to me.
Or, if you really want to do it as a function call, as Kolink has pointed out, the up/down functions need to be in the return value. You could write that like this...
function ArrowDir() {
var up = function(){
$("#arrow").attr('src','up_arrow.jpg');
}
var down = function(){
$("#arrow").attr('src','down_arrow.jpg');
}
return {up:up,down:down};
}
Or like this...
function ArrowDir() {
return {
up: function(){
$("#arrow").attr('src','up_arrow.jpg');
},
down: function(){
$("#arrow").attr('src','down_arrow.jpg');
}
};
}
Now calling ArrowDir().down() should work.

JavaScript: How do use instance variables

why doesn't this work as expected. (see expected comment)
var Module = function () {
var public_instance_var;
function doStuff () {
Module.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
}
}();
Module.doStuff();
Update: Fixed accordingly to a few of jAndy suggestions
Multiple errors here:
You don't return DoStuff as module interface
instance_var is not declared, probably meant public_instance_var
doOtherStuff is never assigned to Module, just call it like doOtherStuff();
Fixed code:
var Module = function () {
var public_instance_var;
function doStuff() {
doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
doStuff: doStuff,
public_instance_var: public_instance_var
}
}();
Module.doStuff();
change your code like so
var Module = function () {
var public_instance_var;
function doStuff () {
doOtherStuff();
console.log("var is ", public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff : doStuff
}
}();
Module.doStuff();
you have to return doStuff() function (otherwise outside it will be undefined) and public_instance_var instead of instance_var
you need to execute doOtherStuff() without prefixing Module.
What this code does is, simply put: create and run a function and assign its return value to a variable: Module. The return value is an object with 1 property: public_instance_var, that points to the variable instance_var, or (after correcting the typo: public_instance_var). This variable was declared, but not instantiated. Therefore the return value looks like this:
Module.public_instance_var = undefined
The very last line Module.doStuff(); won't work one bit: Module is an object that has no methods. The functions you declared are garbage collected when the anonymous function returns. If you want access to those functions, you'll need to include them in the return statement. Read up on closures, Object constructors and design patterns in general, but I'd say the code you're after will look something like this:
var Module = (function()
var public_instance_var;
function doStuff () {
this.doOtherStuff();
console.log(public_instance_var); // expected: true, but logs undefined
};
function doOtherStuff() {
public_instance_var = true;
};
return {
public_instance_var: public_instance_var,
doStuff: doStuff,
doOtherStuff: doOtherStuff
};
})();
Of course, this way your variable public_instance_var is a public property, so my guess would be what you're really trying to do is simulate a private properties and methods. In which case you might end up with code similar to this:
var Module = (function()
{
var public_instance_var;
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
this.doOtherStuff();//this, you're referencing the object's property
console.log('here I am');
},
doOtherStuff: function ()
{
public_instance_var = true;
//this won't work anymore:
//this.public_instance_var = true;
};
}
})();
Module.doStuff() now logs here I am, but the doOtherStuff is now a public method, too. Here's how you might choose to solve the issue:
var Module = (function()
{
var public_instance_var;
function doOtherStuff ()
{
public_instance_var = true;
};
return {
//public_instance_var: public_instance_var, remove this line
//the closure will preserve access to the variable
doStuff: function ()
{
doOtherStuff();//don't use this here, but the reference to the function exists thanks to closure
console.log('here I am');
console.log(public_instance_var);//logs true
}
};
})();
These are just a few of the very powerful things you can do with closures and functions returning objects. Just read a couple of articles, like this one, there are better ones out there. Google the term power constructors

Difference between two JavaScript object types

I see objects in JavaScript organized most commonly in the below two fashions. Could someone please explain the difference and the benefits between the two? Are there cases where one is more appropriate to the other?
Really appreciate any clarification. Thanks a lot!
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {}
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
})();
Second:
SomeObject = function() {
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
}
Both of those examples are incorrect. I think you meant:
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
return SomeObject;
})();
(Note the return at the end of the anonymous function, the use of = rather than :, and the semicolons to complete the function assignments.)
Or possibly you meant:
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
(No anonymous enclosing function.)
Second:
function SomeObject() {
}
SomeObject.prototype = {
doSomething: function() {
},
doSomethingElse: function() {
}
};
(Note that the assignment to the prototype is outside the SomeObject function; here, we use : because we're inside an object initializer. And again we have the ; at the end to complete the assignment statement.)
If I'm correct, there's very little difference between them. Both of them create a SomeObject constructor function and add anonymous functions to its prototype. The second version replaces the SomeObject constructor function's prototype with a completely new object (which I do not recommend), where the first one just augments the prototype that the SomeObject constructor function already has.
A more useful form is this:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = doSomething;
function doSomething() {
}
SomeObject.prototype.doSomethingElse = doSomethingElse;
function doSomethingElse()
}
return SomeObject;
})();
There, the functions we assign to doSomething and doSomethingElse have names, which is useful when you're walking through code in a debugger (they're shown in call stacks, lists of breakpoints, etc.). The anonymous function wrapping everything is there so that the doSomething and doSomethingElse names don't pollute the enclosing namespace. More: Anonymouses anonymous
Some of us take it further:
var SomeObject;
SomeObject = (function() {
var p = SomeObject.prototype;
function SomeObject() {
}
p.doSomething = SomeObject$doSomething;
function SomeObject$doSomething() {
}
p.doSomethingElse = SomeObject$doSomethingElse;
function SomeObject$doSomethingElse()
}
return SomeObject;
})();
...so that not only do we see doSomething, but SomeObject$doSomething in the lists. Sometimes that can get in the way, though, it's a style choice. (Also note I used the anonymous function to enclose an alias for SomeObject.prototype, to make for less typing.)
First off, both snippets will not parse for me (Chrome) - you should use = in place of :. That said, my humble opinion follows.
The latter snippet is slightly strange, because you actually define methods on SomeObject's prototype at the time of the object construction, rather than at the parse time. Thus, if you have re-defined some method on SomeObject.prototype, it will get reverted to the original version once a new object is constructed. This may result in unexpected behavior for existing objects of this type.
The former one looks fine, except that the (function { ...} ())() wrapper may not be necessary. You can declare just:
function SomeObject() {}
SomeObject.prototype.doSomething = function() {}
SomeObject.prototype.doSomethingElse = function() {}
The actual difference between first and second in your questions is just:
var o = (function () {})(); # call this (A)
and
var o = function () {}; # call this (B)
Unfortunately, neither of the examples that you gave are written correctly and, while I don't think either will actually give an error at parse-time, both will break in interesting ways when you try to do things with the result.
To give you an answer about the difference between (A) and (B), (A) is the immediate function application pattern. The JavaScript Patterns book has a good discussion, which I recommend.
The actual problems in your code have been explained by other people while I was writing this. In particular T.J. Crowder points out important things.

When to use anonymous JavaScript functions?

I'm trying to understand when to use anonymous JavaScript functions.
State differences between the functions? Explain when you would use each.
var test1 = function(){
$("<div />").html("test1").appendTo(body)
};
function test2() {
$("<div />").html("test2").appendTo(body)
}
I think the answer is that one uses anonymous function and the other doesn't to replace an empty div element. Does that seem right?
In your example it really doesn't make a huge difference. The only difference is that functions declared using function foo() { } are accessible anywhere within the same scope at any time, while functions declared using var foo = function () { } are only accessible after the code that does the assignment has run.
foo(); // ok
function foo() { ... };
bar(); // error, bar is not a function
var bar = function () { ... };
bar(); // ok
You usually use anonymous functions in cases where you don't need a named function, or where you're constructing objects:
arr.sort(function (a, b) { return a - b; }); // anonymous callback function
function MyObject() {
this.foo = function () { ... } // object constructor
}
You would use a function like the following (which is another type of anonymous function) when you do not want to pollute the global namespace:
(function() {
var pollution = 'blablabla';
function stinky() {
// Some code
}
})();
You may check John Resig's Secrets of JavaScript Libraries, especially page 47 for JavaScript function. Quite lengthy, but you'll learn more about JavaScript

Categories

Resources