Javascript function undefined? - javascript

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.

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.

prototype on single instances of functions

If I know that I only will create one instance of the MyClass function below, which of my two snippets below would you prefer? Should I stick with the latter, even though I know that I'll only create one instance of the function?
I know that prototype is useful from a performance perspective when sharing methods across all instances of a function, but in this case I would like to hear your input.
var MyClass = (function () {
var cls = function () { };
cls.prototype = {
init: function(data){
}
};
return cls;
})();
vs
var MyClass = (function () {
var cls = function () {
this.init = function(data){
}
};
return cls;
})();
Your second code snippet is a syntax error, you're trying to put a property initializer where a statement is expected. (Not anymore)
If you're only going to have a single object that you need the init function on, then:
var MyObject = {
init: function(data) {
// ...
}
};
Then you don't even need to call a function to create it, it's already there.
If you want to have truly private variables and such (which I assume is the reason for your outer anonymous functions), then:
var MyObject = (function() {
var trulyPrivateDataHere;
return {
init: function(data) {
// ...
}
};
})();
I prefer this because it's clear and direct: You're creating the actual object. I don't see any need for a constructor function if you're only ever going to create a single instance.
But if it has to be a constructor function, I guess I'd very marginally prefer your second option, because it's simpler, and simple is good barring the need for complexity.

javascript: passing as object or function

My question is rather weird, it has to do with something i have seen in jQuery but so far i have been unable to recreate it.
in jQuery you can go like this
jQuery('div').append
or
jQuery.ajax
the application i am making would need a similar syntax, i notice if you use new like
var that=new function(){
}
you can call the function with just that, without the (), but in some cases i would need it.
The reason for this is some functions i have need to select a dom element just like jQuery so.
that('[data-something="this"]').setEvent('click',functin(){})
and some automatically do it so:
that.loadIt('this','[data-something="that"]')
the reason for this is that the dom elements are loaded externally and pushed, then the script waits for it to be ready before continuing. and doing it this way, to me anyway seems like the most cleanest way to get this functionality (i am coding a full javascript framework so i avoid libraries to keep the scripts fast)
Functions are objects.
Just get rid of new, and add properties directly to that.
var that = function() {
// do some work
}
that.loadit = function() {
// do other work
}
Since you're trying to achieve something like jQuery does, then have that call a constructor.
;(function(global) {
// function to be publicly exposed
var that = function(foo, bar) {
return new MyLibrary(foo, bar);
}
// publicly expose the function
global.that = that;
// use the function as a namespace for utilities
that.loadit = function() {
// do other work
}
// The actual constructor function, like the internal jQuery constructor
MyLibrary(foo, bar) {
// constructor function
}
// Prototypal inheritance of objects created from the constructor
MyLibrary.prototype.setEvent = function() {
// do some work
return this; // allows for method chaining
};
MyLibrary.prototype.otherMethod = function() {
// do something else
return this; // allows for method chaining
};
})(this);
Functions are objects and can have properties, just like other objects can. So, you can add a property to a function like this:
function myFunc(){}
myFunc.someFunc = function(){}
If you use new myFunc the resulting object won't have someFunc as it's not part of the prototype.
So, you can make something like this:
function myFunc(){
// This lets you do "myFunc()" instead of "new myFunc()"
if (!(this instanceof myFunc)) {
return new myFunc();
}
else{
this.val = 0;
this.setVal = function(x){
this.val = x;
// for function chaining
return this;
}
this.getVal = function(){
return this.val;
}
}
}
// This function is not part of the prototype
myFunc.test = function(){
alert('hi');
}
// Some tests
var obj = myFunc();
obj.setVal(12).getVal(); // 12
myFunc.test();
obj.test(); // Error: 'test' is not a function
myFunc.getVal(); // Error: 'getVal' is not a function
$.fn.loadIt=function(var1,var2) {
// $(this) is automatically passed
// do stuff
}
call it like this
$('#element').loadIt('a variable','another variable');

Scope problem nesting Javascript Objects

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();

Accessing this from within an object's inline function

I'm having difficulty referencing "this" from within a javascript inline function, within an object method.
var testObject = {
oThis : this,
testVariable : "somestring",
init : function(){
console.log(this.testVariable); // outputs testVariable as expected
this.testObject.submit(function(){
var anotherThis = this;
console.log(this.testVariable) // undefined
console.log(oThis.testVariable) // undefined
console.log(testObject.testVariable) // outputs testVariable
console.log(anotherThis.testVariable) // undefined
}
}
How do I access this.testVariable from within the submit function?
I'm also using jQuery as well, if that makes a difference.
I wonder if this is the best approach - and maybe I should have submit as a separate function, and then reference that inline, like:
init : function(){
this.testObject.submit = this.submitForm;
},
submitForm : function(){
// do validation here
console.log(this.testVariable) // outputs testvariable
.
.
.
return valid;
}
But this didn't seem to work either - and I think I'd just like to keep the submit function inline within my init method for now.
A common way is to assign the this you want to a local variable.
init: function() {
var _this = this;
this.testObject.submit(function() {
console.log(_this.testVariable); // outputs testVariable
});
}
You could also do this using ES6 arrow functions:
init: function(){
this.testObject.submit( () => {
console.log(this.testVariable);
}
}
Arrow functions capture the this value of the enclosing context, avoiding the need to assign this to a new variable, or to use bound functions.
The "this" variable is bound dynamically when a function — any function, regardless of where it was defined — is called.
Without seeing what that "submit" function is supposed to do, or where it's supposed to be used, it's hard to say how to change it. One thing you could do is to define "submit" in your "init" function:
init: function() {
// whatever
var instance = this;
instance.submitForm = function() {
console.log(instance.testVariable);
// ...
};
}
As long as "init" is called initially with "this" set to an instance of one of your objects, you should be good.
You can only access the oThis variable from the context of the object, which is lost because you are inside of another function. or through instantiating a new object. like this
var testInstance = new testObject();
Then you could access oThis by using:
testInstance.oThis;
but that would be redundant
I would try something like this Matt:
init: function(){
var self = this; // this allows you to access the parent object from different contexts
this.testObject.submit(function(){
console.log(self.testVariable);
}
A possible answer is to use arrow functions and pass in the object that "this" should refer to...
function create() {
var thing = { name: "thingy" };
thing.doStuff = function() {
alert(this.name);
}
thing.doStuff(thing);
}
The reason this works is arrow functions automatically have a final thisArg optional parameter which is bound to this.

Categories

Resources