javascript closure: protecting inner variable - javascript

I'm using the revealing module pattern somewhat like this:
var SomeClosure = function () {
var SomeInnerVar = 4;
function InnerGetTheVar() {
return SomeInnerVar;
}
function InitClosure() {
// there's something else happening here that requires me to
// wait for document.ready before initializing the closure
setInterval(IncreaseSomeInnerVar, 10000);
}
function IncreaseSomeInnerVar() {
SomeInnerVar = SomeInnerVar + 1;
}
InitClosure();
return {
GetTheVar: InnerGetTheVar
}
}
$(document).ready(function () {
SomeClosure = SomeClosure();
});
Now why is it that if in the console I type this:
SomeClosure.GetTheVar = 2;
SomeClosure.GetTheVar; // outputs 2!
Why doesn't the closure keep SomeInnerVar protected? I don't want the outer scope to be able to change SomeInnerVar like that.
Thanks for your suggestions.

Actually, SomeInnerVar is still 'protected', in this sense. However, you are overwriting SomeClosure's GetTheVar attribute with the value 2, which isn't 'protected' in the same sense. In other words, you aren't modifying SomeInnerVar, you're modifying GetTheVar.

Instead of just returning an object literal, use Object.defineProperty:
var out = {};
if ( Object.defineProperty ) {
Object.defineProperty(out, 'GetTheVar', {
value: InnerGetTheVar,
writable: false
});
} else {
out.GetTheVar = InnerGetTheVar;
}
return out;

Related

Call a returned function from outside its function

I'm trying to call a function that's returned from a function. Here's what I mean:
myFunction.something; // (Wrong)
function myFunction() {
return {
something: function() {
...
}
};
}
When I try calling myFunction.something nothing happens. How can I call a returned function outside of its function?
JSFiddle
var index = 0;
var animID = requestAnimationFrame(myFunction.something);
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction.something);
}
};
}
I would first of all recommend using descriptive variable names; utils rather than myFunction, and incrementFrame rather than something, for example. I would second of all recommend reconsidering your approach to code organization and simply putting all of your helper functions directly in an object, then referencing that object:
var index = 0;
var animID = requestAnimationFrame(utils.incrementFrame);
var utils = {
incrementFrame: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(utils.incrementFrame);
}
}
There are a few differences between these approaches, some of them frustratingly subtle. The primary reason I recommend using an object for organization rather than a function which returns an object is because you don't need to use a function for organization; you are unnecessarily complicating your code.
myfunction is not the object that you get from calling myfunction(), it's the function itself and does not have a .something method.
You could call it again (as in myfunction().something()), but a better approach would be to store a reference to the object you've already created:
function myFunction() {
var index = 0;
var o = {
something: function() {
index++;
console.log(index);
if (index < 5) requestAnimationFrame(o.something);
// btw you don't need to cancel anything once you reach 5, it's enough to continue not
}
};
return o;
}
myFunction().something();
Alternatively you might want to drop the function altogether, or use the module pattern (with an IIFE), as you seem to use it like a singleton anyway.
Try this:
myFunction().something()
myFunction() calls the myFunction function
them we use the dot notation on the returned value (which is an object) to find the something member of it
that member is a function too, so add another set of brackets () to call it
Call function after writing it
var index = 0;
function myFunction() {
return {
something: function() {
index++;
console.log(index);
if (index === 5) cancelAnimationFrame(animID);
else animID = requestAnimationFrame(myFunction().something);
}
};
}
var animID = requestAnimationFrame(myFunction().something);

making a function in an object chainable

I am trying to achieve a chainable object, but cannot figure out how I can do this within a function.
This is how I would like it to work:
$donate.ga('testing').go(value);
My object currently looks like this:
var $donate = {
ga: function (value) {
}
};
You simply need to make each function to return the instance of the object:
var $donate = {
ga: function (value) {
// logic
return this;
}
};
It's already solved here. You must simply return the object in your function.
You need to return the Object like that:
var $donate = {
ga: function (value) {
//after some computation
return this;
},
go: function(val) {
//after some computation
return this;
}
};
If you don't return this (this is a reference to the current Object), you either return undefined or something else and your method defined in your Object is simply out of scope (unknown).
you have to return this; in each sub function before closing it.
for example
Your code
var $donate = {
ga: function (value) {
//perform your code here
return this; // <--- Dont forget to use this before closing the function nest
},
go: function(val) {
//perform your code here
return this; // <--- Dont forget to use this before closing the function nest
}
};

