Javascript bind behaviour - javascript

I have two javascript files that look like:
// module1.js
var globalFunction = function(val1, val2, callback){
var localVariable1 = val1;
var localVariable2 = val2;
someAsyncFunction(function(){
callback(localVariable1, localVariable2 );
});
}
module.exports = function(val1, val2, callback){
var localVariable1 = val1;
var localVariabl2 = val2;
anotherAsyncFunction( function(){
globalFunction(localVariable1, localVariable2, callback);
});
}
and this:
function MyClass(val1, val2){
this._val1 = val1;
this._val2 = val2;
this._boundFunc = require("./module1.js").bind(this);
}
MyClass.prototype.doSomething = function(callback){
this._boundFunc(callback);
}
Now this incredibly contrieved example binds the module.exports to the class MyClass. What is happening under the hood here? Does each MyClass instance have its own copy of the module.exports function and also will it have it's own copy of the globalFunction as this is referenced in the module.exports?
My concern is that if multiple "doSomething" functions are called synchronously on two difference instances of MyClass then they can interfere and overwrite each others local variables whilst waiting on the asyncFunctions to callback. If the bind copied both the globalFunction and module.exports then I dont think Id have a problem. Thanks

this will help you understand
Does each MyClass instance have its own copy of the module.exports function
no it doesn't. The code in module1.js is run only once and it's module.export is "cached" so whenever you require('./module1') you are getting the same instance of that object
they can interfere and overwrite each others local variables
no they can't. These variables are re-created every time you call the function so every call to the function has its own local variables and don't interfere with one another

My concern is that if multiple functions are called they can interfere and overwrite each others local variables
No, that cannot happen ever. The local variables (vars, parameters) in each function are created independently for every function call. Even if you call the same function it twice, it generates two unrelated sets of local variables. Assigning one of the variables from the first call will not change the variable of the same name in the second call.
What can of course happen is that the calls explicitly share a mutable value, i.e. an object or an instance of your class. If you change a property of it, and both function calls work on the same object, they can interfere indeed. In your example, the underscored properties of your MyClass instances are not used anywhere though.

Related

What is the correct way of calling an internal function using the module pattern in Javascript

I am new to Javascript and am still getting my head round the various ways of creating objects i.e constructor+new, prototypal, functional & parts.
I have created what I think is an object factory using the module pattern and want to know what the correct method of calling an internal method would be. Is it via this or function name.
Here is my module:
function chart() {
function my() {
// generate chart here, using `width` and `height`
}
my.sayHi = function(){
console.log('hi');
my.sayBye();
};
my.sayBye = function(){
console.log('Bye');
};
return my;
}
var test = chart();
test.sayHi();
You can see that the first function calls the second using my.sayBye() or is it better to use this.sayBye(). Both produce the same result and run without error.
The module pattern allows you to dispense with the 'this' variable if you want to. I would probably rewrite the above code to look like this and then the question becomes moot.
function chart() {
var hiCount = 0;
function sayHi(){
console.log('hi');
hiCount++;
sayBye();
};
function sayBye(){
console.log('Bye');
};
return {
sayHi : sayHi,
sayBye: sayBye
};
}
var test = chart();
test.sayHi();
In the above code all is defined within the function chart. As JavaScript's scope is at the function level every time the chart function is called a new set of functions will be defined. And a new set of variables can also be defined that are private to the function as they are defined in the function and are not accessible from outside. I added hiCount as an example of how you could do this. The Module pattern allows privacy in JavaScript. It eats more memory than the prototype pattern though as each time a function is declared it is not shared between other instances of the same class. That is the price you have to pay in Javascript to have class variables that are private. I willingly pay it. Removing 'this' from my code makes it easier to understand and less likely that I will fall into problems of misplaced scope.
Using "this" is better approach because you would be able to bind the function directly to the parent function object.And you dont need to return anything from the function.
where as in your case you are explicitly returning another function
Here is the use of "this" approach
function chart() {
this.sayHi = function(){
console.log('hi');
}
}
var test = new chart();
test.sayHi();
Using this approach you would be able to call anything in the prototype of function "chart"
Eg
chart.prototype.hello = function(){
console.log('hello')
}
So you would be able to call the hello function from the same object(test)

