JS λ-functions & "upper context" variables - javascript

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.

Related

How to declare local variables inside an object and reference directly in javascript

I have a function as:
function Main(){
var self = this;
self.reserve=false;
self.change = function(){
self.reserve=!self.reserve
}
self.service={
to_add: 0, to_delete: 0,
init: function(data){
self.service.to_add = data[0];
self.service.to_delete = data[1];
},
custom_func: function(data){
self.service.init(data);
self.service.change;
},
/*there are many other functions here*/
}
}
Now as you can see inside the service object I need to reference everything like self.service.xxx.
But is there a better approach where I could reference the objects local variables directly like to_add=data[0] instead of self.service.add_to=data[0], but to use variables from other objects can follow the default way self.object.xxxx.
Reason: To reduce the script size. There are many such variables and functions inside the service object.
Note: Please change the question accordingly. I was not able to come up with any.

Procedurally Generated Variable Naming

So I am currently attempting to procedurally generate variable names based on some other things I want to do later in the function.
However when I attempt this as a trial function:
var gridCoord = [[1,2]];
var 'run' + gridCoord[0][0] + gridCoord[0][1] = function() {
console.log("Success!");
}
run12();
I am receiving syntax errors in the console.
You can't do it like that. Use dynamic naming of objects.
window['run'+gridCoord[0][0]+gridCoord[0][1]] = function() {
The window object is a global object; these functions can be called normally as any other global function can be called.
window['run'+gridCoord[0][0]+gridCoord[0][1] ]= function(){
console.log("Success!");
}
In the global scope, all variables are children of the window property

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.

How do you reference a custom object outside of the function it was created in with JavaScript?

I'm currently using JavaScript and jQuery.
I have an function which executes once the document is ready, and inside that I am creating objects which contain various attributes.
Within the same function, I can access these new object's attributes no problem, however once I'm inside a different function I can't seem to reference them properly and therefore cannot access the objects or the information inside them.
What's the correct way to reference the attributes of an object which was created in a different function to the one looking for the information?
In general you can't reference an object that was created in a different function. The scoping rules do not allow that.
However, if you create your sub functions inside of the main JQuery ready function, you can create your objects as local variables to the ready function and use them in your other functions.
This would create a closure allowing the variables to still exist yet not be in the global scope.
Something like this:
$(function () {
var MyObj = {"CT":0};
function Inc(){
MyObj.Ct++;
}
$("INPUT[type=button]").click(Inc);
})
Create the a global refernence to the object outside of the function, e.g.:
var obj;
function func1()
{
obj = 1;
}
function func2()
{
alert(obj);
}
The best way would be to create a global object which holds all that data.
var myGlobalData = function(){
// private data
var some = 'data',
foo = 'bar';
// public
return {
publicfunction: function(){
alert(foo);
return(some);
}
}
};
within your ready code you can create an instance of that
$(document).ready(function(){
var myData = new myGlobalData();
myData.publicfunction();
});
Note that in this example, you can't access 'some' and 'foo' with
myData.foo = 'bar'; // not possible
because those are 'private' to the object. If you write an object in that manner, you
can simulate a more OOP style.
I have an function which executes once
the document is ready, and inside that
I am creating objects which contain
various attributes.
Define these objects as properties of the global object (window) and you'll be fine.
function onready() {
window.myObject = {};
}
function otherFunction() {
window.myObject.fu = "bar";
}

Referencing an object to be augmented in javascript

I am trying to localize everything to a namespace in javascript. So I have objects that follow a naming convention like:
myapp.utilities.file.spinner
etc...
My question is, is there a way to avoid repeating that big string everytime I want to augment the object with a property or a method. Currently my code looks like this...
myapp.utilities.file.spinner.method1 = function() { };
myapp.utilities.file.spinner.method2 = function() { };
etc.
Something like this...
spinnerPath.method1 = function()
...where spinnerPath stands for myapp.utilities.file.spinner, would be nicer. But from my understanding I cannot just say
spinnerPath = myapp.utilities.file.spinner
as that will create another object in the global space.
Thanks
The code you're using won't actually create a new object, merely a new global variable referring to the existing object. It will pollute the global namespace however, so if you're looking to avoid that, you have several options:
You can use with, but don't because it will probably cause you more heartache than it's worth.
You can make a shorthand pointer variable inside each function outside of the global namespace: var s = myapp.utilities.file.spinner;, but this is annoying.
(Probably the best option) create a "private namespace" using an immediate-call function:
(function (S)
{
S.method1 = function(){/*whatever*/};
S.method2 = function(){/*whatever*/};
})(myapp.utilities.file.spinner)
Try this:
(function(){
var spinner = myapp.utilities.file.spinner;
spinner.method1 = function(){};
})();
myapp.utilities.file.spinner.method1 = function() { };
myapp.utilities.file.spinner.method2 = function() { };
...
// Somewhere else in your code, create a temp local called "spinner"
// that references your longer path object.
var spinner = myapp.utilities.file.spinner;
spinner.method1();
You can just make a temporary local variable wrapped in an anonymous function:
(function(){
var spinnerPath = myapp.utilities.file.spinner;
spinnerPath.method1 = function() { };
spinnerPath.method2 = function() { };
spinnerPath.method1();
})();
Here, spinnerPath is in fact a local reference to the global myapp.utilities.file.spinner object, not a copy. Objects in JavaScript are references, so if you create a local variable that points to it, you will not create a copy or pollute the global namespace.

Categories

Resources