Javascript - Call a Local Function / Property While in Global Scope

Let's say I have the following JavaScript
function myGlobalFunction(){
function firstInnerFunction(){
return "rainbows";
}
function secondInnerFunction(){
function innerInnerFunction(){
return "clouds";
}
return innerInnerFunction();
}
return firstInnerFunction(); //valid call
}
Is there anyway I can call firstInnerFunction() in the global scope? If so(and better yet), can I go two levels down and call innerInnerFunction() from the global scope?
What are you trying to achieve in doing something like that? I would suggest something like the following:
var myGlobalFunction = {
var innerInnerFunction() { return "clouds"; }
get firstInnerFunction() { return "rainbows"; }
get secondInnerFunction() { return innerInnerFunction(); }
};
You can then call firstInnerFunction() with something like this:
myGlobalFunction.firstInnerFunction;
as for calling innerInnerFunction() from the global scope, myGlobalFunction.secondInnerFunction() will serve the same purpose as calling innerInnerFunction() directly.
In short, no. JavaScript is function scoped, so everything inside is hidden from the outside. So in order to access the inner functions you'll need to expose them somehow.
Absolute simplest (but ugly) option is to do something like this:
var secondInnerCopy;
function myGlobalFunction(){
function firstInnerFunction(){
return "rainbows";
}
function secondInnerFunction(){
function innerInnerFunction(){
return "clouds";
}
return innerInnerFunction();
}
secondInnerCopy = secondInnerFunction;
return firstInnerFunction(); //valid call
}
myGlobalFunction();
secondInnerCopy(); //valid (only after myGlobalFunction called though)
Better option would be to restructure into an object graph with functions:
var global = {
myGlobalFunction: function(){
return this.inner.firstInnerFunction(); //valid call
},
inner: {
firstInnerFunction: function() {
return "rainbows";
},
secondInnerFunction: function(){
return this.inner.innerInnerFunction();
},
inner: {
innerInnerFunction: function(){
return "clouds";
}
}
}
};
global.myGlobalFunction();
global.inner.inner.innerInnerFunction();
//etc...
I don't think that this is possible, however I could be wrong. You could do something like this to access the nested functions via the top level function.
function A(x) {
function B(y) {
function C(z) {
alert(x + y + z);
}
C(3);
}
B(2);
}
A(1); // alerts 6 (1 + 2 + 3)
Another Example
function addSquares(a,b) {
function square(x) {
return x * x;
}
return square(a) + square(b);
}
a = addSquares(2,3); // returns 13
b = addSquares(3,4); // returns 25
c = addSquares(4,5); // returns 41
Check this link, it has some good information on functions and nested functions in Javascript. Javascript Function Scope
I believe something like this would also work, though I like what Alconja did.
var myGlobalFunction = {
firstInnerFunction: function(){
return "rainbows";
},
secondInnerFunction : function(){
var innerInnerFunction = function(){
return "clouds";
}
var inninnerFuncTwo = function(){
return 'more stuff';
}
return {
inn : innerInnerFunction,
inn2: inninnerFuncTwo
}
}
}
myGlobalFunction.secondInnerFunction().inn();
myGlobalFunction.secondInnerFunction().inn2();
If you want a call to globalFunction to define firstInnerFunction, you can do that as follows
function globalFunction() {
firstInnerFunction = function() { return "rainbows" ; } ;
}
For innerInner function, you can do as follows
function globalFunction() {
firstInnerFunction = function() { return "rainbows" ; } ;
secondInnerFunction = function() {
innerInnerFunction = function() { return "clouds" ; } ; }
}
Now you can do this
globalFunction() ; // defines firstInnerFunction and secondInnerFunction in the global scope
firstInnerFunction() ; // returns "rainbows"
secondInnerFunction() ; // defines innerInnerFunction
innerInnerFunction() ; // returns "clouds"

Access Return Object in Javascript

