why can't i call one method from another inside an object - javascript

pardon my javascript ignorance: Why can't i do something like this in javascript? Running this tells me that theCalled is not defined. the order of the functions doesn't matter of course.
var myObj = {
theCaller: function() {
console.log('The Caller');
theCalled();
},
theCalled: function() {
console.log("i was called");
}
}
myObj.theCaller();

Add "this" before you call .theCalled()
var myObj = {
theCaller: function() {
alert('The Caller');
this.theCalled();
},
theCalled: function() {
alert("i was called");
}
}
myObj.theCaller();

Related

Calling a function in another function with AngularJS factory

I have an AngularJS factory that has multiple functions.
I want to call one of the functions inside the other function as shown below:
.factory("AppStart", function($cordovaSQLite) {
return {
init: function() {
var res = "hello";
console.log("in load start up page");
},
create_table: function() {
AppStart.init();
}
}
});
But I get the following error:
AppStart is not defined.
So how do I call the init() function in the create_table() function? I have tried just calling init(), but it doesn't work either.
To accomplish this, I recommend defining your functions with names, and then creating a service object with properties that refer to them, as I did below:
.factory("AppStart", function($cordovaSQLite) {
function init() {
var res = "hello";
console.log("in load start up page");
}
function create_table() {
init();
}
return {
init: init,
create_table: create_table
};
});

javascript variable scope in callbacks

I'm curious how could this be written better:
function Klass(variable) {
this.variable = variable;
this.callAjax = function() {
$.get('/url', { }, function(json) {
console.log(variable); //! <-- shows undefined
}, "json");
}
}
so I create a local variable: _variable
function Klass(variable) {
this.variable = variable;
this.callAjax = function() {
var _variable = this.variable;
$.get('/url', { }, function(json) {
console.log(_variable); //! <-- its ok
}, "json");
}
}
and its fine, but I really don't this solutions,
Does someone of you have a better code?
That's quite the way.
function(json){console.log(_variable);}
forms a closure with "_variable".
"_variable" keeps the original value forever.
If your "variable" should be updated later, and you want the updated "variable"
You define
var self = this;
and call self.variable to get it.
In this way you'll get the updated "variable" each time the callback is executed.
The complete code:
function Klass(variable) {
var self = this;
this.variable = variable;
this.callAjax = function() {
$.get('/url', { }, function(json) {
console.log(self.variable);
}, "json");
}
}

javascript passing function as parameter

