confused about this javascript closure pattern - javascript

h = function(){
x = function(){
alert("try");
}();
x;
};
I'm confused about this behavior: the inner function is immediately invoked, and it's ok. But why i must have an assignment? Why i can't write it anonymously?

I added a var and moved the internal execution down a line
h = function(){
var x = function(){
alert("try");
};
x();
};
then you can invoke h
h();
or you can invoke it directly with
h = function(){
var x = function(){
alert("try");
};
x();
}();
or you can twist it into the module pattern with
h = function(){
var x = function(){
alert("try");
};
return {
x:x
};
};
h().x();
Hope that helps

You can write it anonymously, of course:
(function(){
(function(){
alert("try");
})();
}) ();
In fact, your example is not working, since you forgot to invoke it in the last line:
} ();
See JSFiddle

Related

Function not defined using setTimeout

For some reason after I wrapped my js code in an immediately invoked function expression I'm getting progressBar not defined. Wondering why this is the case?
(function(){
"use strict"
var progressBar = function(){
var bar = document.getElementById('pbar'),
status = document.getElementById('status'),
barValue = bar.value;
status.innerHTML = barValue + "%";
bar.value++;
var increment = setTimeout("progressBar()", 50);
if(bar.value == 100){
status.innerHTML = '100% - Straight Besting';
bar.value = '100';
clearTimeout(increment);
}
}
progressBar();
})()
When you pass a string to setTimeout, it is invoked in the context of the global window object.
Change the setTimeout line to:
var increment = setTimeout(progressBar, 50);
E.g.
(function() {
let i = 0;
let myfunction = function() {
console.log(i++);
if (i < 10) setTimeout(myfunction, 100);
};
myfunction();
})()

how to get property from other function

I want to access var w value from other function. Is it possible.
<script type="text/javascript">
var first = {
myFirst: function(){
var w= 90;
var q=12;
}}
var second= {
mySecond: function(){
first.myFirst.w
}}
</script>
In that way you cannot access w because it's defined in the local scope of myFirst. You can do something like:
var first = {
myFirst: function(){
first.myFirst.w = 90;
var q=12;
}
};
var second= {
mySecond: function(){
alert(first.myFirst.w);
}
};
first.myFirst();
second.mySecond(); //alerts 90
In that way w will be added as property of the function myFirst, if you want to add it as property of first, use:
var first = {
myFirst: function(){
this.w = 90;
var q=12;
}
};
var second= {
mySecond: function(){
alert(first.w);
}
};
first.myFirst();
second.mySecond(); //alerts 90
No, that's not possible, because the scope of w is within the function. Once the function has been called w no longer exists.
Also, technically you would need to call first.myFirst().w;
To get that to work you could do this instead:
var first = {
myFirst: function(){
var w= 90;
var q=12;
return { w : w };
}
}
first.myFirst().w // now works.

Object doesn't support method

I'm trying to run the following code, but get an error in the gameLoop function saying: JavaScript runtime error: Object doesn't support property or method 'update'.
I'm a beginning JavaScript programmer. Can you spot what is wrong with this code?
function Core(context) {
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
}
Core.prototype.run = function() {
setInterval(this.gameLoop, this.fps); // <<<< PROBLEM
}
Core.prototype.gameLoop = function () {
this.update();
this.draw();
}
Core.prototype.update = function () {
this.sprite.x += 50;
this.sprite.y += 50;
}
Core.prototype.draw = function () {
this.context.clearRect(0, 0, 300, 300);
this.context.fillRect(this.sprite.x, this.sprite.y, 50, 50);
this.context.fillText('x: ' + this.sprite.x + ' y: ' + this.sprite.y, 10, 250);
}
In JavaScript, this is defined entirely by how a function is called, not where or how it's defined. The problem is that setInterval doesn't call your code with the correct this value. To fix:
function Core(context) {
var self = this;
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
this.boundGameLoop = function() {
self.gameLoop();
};
}
Core.prototype.run = function() {
setInterval(this.boundGameLoop, this.fps);
}
On JavaScript engines that have ES5 features (or if you're using an ES5 "shim"), you can change Core to:
function Core(context) {
this.context = context;
this.fps = 500;
this.sprite = new Sprite();
this.boundGameLoop = this.gameLoop.bind(this);
}
More reading:
Mythical methods
You must remember this
Function#bind in the ES5 spec
Side note: Your code relies on the horror that is Automatic Semicolon Insertion. (All of your function assignments — Core.prototype.run = function() { ... }) need semicolons after the closing }.)
What you need is .bind.
setInterval(this.gameLoop.bind(this), this.fps)
Try reshuffling your code so that you declare update before you call it, e.g.
Core.prototype.update = function () {
this.sprite.x += 50;
this.sprite.y += 50;
}
Core.prototype.gameLoop = function () {
this.update();
this.draw();
}

