This is a basic question, but this impose an interesting question.
For instance,
var Foobar = function(){
this.baz = 100;
this.timer = null;
this.printLazy = function(){
this.timer = setTimeout(function(){
console.log(this.baz); //correctly bind this.
}.bind(this), 1000);
}
}
creates a traditional class that we can create instance and call printLazy as
var myBar = new Foobar();
myBar.printLazy();
Now in above code, printLazy method sets a timer and inside it, we access this.
Same thing can be achived using capturing as,
this.printLazy = function(){
var self = this; //capture this.
this.timer = setTimeout(function(){
console.log(self.baz); //correctly bind this.
}, 1000);
}
Is one of these methods are better than the other? (Considering efficiency or performance)
Can 2nd method can cause memory leaks, if its called lets say 1000 or more times in a quick succession where self would be referenced by other parts inside the function?
Is one of these methods are better than the other? (Considering efficiency or performance)
Not really. In your specific example, the version using bind creates an unnecessary function object (but JavaScript engines are very fast at doing that). But it also means that the function you're passing setTimeout doesn't close over anything, which is information the JavaScript engine might be able to use to optimize the context attached to it ("closure optimization").
But in modern environments, you'd probably use an arrow function in that situation rather than your self option:
this.printLazy = function(){
this.timer = setTimeout(() => {
console.log(this.baz);
}, 1000);
}
That will log this.baz as of when the timer fires. Another option, depending on what you need logged, would be setTimeout(console.log, 1000, this.baz). The difference is that this version will log the value this.baz has when the timer is set up, not as of when it fires. (It also relies on the fact that console.log, in most [but perhaps not all] environments, doesn't care what this is when you call it.) That's because setTimeout passes any extra arguments you give it to the function it calls when it calls it.
Can 2nd method can cause memory leaks, if its called lets say 1000 or more times in a quick succession where self would be referenced by other parts inside the function?
No. Memory leaks aren't caused by doing things quickly. They're caused by holding onto memory when you don't need it any more and not releasing it. What you're doing doesn't do that.
Had the same problem (in React) recently and found this article that shows several options. Below are 3 for your case, with the last one being the recommended option.
Option 1
Use arrow functions. But, this will still create a new function every time printLazy is called.
this.printLazy = function(){
this.timer = setTimeout(() => {
console.log(this.baz); //correctly bind this.
}, 1000);
}
Option 2
Create second function and bind it in the constructor, which still has performance drawbacks.
var Foobar = function(){
constructor() {
this.printLazyCallback = this.printLazyCallback.bind(this)
}
printLazyCallback() {
console.log(this.baz); //correctly bind this.
}
}
Option 3 (the one you should use)
Create second function as class prop arrow function
var Foobar = function(){
printLazyCallback = () => {
console.log(this.baz); //correctly bind this.
}
}
Related
I know this question has been asked multiple times (yes, I did some research) but I can't see to find a solution that fits my needs.
What I have done so far:
I was building a function that tracked the percentage of how far the user scrolled down a page and display this nicely into some progressbar. This worked perfectly but when I opened the developer console on Chrome and looked at the Timeline tab (this displays what is being run in a nice graphic), I realised that my code was quite "active". It ran every pixel the user scrolled down the page, which is quite alot to be honest.
So I thought to myself, how can this be improved and I have come up with a solution that involves executing a function only once per {whatever} milliseconds. This involves a variable set to true or false, if the function has already been executed in the {whatever} milliseconds.
What i want to accomplish:
I want to be able to set a reference to an external variable that will act as a flag to determine if the function has already been executed or not.
function qeue(fn, interval, status){ // this function name might not be very fitting..
// fn = function to be executed
// interval = function can only run once between the intervals
// status = tricky part..
// This should contain a reference to an external variable that is either true or false
}
How can this be accomplished?
side note
If this explanation isn't helping, and you still don't get what I want:
How can I pass a reference to a variable into a function, so that function can act based on the value of that variable?
Why normal parameters are not an option
I want to implement some sort of recursive setTimeout functionality inside a function, that checks if another function has been executed or not, if I pass this in to a parameter, this parameter cannot change during the process.
Hope you guys can help me out!
Thank you
Thank you for all your great answers. You made me learn alot. I am going with the debounce strategy! I marked T.J. Crowder as the best answer, because it was a good explanation and one of the first. But thank you all once again!
What you've described wanting to do doesn't immediately say "use a reference to a variable" to me (as Teemu points out, sounds like you want debouncing), but answering your question about references to variables...
JavaScript doesn't have any form of references to variables (other than through closures, which might be problematic here). But you can readily do what you're talking about by just using an object and using a property on it. The property is the "variable."
Simple example:
function foo(obj) {
var counter = 0;
var timer = setInterval(function() {
console.log("foo: " + obj.property);
if (++counter === 5) {
clearInterval(timer);
}
}, 500);
}
var o = {property: "unchanged"};
// Give the "reference" to `property` to `foo`:
foo(o);
// Update it periodically while `foo` is doing its asynchronous thing
setTimeout(function() {
o.property = "update 1";
}, 1000);
setTimeout(function() {
o.property = "update 2";
}, 1700);
In JavaScript values such as integers, strings, etc. are passed by value. If you want to pass a reference, you have to pass an object into the JavaScript function. (JavaScript objects are passed by reference)
function adjustValues(referenceObject) {
referenceObject.foo = 2;
referenceObject.bar = "newValue";
}
referenceObject = {
foo: 1,
bar: "initialValue"
};
adjustValues(referenceObject);
why don't you use the setInterval function, it will do exactly what you want.
Example:
setInterval(function() {
// logic to be implemented
}, delayInMilliseconds)
How can this be accomplished?
Not with a variable. There are no "references to variables" in JS. I can see two simple solutions:
pass a getter/setter function:
function queue(getStatus) {
…
getStatus() // gets current value
…
}
var executed = false;
queue(function() { return executed; });
pass an object with a property:
function queue(status) {
…
status.executed // gets current value
…
}
var status = {executed: false};
queue(status);
I have come up with a solution that involves executing a function only once per {whatever} milliseconds. This involves a variable set to true or false, if the function has already been executed in the {whatever} milliseconds.
I cannot see the reason why this variable would need to be a parameter to the function, and be available (or even settable?) outside it. Just use a local variable inside queue.
Btw, this functionality is known as debouncing, you don't have to write this yourself. Many implementations are already available on the web, sometimes as part of larger libraries. See for example What does _.debounce do?.
Try the following example :
'use strict';
var observable = 0;
function incObservable() {
++observable;
console.log('incObservable observable: '+observable);
}
function observe() {
console.log('observe observable: '+observable);
}
var observer = setInterval(observe, 100);
setTimeout(function() {
incObservable();
setTimeout(function() {
incObservable();
setTimeout(function() {
incObservable();
}, 300);
}, 300);
}, 300);
setTimeout(function() {
// Stop obsever
clearInterval(observer);
}, 1000);
// observe observable: 0
// observe observable: 0
// incObservable observable: 1
// observe observable: 1
// observe observable: 1
// observe observable: 1
// incObservable observable: 2
// observe observable: 2
// observe observable: 2
// observe observable: 2
// incObservable observable: 3
// observe observable: 3
I have a Javascript class like below:
var MYCLASS = function(elem, data, op) {
var options = {};
var loopForEver = function() {
console.log('I cant stop me');
setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
}
when I instantiate the class and call init function, then the loop starts and I get the text in my console every 1 second :
var ins = new MYCLASS();
ins.init();
Why when I set the instance to null, the thread does not stop? or any time I create a new instance and assign it to the previous instance name, it increases the calls.
in my production code, I do not have infinite loop, but I do have some business logic. do I need to be worried about performance when I create a new instance?
When you call setTimeout it is not bound by the function that called it. You need to add a property to object called something like timeOutID. As long as the function is still required being used by something like setTimeout it will remain in scope.
var MYCLASS = function(elem, data, op) {
var options = {};
var timeOutID = null;
var loopForEver = function() {
console.log('I cant stop me');
timeOutID = setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
this.stop = function () {
clearTimeout(timeOutID);
}
}
You have a memory leak.
In other words, memory leaks may occur when objects, which are now unreachable, are still kept in memory because they are being referenced somewhere else in the call stack.
Nullifying the instance doesn't clear from memory other references to that object. See this answer to "Can an object automatically delete itself in javascript once it has achieved its purpose?"
In fact, your setTimeout call is repeatedly creating a new execution context each with its own untouchable Activation object, which are unaffected by assigning the original instance to null.
An excerpt from "Understanding delete" (Perfection Kills by kangax) explains it this way:
When a function is executed, it is said that control enters
execution context…; that code might call a function, with its own execution context; that function could call another function, and so
on and so forth.
Even if function is calling itself recursively, a new execution
context is being entered with every invocation.
…when in Function code, a Variable object is … a so-called Activation
object. Activation object is created every time execution context for
Function code is entered.
Note that Activation object is an internal mechanism and is never
really accessible by program code.
If you want to nullify the instance, you should clean it up first by clearing the timed recursive call using .clearTimeout().
I have tried searching through a lot of S.O. pages but nothing has touched EXACTLY on this top while also NOT USING JQUERY.... I am trying to stick to pure JavaScript as I want to learn it 115% before advancing my current knowledge of JQuery.
I have an object called ScreenResizeTool like this...
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg);
}, true);
}
and a method like this...
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
My trouble is probably obvious to an experienced JavaScript user but I am having trouble not making this into a messy dirty awful OOP set. I have done various tests to show and prove to myself that the this inside the addEventHandler changes when it becomes bound to the window. This much I assumed before testing but I was able to see that once window.resize event happens the listen method is gone and not a part of the global window variable....
I have also tried adding a this capture such as this.me = this inside the object constructor however it also couldn't see the me variable once it ran. Once the window took the function over it no longer knew anything about the me variable or any reference to my class methods....
I am aware that I could separate this differently but my goal here is to learn how to fully encapsulate and use as many clean OOP structures as possible as I just came from the .NET world and I need it in my life.
I am also aware that I could make messy calls and or store this object or access to the methods inside the window variable but that seems outright wrong to me. I should be able to fully encapsulate this object and have its events and methods all implemented in this class structure.
I also know that the currImg variable is not going to be seen either but lets start small here. I assume once I figure out my incorrect train of thought on scope for JavaScript I should be fine to figure out the currImg problem.
I know there's 1000 JavaScript programmers out there waiting to rip me a new one over asking this simple question but I gotta know...
Thoughts anyone?
this inside a function bound to a DOM Object (like window) will always refer to that object.
this inside a constructor function will always refer to the prototype.
A common practice to circumvent the this issue, as you mentioned, is to cache it in a variable, often called self. Now you want the variables and properties of your object available after instantiation, so what you need is the return keyword, more specifically to return the parent object itself. Let's put that together:
function ScreenResizeTool() {
var self = this;
// method to instantiate the code is often stored in init property
this.init = function() {
window.addEventListener('resize', function() {
self.listen(); // self will refer to the prototype, not the window!
}, true);
};
return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
var h = window.innerHeight, w = window.innerWidth;
console.log('Resized to ' + w + ' x ' + h + '!');
};
Pretty easy huh? So we have our prototype now, but prototypes can't do anything if there's not an instance. So we create an instance of ScreenResizeTool and instantiate it with its init method:
var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!
You could also simply store the listen & init methods as private functions inside your constructor, and return them in an anonymous object:
function ScreenResizeTool() {
var listen = function() { ... };
var init = function() { ... };
// in this.init you can now simply call listen() instead of this.listen()
return {
listen: listen,
init: init
}
}
Check out the fiddle and make sure to open your console. Note that in this case I'd rather use the first function than the second (it does exactly the same) because prototypes are only useful if you have multiple instances or subclasses
The whole concept of this in JavaScript is a nightmare for beginners and in my code I usually try to avoid it as it gets confusing fast and makes code unreadable (IMHO). Also, many people new to JavaScript but experienced in object-oriented programming languages try to get into the whole this and prototype stuff directly though the don't actually need to (google JS patterns like IIFE for example as alternatives).
So looking at your original code:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg); // global function listen?
}, true);
}
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
First off, you probably mean addEventListener instead. In its callback you refer to listen but as a global variable which would look for it as window.listen - which doesn't exit. So you could think to do this:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
this.listen(currImg); // what's this?
}, true);
}
As you want to use the prototype.listen function of ScreenResizeTool. But this won't work either as the event listener's callback function is called with a different this and not the this that is your function scope.
This is where something comes in which makes most programmers cringe, you have to cache this, examples from code I've seen:
var _this = this;
var that = this;
var _self = this;
Let's just use the latter to be able to refer to the function within the event callback:
function ScreenResizeTool(currImg) {
var _self = this;
window.addEventListener('resize', function() {
_self.listen();
}, true);
}
Now this will actually work and do what you want to achieve: invoke the prototype.listen function of ScreenResizeTool.
See this JSFiddle for a working example: http://jsfiddle.net/KNw6R/ (check the console for output)
As a last word, this problem did not have anything to do with using jQuery or not. It's a general problem of JS. And especially when having to deal with different browser implementations you should be using jQuery (or another such library) to make your own code clean and neat and not fiddle around with multiple if statements to find out what feature is supported in what way.
I am trying to write a simple slider using plain JavaScript. As these are my first steps using the prototype of an object & following an object oriented approach in general, I am quite confused sometimes, so please bear with me.
Here is what I have:
function MySlider(noOfSlides, startSlide){
this.noOfSlides = noOfSlides;
this.startSlide = startSlide;
this.currentSlide = this.startSlide;
}
MySlider.prototype.nextSlide = function(){
this.currentSlide++;
console.log(this.currentSlide);
return this.currentSlide;
};
MySlider.prototype.startSlider = function(){
setInterval(function(){
MySlider.nextSlide();
}, 2000);
};
var slides = new MySlider(4, 1);
document.getElementById("button").addEventListener("click", function(){
slides.startSlider();
}, false);
Unfortunately, this isn't working, after the 2 seconds wait because of setInterval, I get the following error: TypeError: MySlider.nextSlide is not a function.
While I understand what the problem is, I don't know what to change. I already tried it with this.nextSlide() but that didn't work either. My guess is that it has something to do with the prototype chain, but I am still trying to understand this.
How to solve this problem? Or is it a bad idea in general to it this way?
You need to preserve the context (the value of this) when you set up the timer handler:
MySlider.prototype.startSlider = function(){
var slider = this;
setInterval(function(){
slider.nextSlide();
}, 2000);
};
By saving the value of this, you ensure that when the interval timer goes off it'll be able to invoke the "nextSlide" function in the context of the correct object.
I would like to have a pulldown menu close itself upon a mouseleave event, after a short delay. But I'm having trouble getting it working.
Consider the following methods in an object: (I am using jQuery)
myObj = {};
myObj.message = "woot!";
myObj.bindEvents = function() {
var that = this;
$("#menuPanel")
.bind("mouseleave", function() {
that.timer = setTimeout(that.closeMenu,500);
});
}
myObj.closeMenu = function() {
// close the menu
alert(this.message);
}
This doesn't work. That is to say, this.message comes up undefined. After a bit of digging, I understand why. :) The 'that' reference is not available to code inside of setTimeout at the time of execution.
I'm wondering, what is the "best" way to get around this type of problem? How can I have a method that uses setTimeout call another method in the same object, and still have access to the properties in the object?
Thanks in advance for your help.
The problem here is that you're detaching the closeMenu method from it's object. You would have the same problem if you did this:
var closeMenu = myObj.closeMenu; // detaching the method from the object
closeMenu();
Detaching and calling methods like this means they no longer apply to the objects they were created on. In your example, you're doing almost the same thing:
// Setting the first parameter of setTimeout to be the detached closeMenu method
that.timer = setTimeout(that.closeMenu,500);
A fix for the first method would be to use the call or apply methods:
var closeMenu = myObj.closeMenu; // detaching the method from the object
closeMenu.apply(myObj);
But that wouldn't work for a timer. Instead, create an anonymous function:
that.timer = setTimeout(function () { that.closeMenu(); },500);
It might also be worth mentioning bind() - not to be confused with jQuery's $('#selector').bind() - a method that's been floating around on various blogs and in some libraries (Prototype being the most notable) for a while now, and has finally been implemented in ECMAScript edition 5.
that.timer = setTimeout(that.closeMenu.bind(that),500);
I use a similar method in one or two classes I created, because it just makes things easier.