For a project I'm working on, I'm building some data objects with the following lay-out (it's a binary file that I'm reading with ArrayBuffers:
AFile.prototype = {
p: new BufferPack(),
filedata: null,
position: 0,
label_records: null,
closestmultipleof: function(n,v) {
return Math.ceil((v / n) * n);
},
r: function(size) {
result = new Uint8Array(this.filedata,this.position,size);
this.position += size;
return result;
}
readValueLabel: function() {
return {
value: this.rS(8),
len: this.rS8(),
label: this.rS(this.closestmultipleof(8, this.len + 1))
};
},
readLabelRecords: function() {
return {
rec_type: this.rS32(),
label_count: this.rS32(),
value_labels: _.map(_.range(this.label_count), function(num) {
console.debug(num);
},this)
};
},
loadFile: function(blob) {
this.filedata = blob;
this.label_records = this.readLabelRecords();
}
};
However, I seem to have problems with accessing the values in the return scope. In some return scopes, I need to access the variables from the same scope in order to manipulate the data a little bit (see the definition of value_labels).
Only, it doesn't seem to be able to access the variable label_count there (probably because it is in the same return scope). How would I be able to do this?
The only way that I can get it to work is if I do this:
ret = {}
ret['a'] = 5;
ret['b'] = ret['a'] * 2
return ret;
But that seems ugly enough. Any ideas?
And yes, it is a singleton! I'm only going to use this once.
Let me make clear: The problem is within the following code:
return {
a: functionreturn(),
b: this.a * s
};
This.a doesn't seem to exist there.
[update]
You can create a closure to label_count.
function AFile(){};
AFile.prototype ={
readLabelRecords: function() {
label_count=this.rS32();
return {
label_count:label_count,
log:console.log(label_count)//'return from rs32'
};
},
};
AFile.prototype.rS32=function(){
return "return from rs32";
}
var o = new AFile();
o.readLabelRecords();
That answer was based on the code provided, the simplest code to re produce:
function complicatedCalculations(){
return 22;
}
function returnObject(){
var cacheComplicated=complicatedCalculations();//closure variable will
// be available within the entire body of returnObject function
// but never outside of it.
return{
calculated:cacheComplicated,
twiceCalculated:cacheComplicated*2//you could not access calculated
// here so using a cache closure variable
}
}
Or have your returnObject function return a new instance of an object created with a constructor function:
function returnObject(){
return new (function(){
this.calculated=complicatedCalculations();
this.twiceCalculated=this.calculated*2;
})();
}
You forgot a comma before readValueLabel which makes the structure is invalid.
Update:
Too bad that the other answer was deleted, it had a valid point even if it didn't "compile".
Reference to this is problematic inside inner scopes in JS, but it can be worked around by doing something like that:
readLabelRecords: function() {
var that = this;
return {
rec_type: that.rS32(),
label_count: that.rS32(),
value_labels: _.map(_.range(that.label_count), function(num) {
console.debug(num);
},that)
};
}

How can I call any function in a chain of functions, without the chaining?

Sorry if my question wasn't clear enough. I'll put my code here...
var chain = {
'fn_1' : {
//fn_1 code here
chain.fn_2();},
'fn_2' : {
//fn_2 code here
chain.fn_3();}
...and so on
}
Let's say if i wana call chain.fn_1(), is there a way I can do that without calling chain.fn_2()?
What I can think of right now is a flag, but that would be alot of excess flags probably for each function. Do you guys have any ideas?
If the series of functions each call the next one you're correct, you'd need to have some sort of flag. In all likelihood, what would be best would be to modify your functions so that they return the reference to the object. Then you could chain like so:
var chain = {
'fn_1': function () {
// do something here.
return this;
},
'fn_2': function () {
// do something here.
return this;
},
'fn_3': function () {
// do something here.
return this;
}
};
// call the full chain:
chain.fn_1().fn_2().fn_3();
// call only the middle.
chain.fn_2();
g.d.d.c's answer is best, but if you can't modify the object for some reason, you could do this:
var _oldFn2 = chain.fn_2
chain.fn_2 = function() { return; };
chain.fn_1();
chain.fn_2 = _oldFn2;
var chain = {
fn : ['fn1', 'fn2', 'fn3'],
call : function(name) {
var i = 0, pos = -1, l = this.fn.length;
for(i = 0; i < l; i += 1) {
if(this.fn[i] == name) {
pos = i;
}
if(pos !== -1) {
this[this.fn[i]]();
}
}
},
fn1 : function() {
alert('fn1');
},
fn2 : function() {
alert('fn2');
},
};
chain.call('fn1'); //chain
chain.fn1(); //single

Categories

Resources