Access a javascript variable from a function inside a variable

Hello i have the following issue i am not quite sure how to search for it:
function(){
var sites;
var controller = {
list: function(){
sites = "some value";
}
}
}
So the question is how to access the sites variable from the top defined as
var sites
EDIT:
Here is a more complete part. i am Using marionette.js. i don't want to define the variable attached to the Module (code below) variable but keep it private to the Module, hope that makes sense. Here is the code that works:
Admin.module("Site", function(Module, App, Backbone, Marionette, $, _ ) {
Module.sites = null;
Module.Controller = {
list: function (id) {
Module.sites = App.request("site:entities");
}
};
});
and i would like instead of
Module.sites=null;
to do
var sites;
That sort of thing does make a difference right? Because in the first case i would be defining an accessible variable from outside where as the second case it would be a private one. i am a bit new to javascript so please try to make it simple.
if you are looking for global access, just declare the variable outside the function first, make your changes to the variable inside the function, then you can get the value whenever you need it.
I have found some info on this: sadly what i am trying to do doesn't seem possible.
Can I access a private variable of a Marionette module in a second definition of that module?
So i guess i have to do _variable to make developers know its private.
Disclaimer: I have no experience using Marionette, however, what you're describing sounds very doable.
One of the most powerful (in my opinion) features of JavaScript is closures. What this means is that any function declared from within another function has access to the variables declared in the outer function.
For example:
var func;
function foo() {
var answer = 42;
func = function () {
// I have access to variable answer from in here.
return answer++;
};
}
// By calling foo(), I will assign the function func that has access "answer"
foo();
// Now I can call the func() function and it has access to the "answer"
// variable even though it was in a scope that doesn't exist anymore.
// Outputs:
// 42
// 43
console.log(func());
console.log(func());
What this means is that if you declare var sites from within your module definition function as you described, you should have access to it from within any of your inner anonymous functions. The only exception is if Marionette is re-writing your functions (by using the Function function and toString()), which seems unlikely but possible.
Your original example should would as described, my suspicion is that there is something else going wrong with the code that is unrelated to your scope.

Javascript: append script with an object, and create a local instance

Let me expose my question:
I have a main script, let's say that it creates an instance of a "game" object, which, depending on the actions of the user, loads one of many javascript files, let's call them "levels" :D These files contains different objects, for example, "level1.js" which contains the object for level1, then "level2.js", etc.
Each time a level script is loaded, for example level1.js, the instance of "game" creates an instance of the object level1 and stores it in a local variable.
The only way I've found to do it, is to write, at the end of all the "level" scripts, a global variable, which has always the same name, and that points to the definition of the current level. Then in game, when any level script is loaded, I use this global variable to create the instance of the current level. I would like to know if there is a way to do it without using a global variable.
Here is a simplified example:
In game.js:
function Game() {
var levelCurrent = null;
var scriptCour = document.createElement("script");
scriptCur.type = "text/javascript";
scriptCur.onload = function() {
levelCurrent = new level();
}
}
And in each "level" script (level1.js, level2.js):
function level1() {
//definition of the level
//...
}
level = level1;
Or, similarly:
level = function() {
//definition of the level
//...
}
I don't know if I explained well enough my question, but if anyone has an answer... Thank you! Note that the instance of game is created using a self-executing function, and is therefore a local variable, like:
(function() {
var game = new Game();
})();
Thank you!
Instead of assigning the new level to a global variable, you should call a global function with the level information, e.g.
window.addLevel(function level1() {
//definition of the level
//...
});
Why is your Game instance a local variable, can't it be accessed? I guess it's a singleton (only one instance), so it would be perfectly valid to have it as a global variable. It then would be a good namespace for the addLevel function (window.game.addLevel()).
You could have the main game code expose a single global function, like "startNewLevel" or something, and then instead of declaring a global variable you'd just have the new level pass itself to that function.