Prevent event inside object function to overwrite "this"

Game.prototype.run = function() {
window.setInterval(function() {
var thisLoop = new Date().getTime();
this.update();
this.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
game.js:198Uncaught TypeError: Object [object DOMWindow] has no method 'update'
Why is this happening ?
"this" should relate to the Game object.
Cache the this variable, or use Function.bind:
Game.prototype.run = function() {
var _this = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
_this.update();
_this.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
Or, using Function.bind:
Game.prototype.run = function() {
window.setInterval((function() {
...
}.bind(this), 1000 / this.fps);
};
this in a function passed to setInterval refers to the global window object, or is undefined (in strict mode).
Another method, similar to the first one. Pass this as a parameter to the function (so that no extra local variable is used):
Game.prototype.run = function() {
window.setInterval(function(_this) {
var thisLoop = new Date().getTime();
_this.update();
_this.render();
lastLoop = thisLoop;
}, 1000 / this.fps, this);
};
No, this in the scope of the function refers to the function itself. Its somewhat hard to wrap your head around scoping in JS if you're not used to it.
The easy solution is to cache the context of "this" outside the anonymous function and use that instead.
Game.prototype.run = function() {
var game = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
game.update();
game.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
DEMO: http://jsfiddle.net/kmendes/awzMn/
In this case there's no way you can do that because the setInterval function has a different scope. This is what you can do:
Game.prototype.run = function() {
var currentGame = this;
window.setInterval(function() {
var thisLoop = new Date().getTime();
currentGame.update();
currentGame.render();
lastLoop = thisLoop;
}, 1000 / this.fps);
};
Try this :
Game.prototype.run = function() {
var intervalCallBack = function() {
var thisLoop = new Date().getTime();
this.update();
this.render();
lastLoop = thisLoop;
};
var self = this;
window.setInterval(function(){intervalCallBack.call(self);}, 1000 / this.fps);
};
Because of the fact that setInterval and setTimeout executes your callback in the global context, your this "pointer" that you used to refer to your game object is now referring to the global object (window) , which of course has no method 'update'.

javascript setInterval on an object's function only calls 2x

var focus = true;
function z() {
this.t = 0;
this.p = function (t) {
if (focus == true) {
this.t = t;
alert(this.t);
}
}
}
var zp = new z();
setTimeout('zp.p(0)', 100);
window.setInterval('zp.p(1)', 2000);
var ftimer = setTimeout('focus=false', 2000);
document.addEventListener('mousemove', function (e) {
clearTimeout(ftimer);
focus = true;
ftimer = setTimeout('focus=false', 2000);
}, false);
I have this code. but for some reason it only alerts twice even with continuous mouse movements. I have been working at this and investigating in firebug and focus is true when I am moving my mouse. I have been trying to figure out what is going on.. even if I do this:
function z() {
this.t = 0;
this.p = function (t) {
if (focus == true) {
this.t = t;
}
alert(this.t);
}
}
It still only alerts twice.
I have tried using a looping setTimeout function too but that doesnt work either. It is driving me crazy.
Good that you found your bug.
I would write your code using a bit more functions-as-first-class-objects and less eval logic:
var focus = true;
function z() {
var that = this; // we won't always have the correct value of "this"
this.focus = true;
this.t = 0;
this.p = function (t) {
if (that.focus == true) {
that.t = t;
alert(t);
}
}
this.fade = ( function(obj){ return function(){ obj.focus = false; } } )(this); // Using self-invokation
}
var zp = new z();
setTimeout(zp.p, 100, 0);
window.setInterval(zp.p, 2000, 1);
var ftimer = setTimeout(zp.fade, 2000);
document.addEventListener('mousemove', function (e) {
clearTimeout(ftimer);
zp.focus = true;
ftimer = setTimeout(zp.fade, 2000);
}, false);
I used a self-invoking function on line 10: ( function(obj){ return function(){...} })(this);, and set this to a different variable.
I found out that it was just related to firefox and that firefox choked on a line of code so that is why it wouldn't run. So I fixed that and now everything is all good.

Categories