If I have this:
$(SomeID).on({
click: function () { SomeFunction1(); },
mouseenter: function () { SomeFunction2(); },
mouseleave:function () { SomeFunction3(); }
}, '.SomeClass');
I can rewrite it as
$(SomeID).on({
click: SomeFunction1,
mouseenter: SomeFunction2,
mouseleave: SomeFunction3
}, '.SomeClass');
But what if I need to pass some parameter like this:
$(SomeID).on({
click: function () { SomeFunction1($(this)); },
mouseenter: function () { SomeFunction2($(this).index()); },
mouseleave: function () { SomeFunction3($(this).index()); }
}, '.SomeClass');
Is there an alternative?
Thanks.
As #Jashwant says, the same this would be used in the function anyway, so it's the one value you don't need to worry about (in your example).
Note that you could do as you describe if you needed to, it's easy for static values, and is called currying. A javascript example would be: http://www.dustindiaz.com/javascript-curry/
You should modify implementation of SomeFunctions to get them work without parameter.
For example, if you have:
function SomeFunction2(arg) {
//do something assuming arg to be $(this).index()
}
You can write it like that:
function SomeFunction2() {
var arg = $(this).index();
//do exactly the same
}
After doing that for all three callbacks, you can use your second code sample to bind them.
The meaning of this inside a javascript function does not depend on the lexical scope the function was defined in – for example, the following alerts "Hello, World!", event if this.name is not defined when greet is created
var x = { name: 'World' };
var greet = function() { alert('Hello, ' + this.name); };
x.greet = greet;
x.greet();
the following too alerts "Hello, World!":
var x = { name: 'World' };
var y = { name: 'Dude', greet: function() { alert('Hello, ' + this.name); } };
x.greet = y.greet;
x.greet();
Behind the scenes, what goes on is similar to:
var greet = function() { alert('Hello, ' + this.name); };
greet.call({ name: 'World' });
So you can safely mix your #2 and #3 snippets.
BTW:
most jQuery event handlers get called with a reference to the jQuery event object as the first parameter, so if you find how this works tricky (or if you fear you'll have to explain to each one of you colleagues), you can also use event.delegateTarget instead of this.
See for example:
$(document).click(function(evt){ alert (evt.delegateTarget === this); });

Passing local functions to setTimeout()

I have written the following function.
function obj()
{
this.a;
}
obj.prototype.catch = function()
{
alert('Catched')
}
obj.prototype.do = function()
{
alert('called');
}
What i need is, to call obj::catch() after obj::do() is called and the call must be performed from inside obj::do()
So how to pass the local function of obj to setTimeout
i have tried
obj.prototype.do = function()
{
window.setTimeout('"'+this.catch+'()"',1000);
alert('called');
}
It does not worked
Then i tried
obj.prototype.do = function()
{
window.setTimeout('"'+this+'.catch()"',1000);
alert('called');
}
which gave me the following error on Chrome console
Uncaught SyntaxError: Unexpected token ILLEGAL
So i tried the following dirty method(is it really dirty ?)
obj.prototype.do = function()
{
this.pid = randomVal(100);
window['temp'+this.pid] = this;
window.setTimeout("temp"+this.pid+".catch();",1000);
alert('called');
}
function randomVal(bound)//returns a random number between 0 and <bound>
{
return (Math.floor(Math.random()*(bound)));
}
That worked.
so why the first two methods not worked.Is there any other way to do the same thing without global variables..
The second method and last method are almost similar .But why am i gettng the error in second method..?
The worked code can be found here
http://jsfiddle.net/jXhAs/
Don't pass strings to setTimeout … ever.
var self = this; // Because the scope will change
setTimeout(function () { self.catch() },1000);
Or if you are using JS 1.8.5:
setTimeout(this.catch.bind(this),1000);
You can read more about bind
You should pass a function to setTimeout (not a string):
Example:
var self = this;
setTimeout(function(){
self.catch();
},1000);
use a closure
obj.prototype.do = function()
{
window.setTimeout((function(that){
return function(){
that.catch();
};
})(this),1000);
alert('called');
}
Why go through all of this effort, just pass the function.
function obj() {
this.a;
}
obj.prototype.
catch = function() {
alert('Catched')
}
obj.prototype.do = function() {
setTimeout(this.
catch, 1000);
}
var test = new obj();
test.do();​

How do you add objects to a javascript namespace?

var Test = (function() {
return {
useSub: function () {
this.Sub.sayHi();
},
init: function () {
$(document).ready(this.useSub);
}
};
})();
Test.Sub = (function () {
return {
sayHi: function () {
alert('hi');
}
};
})();
Test.useSub(); // works
Test.init(); // explodes
Above I am trying to create a Test namespace and add an object Sub to it. I was doing fine until I tried using the object in jQuery. The error is "Uncaught TypeError: Cannot call method 'sayHi' of undefined". If there is a better way to do this, I am open to it.
Edit:
Obviously this was demo code. In my real application the solution that I went with because I think it is the most clear is this one:
var Namespace (function () {
return {
init: function () {
$(document).ready(function() {
Namespace.onReady();
}
},
onReady: function() {
alert('Now I am back in the Namespace scope. Proceed as planned');
}
};
})();
Edit2: All jQuery callbacks seem to require they are used in this manner or else the scoping is screwed up.
I think it is a scope problem. If you do
$(document).ready(this.useSub);
then this.useSub will be executed in the window scope (so inside the function, this refers to the window object) and there doesn't exist a Sub attribute.
Try:
init: function () {
var obj = this;
$(function(){obj.useSub()});
}
For some reason it does not work using $(document).ready(function(){obj.useSub()}); but it works with the $() shortcut.
Here is one way
var Test = {
useSub : function () {
Test.Sub.sayHi();
},
init: function () {
$(document).ready(Test.useSub);
},
Sub: {
sayHi: function () {
alert('hi');
}
}
};
in this line:
$(document).ready(this.useSub);
you're passing a reference to a function and the scope is lost- when the function runs, this no longer means Test.

Categories