how to assign functions in javascript?

I'm new to Javascript and I just discovered the property keyword for defining functions for objects. I tried to refactor my websocket experiment using objects, but I can't get it to work.
This works (no objects):
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
But this doesn't:
function MyObject() {
this.ws = new WebSocket(something, somethingelse);
this.ws.onopen = this.onOpen;
}
MyObject.prototype.onOpen = function() {
this.ws.send("hello"); // undefined!
};
Why is ws undefined? Am I assigning the onOpen function incorrectly?
You are assigning functions correctly (there is only one way of assigning functions), your problem is that the context of the function changes.
Consider this line:
this.ws.onopen = this.onOpen;
Possibility 1:
Now I assume, inside WebSocket, somewhere this function gets called as a response to an opening connection (like an event handler), probably like
this.onopen();
What this refers to inside a function is determined by how a function is called on run time (<- read this link, it helps a lot). It is not bound at definition time. In your case, this would refer to the WebSocket instance.
So inside if called this way, inside MyObject.prototype.onOpen, this refers to this.ws, the WebSocket instance, which does not have a ws property, and not the MyObject instance.
This can be solved in two ways:
Since this already refers to this.ws, you can call send directly on this:
MyObject.prototype.onOpen = function() {
this.send("hello");
};
If you want this inside MyObject.prototype.onOpen to always refer to the MyObject instance, you have to keep an explicit reference to the instance, e.g. through a closure:
var self = this;
this.ws.onopen = function() {
self.onOpen();
};
Now inside onOpen, this refers to the MyObject instance which has a property ws, just like you set it up in the constructor.
In browsers supporting ECMAScript 5, functions already have a method for this technique, called .bind():
this.ws.onopen = this.onOpen.bind(this);
Possibility 2:
It could also be that WebSocket calls onopen in such a way:
this.onopen.call(null);
In that case, this would either refer to window or would be undefined, depending on whether the code runs in strict mode or not (it does not matter, in any case it is a problem).
This situation could only be solved with the second solution from the first possibility.
Why does the first example work?
var ws = new WebSocket(something, somethingelse);
ws.onopen = function() {
ws.send("hello");
console.log("works");
}
In this case, the function you assign to ws.onopen is a closure, closing over the variables defined in this scope, also ws. In this sense it is similar to the second way of solving the problem, but
ws.onopen = function() {
this.send("hello");
console.log("works");
}
would probably work as well.

JS λ-functions & "upper context" variables

Say I have some context where variables are set and a λ-function is called which uses them directly:
function outerContext(){
...
var data = ...; // some data the script uses
...
someObject.method = function(){
data; // the variable is used here
};
...
}
I know that the dynamically created function has a snapshot of the context it was created in, so data variable is accessible there.
What are the dangers I may face with such an approach when I use this dynamically created method? Should I always give this data as an argument or is it ok?
The inner function does not have access to a "snapshot", it has full access to the data variable.
function outer() {
var data = 1;
...
someObject.method = function () {
data = 42;
};
someObject.method();
// data == 42
}
(The real explanation being that when using data in the inner function, Javascript will try to figure out which scope data is in. It will traverse up the scope chain to find the place where the variable was created, and that's the variable that will be used.)
There's no "danger", this is one of the core competencies of Javascript. It's like an object method modifying an object's properties. Of course you need to take care what you want to do, do you really want to modify the variable or do you just want to use it locally?
For the "snapshot", you need to use a closure:
function outer() {
var data = 1;
...
someObject.method = (function (data) {
return function () {
data = 42;
}
})(data);
someObject.method();
// data == 1
}
I can't really think of any "dangers" besides the possibility of causing a circular reference and thus a memory leak in case of DOM objects or such.
It works much like a private variable in a class.

Categories

Resources