How to do chain interface using constructor functions in Javascript? - javascript

I want an chain-able interface similar to jQuery. Still all prototype tutorials, talks, jQuery source is not making this clear, so much appreciate help in solving this.
In jQuery I can call jQuery('.apple') but also jQuery.ajax('param') since jQuery seems to be a constructor function, and therefore can have properties such as the ajax function I assume?
What I want:
Postal('apple') // Return chain-able function/object/constructor thing
Postal('apple').send('China').fee(99) // Used like this
Postal.send // should be undefined, need product-selector
Postal.area // should be function, accepting 1 parameter
Postal.area('Europe') // Use like this
Postal.area('Asia')
Note above: The Area should be accessible for chain-methods such as send()
Functions that can use the "Global Accessor" product selector:
Postal('apple').send('China').fee(9) // Apples to China fee
Postal('apple').fee(9) // Apples to anywhere default fee
Postal('orange').send('USA').fee(9)
My attempt at solving it:
Comments is around my approach to understand and mimic jQuery's source:
// # Assume
// ES2016 and not to much performance downsides or object allocations
//This should become our Globalisk-jQuery-Accessor
var Postal
// Create a non-global scope inside here
(function() {
// Locals that are global for the postal-object-function
var p_area = 'global'
var p_destination = 'unknown'
var p_product = '<unknown product>'
// our main selector, like: jQuery('.container')
var postal = (product) => {
// We use the same postal-object but create a new instance that can
// handle initializations of something
return new postal.prototype.init(product)
}
// All functions that only callable with a product-selector
postal.prototype = {
init: (product) => {
console.log("Init ran "+product)
// here we return this in case of no arguments?
// should we return the base object with slightly different methods?
if (!arguments[0]) {
return this
}
// Make 'product' parameter local to this postal call but shared
// amongst all chaining functions
p_product = product // or?
}
}
area = (area) => {
p_area = area //Save for future calls
console.log("Area set to: " + area)
return
// No return since no chaining possible after area is set
}
send = (destination) => {
p_destination = destination //Save for future chaining
console.log("Sending to " + destination + "...")
return send
}
send.fee = function fee(amount) {
console.log("Setting "+p_destination+" send fee to " + amount + " in " +
p_area + " for product "+ p_product)
return fee
}
// Set so new instance has same "properties" as postal has itself
//Need something like this? postal.prototype.init.prototype = postal.prototype
Postal = postal // Set our global accessor, from now on it should be const
})()
// Call direct function without going trough selector
console.log( Postal.send === undefined )
Postal.area('Europe') // Change the Postal-global "current area" state
Postal('apple').send('China').fee(99) // Applies only to "Europe"
Postal.area('Asia')
Postal('apple').send('China').fee(33)
Postal('orange').send('USA').fee(9)
Expected output:
Assuming code is fixed to work as intended. I am running in node v5.3.0.
true
Area set to: Europe
init ran apple
Sending to China...
Setting China send fee to 99 in Europe for product apple
Area set to: Asia
Sending to China...
Setting China send fee to 33 in Asia for product apple
init ran orange
Sending to USA...
Setting USA send fee to 9 in Asia for product orange
This is easy to accomplish with two accessors such as:
PostalCore.area() for global-methods and Postal('product here') for product-selector-methods, so the essence of the question is really how to do this with a constructor function so one can have both on same object, like jQuery does - I also welcome arguments to why not :)

Related

How to dynamically add function objects to an object function map

Hey there StackOverflow people of the world! Thank you for helping me with my question, and I apologize if this question gets a bit long winded. I just want to be clear about all the details and constraints I am working with. I found a few other related questions but nothing that was really very clear about how to get around my specific problem, unless I am missing something. Related questions:[1, 2]
Question Setup:
This is what I have and how it works, my question will be about a problem I am having
I've got a object that I've filled with named functions. The purpose of the object map is to contain many functions calls from multiple files. I am calling each function a "business rule" and they are typically very small functions that do a singular action with well-defined inputs and outputs. It also lets me chain the function calls sequentially with the output from functionCall1 becoming the input functionCall2.
All of my business rule definitions up to this point have been in a set of files that reside in a sub-folder called "Framework", but what I am trying to do now is allow the "Client" to define their own business rules in their own files and their own object map of function calls. What I would like to do is add all of the function calls to a single shared data storage.
What I am trying to avoid doing:
I am NOT trying to serialize the function calls, neither am I trying to leverage the 'eval' capability of JS. I've tried working with this before and it gets really messy!
Also I DO NOT want to declare a "class" object or use the "this" keyword for this reason:
10-most-common-javascript-mistakes
What is working:
(NOTE: Greatly simplified as I currently have hundreds of "business rules")
// rulesLibrary.js
import * as stringParsing from './Rules/stringParsing';
export const rulesLibrary = {
['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),
// Business Rules
// ********************************
// StringParsing rules in order
// ********************************
['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
}
// stringParsing.js
export const stringToBoolean = function(inputData, inputMetaData) {
var returnData;
// Function Body...
return returnData;
};
export const stringToDataType = function(inputData, inputMetaData) {
var returnData;
// Function Body...
return returnData;
};
// ruleBroker.js
import * as rules from './rulesLibrary';
export const processRules = function(inputData, inputMetaData, rulesToExecute) {
var returnData = inputData;
for (var rule in rulesToExecute) {
if (rulesToExecute.hasOwnProperty(rule)) {
var key = rule;
var value = rulesToExecute[key];
returnData = rules.rulesLibrary[value](returnData, inputMetaData);
}
}
return returnData;
};
You can see in the code above the rulesLibrary is defining the functions in an object rulesLibrary = {}; which is also exported. Then in the ruleBroker we are calling the associated function:
rules.rulesLibrary[value](returnData, inputMetaData)....and this works great.
My Goal
My goal is to rather than store all these functionName: functionCall on the rules.rulesLibrary, I want to store them on a singleton data storage object I am calling "D".
Here is the definition of "D":
// data.js
export var data = {};
What I have tried - Attempt 1
I first tried to assign all of the contents of the rules.rulesLibrary from the rulesLibrary.js directly to "D" like so in the ruleBroker.js file:
// NOTE: I am actually doing this inside a function so I can boot-strap the rules.rulesLibrary into `D`, before the application begins going about the business of calling business rules via the ruleBroker.
import * as rules from './rulesLibrary';
var D = require('../Resources/data');
D['BusinessRules'] = {};
D['BusinessRules'] = rules.rulesLibrary;
This did not work and attempting to console.log(JSON.stringify(D)); just gave me back:
D{BusinessRules} = {};
What I have tried -- Attempt 2
So I thought maybe I should try and define the business rules map named function calls directly on "D" like so in the rulesLibrary.js file:
// NOTE: I am again doing all of this inside a boot-strap function for the same reason as above.
export const initRulesLibrary = function() {
D['BusinessRules'] = {};
D['BusinessRules'] = {
['Echo']: (inputData, inputMetaData) => (inputData, inputMetaData),
// Business Rules
// ********************************
// StringParsing rules in order
// ********************************
['stringToBoolean']: (inputData, inputMetaData) => stringParsing.stringToBoolean(inputData, inputMetaData),
['stringToDataType']: (inputData, inputMetaData) => stringParsing.stringToDataType(inputData, inputMetaData),
}
};
Again I get the same thing, contents of D are: D{BusinessRules} = {}.
Maybe console.log in combination with JSON.stringify doesn't work with function-objects?
But then again, I do have rules that return a function-object and I have been able to stringify those function-objects in the past with this same code. Granted it's a function-object so I am not expecting it to look pretty when stringified, but that's not the point. The point should be that the function-object exists on 'D' and it clearly does not, what am I missing here? How can I get all my function-objects mapped on 'D' so that I can add/merge more function-object definitions to it?
Ultimately this is what I want to be able to do:
function addClientRules(clientRules) {
Object.assign(D['BusinessRules'], clientRules['BusinessRules']);
};
Such that D now contains all of the system-defined business rules & all of the client defined business rules. Then in the ruleBroker, I would just call whatever business rule like this:
export const processRules = function(inputData, inputMetaData, rulesToExecute) {
var returnData = inputData;
for (var rule in rulesToExecute) {
if (rulesToExecute.hasOwnProperty(rule)) {
var key = rule;
var value = rulesToExecute[key];
// OLD WAY:
// returnData = rules.rulesLibrary[value](returnData, inputMetaData);
// NEW WAY:
returnData = D['BusinessRules'][value](returnData, inputMetaData);
}
}
return returnData;
};
Any ideas? Thoughts? Edits? Rants? Am I at least on the right track?
Thank you again for your help! Hopefully this will help someone else too!! :-D
Turns out I was already doing everything correctly to begin with. It's just that console.log & JSON.stringify don't work well with a object map of functions.
The function maps do contain the function calls, just don't expect your console.log even with JSON.stringify to dump that data in any way. You have to proceed with making the call as if it is there and verify that the execution is successful by putting console logs in the function that calls the rule and additionally putting console logs in the rule that is to be executed.
It does work and it's pretty cool when it does!!
I hope this can help someone else, please comment if you have any additional questions and/or if I can provide additional solution details.
Log of successful execution:
c.ccustomEcho resolves as: customEcho
BEGIN warden.executeBusinessRule function
businessRule is: customEcho
ruleInput is: Calling Custom Echo from application
ruleMetaData is: Calling Custom Echo from application
BEGIN ruleBroker.processRules function
inputData is: "Calling Custom Echo from application"
inputMetaData is: "something-nothing"
rulesToExecute are: {"0":"customEcho"}
BEGIN clientStringParsing.customEcho function
inputData is: Calling Custom Echo from application
inputMetaData is: something-nothing
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END clientStringParsing.customEcho function
returnData is: "Calling Custom Echo from application clientStringParsing.customEcho"
END ruleBroker.processRules function
returnData is: Calling Custom Echo from application clientStringParsing.customEcho
END warden.executeBusinessRule function
Cheers
~Seth

RegEx expression into a constant variable [duplicate]

Is there a way to use constants in JavaScript?
If not, what's the common practice for specifying variables that are used as constants?
Since ES2015, JavaScript has a notion of const:
const MY_CONSTANT = "some-value";
This will work in pretty much all browsers except IE 8, 9 and 10. Some may also need strict mode enabled.
You can use var with conventions like ALL_CAPS to show that certain values should not be modified if you need to support older browsers or are working with legacy code:
var MY_CONSTANT = "some-value";
Are you trying to protect the variables against modification? If so, then you can use a module pattern:
var CONFIG = (function() {
var private = {
'MY_CONST': '1',
'ANOTHER_CONST': '2'
};
return {
get: function(name) { return private[name]; }
};
})();
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.MY_CONST = '2';
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
CONFIG.private.MY_CONST = '2'; // error
alert('MY_CONST: ' + CONFIG.get('MY_CONST')); // 1
Using this approach, the values cannot be modified. But, you have to use the get() method on CONFIG :(.
If you don't need to strictly protect the variables value, then just do as suggested and use a convention of ALL CAPS.
The const keyword is in the ECMAScript 6 draft but it thus far only enjoys a smattering of browser support: http://kangax.github.io/compat-table/es6/. The syntax is:
const CONSTANT_NAME = 0;
"use strict";
var constants = Object.freeze({
"π": 3.141592653589793 ,
"e": 2.718281828459045 ,
"i": Math.sqrt(-1)
});
constants.π; // -> 3.141592653589793
constants.π = 3; // -> TypeError: Cannot assign to read only property 'π' …
constants.π; // -> 3.141592653589793
delete constants.π; // -> TypeError: Unable to delete property.
constants.π; // -> 3.141592653589793
See Object.freeze. You can use const if you want to make the constants reference read-only as well.
IE does support constants, sort of, e.g.:
<script language="VBScript">
Const IE_CONST = True
</script>
<script type="text/javascript">
if (typeof TEST_CONST == 'undefined') {
const IE_CONST = false;
}
alert(IE_CONST);
</script>
ECMAScript 5 does introduce Object.defineProperty:
Object.defineProperty (window,'CONSTANT',{ value : 5, writable: false });
It's supported in every modern browser (as well as IE ≥ 9).
See also: Object.defineProperty in ES5?
No, not in general. Firefox implements const but I know IE doesn't.
#John points to a common naming practice for consts that has been used for years in other languages, I see no reason why you couldn't use that. Of course that doesn't mean someone will not write over the variable's value anyway. :)
In JavaScript, my preference is to use functions to return constant values.
function MY_CONSTANT() {
return "some-value";
}
alert(MY_CONSTANT());
Mozillas MDN Web Docs contain good examples and explanations about const. Excerpt:
// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;
// this will throw an error - Uncaught TypeError: Assignment to constant variable.
MY_FAV = 20;
But it is sad that IE9/10 still does not support const. And the reason it's absurd:
So, what is IE9 doing with const? So
far, our decision has been to not
support it. It isn’t yet a consensus
feature as it has never been available
on all browsers.
...
In the end, it seems like the best
long term solution for the web is to
leave it out and to wait for
standardization processes to run their
course.
They don't implement it because other browsers didn't implement it correctly?! Too afraid of making it better? Standards definitions or not, a constant is a constant: set once, never changed.
And to all the ideas: Every function can be overwritten (XSS etc.). So there is no difference in var or function(){return}. const is the only real constant.
Update:
IE11 supports const:
IE11 includes support for the well-defined and commonly used features of the emerging ECMAScript 6 standard including let, const, Map, Set, and WeakMap, as well as __proto__ for improved interoperability.
If you don't mind using functions:
var constant = function(val) {
return function() {
return val;
}
}
This approach gives you functions instead of regular variables, but it guarantees* that no one can alter the value once it's set.
a = constant(10);
a(); // 10
b = constant(20);
b(); // 20
I personally find this rather pleasant, specially after having gotten used to this pattern from knockout observables.
*Unless someone redefined the function constant before you called it
with the "new" Object api you can do something like this:
var obj = {};
Object.defineProperty(obj, 'CONSTANT', {
configurable: false
enumerable: true,
writable: false,
value: "your constant value"
});
take a look at this on the Mozilla MDN for more specifics. It's not a first level variable, as it is attached to an object, but if you have a scope, anything, you can attach it to that. this should work as well.
So for example doing this in the global scope will declare a pseudo constant value on the window (which is a really bad idea, you shouldn't declare global vars carelessly)
Object.defineProperty(this, 'constant', {
enumerable: true,
writable: false,
value: 7,
configurable: false
});
> constant
=> 7
> constant = 5
=> 7
note: assignment will give you back the assigned value in the console, but the variable's value will not change
Group constants into structures where possible:
Example, in my current game project, I have used below:
var CONST_WILD_TYPES = {
REGULAR: 'REGULAR',
EXPANDING: 'EXPANDING',
STICKY: 'STICKY',
SHIFTING: 'SHIFTING'
};
Assignment:
var wildType = CONST_WILD_TYPES.REGULAR;
Comparision:
if (wildType === CONST_WILD_TYPES.REGULAR) {
// do something here
}
More recently I am using, for comparision:
switch (wildType) {
case CONST_WILD_TYPES.REGULAR:
// do something here
break;
case CONST_WILD_TYPES.EXPANDING:
// do something here
break;
}
IE11 is with new ES6 standard that has 'const' declaration.
Above works in earlier browsers like IE8, IE9 & IE10.
Forget IE and use the const keyword.
You can easily equip your script with a mechanism for constants that can be set but not altered. An attempt to alter them will generate an error.
/* author Keith Evetts 2009 License: LGPL
anonymous function sets up:
global function SETCONST (String name, mixed value)
global function CONST (String name)
constants once set may not be altered - console error is generated
they are retrieved as CONST(name)
the object holding the constants is private and cannot be accessed from the outer script directly, only through the setter and getter provided
*/
(function(){
var constants = {};
self.SETCONST = function(name,value) {
if (typeof name !== 'string') { throw new Error('constant name is not a string'); }
if (!value) { throw new Error(' no value supplied for constant ' + name); }
else if ((name in constants) ) { throw new Error('constant ' + name + ' is already defined'); }
else {
constants[name] = value;
return true;
}
};
self.CONST = function(name) {
if (typeof name !== 'string') { throw new Error('constant name is not a string'); }
if ( name in constants ) { return constants[name]; }
else { throw new Error('constant ' + name + ' has not been defined'); }
};
}())
// ------------- demo ----------------------------
SETCONST( 'VAT', 0.175 );
alert( CONST('VAT') );
//try to alter the value of VAT
try{
SETCONST( 'VAT', 0.22 );
} catch ( exc ) {
alert (exc.message);
}
//check old value of VAT remains
alert( CONST('VAT') );
// try to get at constants object directly
constants['DODO'] = "dead bird"; // error
Yet there is no exact cross browser predefined way to do it , you can achieve it by controlling the scope of variables as showed on other answers.
But i will suggest to use name space to distinguish from other variables. this will reduce the chance of collision to minimum from other variables.
Proper namespacing like
var iw_constant={
name:'sudhanshu',
age:'23'
//all varibale come like this
}
so while using it will be iw_constant.name or iw_constant.age
You can also block adding any new key or changing any key inside iw_constant using Object.freeze method. However its not supported on legacy browser.
ex:
Object.freeze(iw_constant);
For older browser you can use polyfill for freeze method.
If you are ok with calling function following is best cross browser way to define constant. Scoping your object within a self executing function and returning a get function for your constants
ex:
var iw_constant= (function(){
var allConstant={
name:'sudhanshu',
age:'23'
//all varibale come like this
};
return function(key){
allConstant[key];
}
};
//to get the value use
iw_constant('name') or iw_constant('age')
** In both example you have to be very careful on name spacing so that your object or function shouldn't be replaced through other library.(If object or function itself wil be replaced your whole constant will go)
For a while, I specified "constants" (which still weren't actually constants) in object literals passed through to with() statements. I thought it was so clever. Here's an example:
with ({
MY_CONST : 'some really important value'
}) {
alert(MY_CONST);
}
In the past, I also have created a CONST namespace where I would put all of my constants. Again, with the overhead. Sheesh.
Now, I just do var MY_CONST = 'whatever'; to KISS.
My opinion (works only with objects).
var constants = (function(){
var a = 9;
//GLOBAL CONSTANT (through "return")
window.__defineGetter__("GCONST", function(){
return a;
});
//LOCAL CONSTANT
return {
get CONST(){
return a;
}
}
})();
constants.CONST = 8; //9
alert(constants.CONST); //9
Try! But understand - this is object, but not simple variable.
Try also just:
const a = 9;
I too have had a problem with this. And after quite a while searching for the answer and looking at all the responses by everybody, I think I've come up with a viable solution to this.
It seems that most of the answers that I've come across is using functions to hold the constants. As many of the users of the MANY forums post about, the functions can be easily over written by users on the client side. I was intrigued by Keith Evetts' answer that the constants object can not be accessed by the outside, but only from the functions on the inside.
So I came up with this solution:
Put everything inside an anonymous function so that way, the variables, objects, etc. cannot be changed by the client side. Also hide the 'real' functions by having other functions call the 'real' functions from the inside. I also thought of using functions to check if a function has been changed by a user on the client side. If the functions have been changed, change them back using variables that are 'protected' on the inside and cannot be changed.
/*Tested in: IE 9.0.8; Firefox 14.0.1; Chrome 20.0.1180.60 m; Not Tested in Safari*/
(function(){
/*The two functions _define and _access are from Keith Evetts 2009 License: LGPL (SETCONST and CONST).
They're the same just as he did them, the only things I changed are the variable names and the text
of the error messages.
*/
//object literal to hold the constants
var j = {};
/*Global function _define(String h, mixed m). I named it define to mimic the way PHP 'defines' constants.
The argument 'h' is the name of the const and has to be a string, 'm' is the value of the const and has
to exist. If there is already a property with the same name in the object holder, then we throw an error.
If not, we add the property and set the value to it. This is a 'hidden' function and the user doesn't
see any of your coding call this function. You call the _makeDef() in your code and that function calls
this function. - You can change the error messages to whatever you want them to say.
*/
self._define = function(h,m) {
if (typeof h !== 'string') { throw new Error('I don\'t know what to do.'); }
if (!m) { throw new Error('I don\'t know what to do.'); }
else if ((h in j) ) { throw new Error('We have a problem!'); }
else {
j[h] = m;
return true;
}
};
/*Global function _makeDef(String t, mixed y). I named it makeDef because we 'make the define' with this
function. The argument 't' is the name of the const and doesn't need to be all caps because I set it
to upper case within the function, 'y' is the value of the value of the const and has to exist. I
make different variables to make it harder for a user to figure out whats going on. We then call the
_define function with the two new variables. You call this function in your code to set the constant.
You can change the error message to whatever you want it to say.
*/
self._makeDef = function(t, y) {
if(!y) { throw new Error('I don\'t know what to do.'); return false; }
q = t.toUpperCase();
w = y;
_define(q, w);
};
/*Global function _getDef(String s). I named it getDef because we 'get the define' with this function. The
argument 's' is the name of the const and doesn't need to be all capse because I set it to upper case
within the function. I make a different variable to make it harder for a user to figure out whats going
on. The function returns the _access function call. I pass the new variable and the original string
along to the _access function. I do this because if a user is trying to get the value of something, if
there is an error the argument doesn't get displayed with upper case in the error message. You call this
function in your code to get the constant.
*/
self._getDef = function(s) {
z = s.toUpperCase();
return _access(z, s);
};
/*Global function _access(String g, String f). I named it access because we 'access' the constant through
this function. The argument 'g' is the name of the const and its all upper case, 'f' is also the name
of the const, but its the original string that was passed to the _getDef() function. If there is an
error, the original string, 'f', is displayed. This makes it harder for a user to figure out how the
constants are being stored. If there is a property with the same name in the object holder, we return
the constant value. If not, we check if the 'f' variable exists, if not, set it to the value of 'g' and
throw an error. This is a 'hidden' function and the user doesn't see any of your coding call this
function. You call the _getDef() function in your code and that function calls this function.
You can change the error messages to whatever you want them to say.
*/
self._access = function(g, f) {
if (typeof g !== 'string') { throw new Error('I don\'t know what to do.'); }
if ( g in j ) { return j[g]; }
else { if(!f) { f = g; } throw new Error('I don\'t know what to do. I have no idea what \''+f+'\' is.'); }
};
/*The four variables below are private and cannot be accessed from the outside script except for the
functions inside this anonymous function. These variables are strings of the four above functions and
will be used by the all-dreaded eval() function to set them back to their original if any of them should
be changed by a user trying to hack your code.
*/
var _define_func_string = "function(h,m) {"+" if (typeof h !== 'string') { throw new Error('I don\\'t know what to do.'); }"+" if (!m) { throw new Error('I don\\'t know what to do.'); }"+" else if ((h in j) ) { throw new Error('We have a problem!'); }"+" else {"+" j[h] = m;"+" return true;"+" }"+" }";
var _makeDef_func_string = "function(t, y) {"+" if(!y) { throw new Error('I don\\'t know what to do.'); return false; }"+" q = t.toUpperCase();"+" w = y;"+" _define(q, w);"+" }";
var _getDef_func_string = "function(s) {"+" z = s.toUpperCase();"+" return _access(z, s);"+" }";
var _access_func_string = "function(g, f) {"+" if (typeof g !== 'string') { throw new Error('I don\\'t know what to do.'); }"+" if ( g in j ) { return j[g]; }"+" else { if(!f) { f = g; } throw new Error('I don\\'t know what to do. I have no idea what \\''+f+'\\' is.'); }"+" }";
/*Global function _doFunctionCheck(String u). I named it doFunctionCheck because we're 'checking the functions'
The argument 'u' is the name of any of the four above function names you want to check. This function will
check if a specific line of code is inside a given function. If it is, then we do nothing, if not, then
we use the eval() function to set the function back to its original coding using the function string
variables above. This function will also throw an error depending upon the doError variable being set to true
This is a 'hidden' function and the user doesn't see any of your coding call this function. You call the
doCodeCheck() function and that function calls this function. - You can change the error messages to
whatever you want them to say.
*/
self._doFunctionCheck = function(u) {
var errMsg = 'We have a BIG problem! You\'ve changed my code.';
var doError = true;
d = u;
switch(d.toLowerCase())
{
case "_getdef":
if(_getDef.toString().indexOf("z = s.toUpperCase();") != -1) { /*do nothing*/ }
else { eval("_getDef = "+_getDef_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_makedef":
if(_makeDef.toString().indexOf("q = t.toUpperCase();") != -1) { /*do nothing*/ }
else { eval("_makeDef = "+_makeDef_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_define":
if(_define.toString().indexOf("else if((h in j) ) {") != -1) { /*do nothing*/ }
else { eval("_define = "+_define_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
case "_access":
if(_access.toString().indexOf("else { if(!f) { f = g; }") != -1) { /*do nothing*/ }
else { eval("_access = "+_access_func_string); if(doError === true) { throw new Error(errMsg); } }
break;
default:
if(doError === true) { throw new Error('I don\'t know what to do.'); }
}
};
/*Global function _doCodeCheck(String v). I named it doCodeCheck because we're 'doing a code check'. The argument
'v' is the name of one of the first four functions in this script that you want to check. I make a different
variable to make it harder for a user to figure out whats going on. You call this function in your code to check
if any of the functions has been changed by the user.
*/
self._doCodeCheck = function(v) {
l = v;
_doFunctionCheck(l);
};
}())
It also seems that security is really a problem and there is not way to 'hide' you programming from the client side. A good idea for me is to compress your code so that it is really hard for anyone, including you, the programmer, to read and understand it. There is a site you can go to: http://javascriptcompressor.com/. (This is not my site, don't worry I'm not advertising.) This is a site that will let you compress and obfuscate Javascript code for free.
Copy all the code in the above script and paste it into the top textarea on the javascriptcompressor.com page.
Check the Base62 encode checkbox, check the Shrink Variables checkbox.
Press the Compress button.
Paste and save it all in a .js file and add it to your page in the head of your page.
Clearly this shows the need for a standardized cross-browser const keyword.
But for now:
var myconst = value;
or
Object['myconst'] = value;
Both seem sufficient and anything else is like shooting a fly with a bazooka.
I use const instead of var in my Greasemonkey scripts, but it is because they will run only on Firefox...
Name convention can be indeed the way to go, too (I do both!).
In JavaScript my practice has been to avoid constants as much as I can and use strings instead. Problems with constants appear when you want to expose your constants to the outside world:
For example one could implement the following Date API:
date.add(5, MyModule.Date.DAY).add(12, MyModule.Date.HOUR)
But it's much shorter and more natural to simply write:
date.add(5, "days").add(12, "hours")
This way "days" and "hours" really act like constants, because you can't change from the outside how many seconds "hours" represents. But it's easy to overwrite MyModule.Date.HOUR.
This kind of approach will also aid in debugging. If Firebug tells you action === 18 it's pretty hard to figure out what it means, but when you see action === "save" then it's immediately clear.
Okay, this is ugly, but it gives me a constant in Firefox and Chromium, an inconstant constant (WTF?) in Safari and Opera, and a variable in IE.
Of course eval() is evil, but without it, IE throws an error, preventing scripts from running.
Safari and Opera support the const keyword, but you can change the const's value.
In this example, server-side code is writing JavaScript to the page, replacing {0} with a value.
try{
// i can haz const?
eval("const FOO='{0}';");
// for reals?
var original=FOO;
try{
FOO='?NO!';
}catch(err1){
// no err from Firefox/Chrome - fails silently
alert('err1 '+err1);
}
alert('const '+FOO);
if(FOO=='?NO!'){
// changed in Sf/Op - set back to original value
FOO=original;
}
}catch(err2){
// IE fail
alert('err2 '+err2);
// set var (no var keyword - Chrome/Firefox complain about redefining const)
FOO='{0}';
alert('var '+FOO);
}
alert('FOO '+FOO);
What is this good for? Not much, since it's not cross-browser. At best, maybe a little peace of mind that at least some browsers won't let bookmarklets or third-party script modify the value.
Tested with Firefox 2, 3, 3.6, 4, Iron 8, Chrome 10, 12, Opera 11, Safari 5, IE 6, 9.
If it is worth mentioning, you can define constants in angular using $provide.constant()
angularApp.constant('YOUR_CONSTANT', 'value');
An improved version of Burke's answer that lets you do CONFIG.MY_CONST instead of CONFIG.get('MY_CONST').
It requires IE9+ or a real web browser.
var CONFIG = (function() {
var constants = {
'MY_CONST': 1,
'ANOTHER_CONST': 2
};
var result = {};
for (var n in constants)
if (constants.hasOwnProperty(n))
Object.defineProperty(result, n, { value: constants[n] });
return result;
}());
* The properties are read-only, only if the initial values are immutable.
JavaScript ES6 (re-)introduced the const keyword which is supported in all major browsers.
Variables declared via const cannot be re-declared or re-assigned.
Apart from that, const behaves similar to let.
It behaves as expected for primitive datatypes (Boolean, Null, Undefined, Number, String, Symbol):
const x = 1;
x = 2;
console.log(x); // 1 ...as expected, re-assigning fails
Attention: Be aware of the pitfalls regarding objects:
const o = {x: 1};
o = {x: 2};
console.log(o); // {x: 1} ...as expected, re-assigning fails
o.x = 2;
console.log(o); // {x: 2} !!! const does not make objects immutable!
const a = [];
a = [1];
console.log(a); // 1 ...as expected, re-assigning fails
a.push(1);
console.log(a); // [1] !!! const does not make objects immutable
If you really need an immutable and absolutely constant object: Just use const ALL_CAPS to make your intention clear. It is a good convention to follow for all const declarations anyway, so just rely on it.
Another alternative is something like:
var constants = {
MY_CONSTANT : "myconstant",
SOMETHING_ELSE : 123
}
, constantMap = new function ConstantMap() {};
for(var c in constants) {
!function(cKey) {
Object.defineProperty(constantMap, cKey, {
enumerable : true,
get : function(name) { return constants[cKey]; }
})
}(c);
}
Then simply: var foo = constantMap.MY_CONSTANT
If you were to constantMap.MY_CONSTANT = "bar" it would have no effect as we're trying to use an assignment operator with a getter, hence constantMap.MY_CONSTANT === "myconstant" would remain true.
in Javascript already exists constants. You define a constant like this:
const name1 = value;
This cannot change through reassignment.
The keyword 'const' was proposed earlier and now it has been officially included in ES6. By using the const keyword, you can pass a value/string that will act as an immutable string.
Introducing constants into JavaScript is at best a hack.
A nice way of making persistent and globally accessible values in JavaScript would be declaring an object literal with some "read-only" properties like this:
my={get constant1(){return "constant 1"},
get constant2(){return "constant 2"},
get constant3(){return "constant 3"},
get constantN(){return "constant N"}
}
you'll have all your constants grouped in one single "my" accessory object where you can look for your stored values or anything else you may have decided to put there for that matter. Now let's test if it works:
my.constant1; >> "constant 1"
my.constant1 = "new constant 1";
my.constant1; >> "constant 1"
As we can see, the "my.constant1" property has preserved its original value. You've made yourself some nice 'green' temporary constants...
But of course this will only guard you from accidentally modifying, altering, nullifying, or emptying your property constant value with a direct access as in the given example.
Otherwise I still think that constants are for dummies.
And I still think that exchanging your great freedom for a small corner of deceptive security is the worst trade possible.
Rhino.js implements const in addition to what was mentioned above.

In a custom widget, inside a validation handler of addMethod(), I have a wrong context (this)

I'm creating a custom combobox which uses jQuery validator.
At first they all are gray except the first (it means Country). When I choose 'Slovenská republika' the second combobox is enabled.
They all are instances of a a custom autocomplete combobox widget.
To enable the validation I use this code (which is called within _create: function(){..})
There you can find $.validator.addClassRules(); and $.validator.addMethod(). I also added the appropriate class so it really does something.
_registerCustomValidator: function(){
var uniqueName = this._getUniqueInstanceNameFromThisID(this.id);
var that = this;
console.log(this.id);//this prints 5 unique ids when the page is being loaded
$.validator.addMethod(uniqueName, function(value,element){
if(!that.options.allowOtherValue){
return that.valid;
}
console.log(that.id);//this always prints the ID of the last combobox StreetName
return true;
}, "Error message.");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
//this.id is my own property that I set in _create
Problem: When I change the value of any instance of combobox, it always prints the ID of the last instance StreetName, but it should belong to the one that has been changed.
I thought it might be because of registering $.validator.addMethod("someName",handler) using such a fixed string, so now I pass a uniqueName, but the problem remains.
Therefore the validation of all instances is based on the property allowOtherValue of the last instance.
I don't understand why it behaves so. Does anyone see what might be the problem?
EDIT:
see my comments in the following code
_registerCustomValidator is a custom function within a widget factory.
//somewhere a global var
var InstanceRegistry = [undefined];
//inside a widget factory
_registerCustomValidator: function(){
var i=0;
while(InstanceRegistry[i] !== undefined) ++i;
InstanceRegistry[i] = this.id;
InstanceRegistry[i+1] = undefined;
var ID = i; //here ID,i,InstanceRegistry are correct
$.validator.addMethod(uniqueName, function(value,element){
//here InstanceRegistry contains different values at different positions, so its correct
console.log("ID=="+ID);//ID is always 5 like keeping only the last assiged value.
var that = InstanceRegistry[ID];
if(!that.options.allowOtherValue){
return that.valid;
}
return true;
}, "Error message");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
It looks like a sneaky combination of closure logic and reference logic. The callback in $.validator.addMethod is enclosing a reference to this which will equal the last value of this when $.validator.addMethod. (Or something like that?)
Glancing at your code, it's not clear to me what this is in this context. So I can't really offer a concrete solution. But one solution might be to create some kind of global registry for your thises. Then you could do something along the lines of:
_registerCustomValidator: function(){
var uniqueName = this._getUniqueInstanceNameFromThisID(this.id);
$.validator.addMethod(uniqueName, function(value,element) {
var instance = InstanceRegistry[uniqueName];
if(! instance.options.allowOtherValue){
return instance.valid;
}
return true;
}, "Error message.");
var o = JSON.parse('{"'+uniqueName+'":"true"}');
$.validator.addClassRules("select-validator", o);
}
The registry could be keyed to uniqueName or id, just so long as it is a value getting enclosed in your callback.

Alternatives to deep nesting functions javascript

I've been trying to organize code in a javascript project and have ended up with a bunch of nested functions. Supposedly that's bad practice, and I know it affects performance, but I'm having trouble coming up with an alternative. Here's an example of what I'm trying to do:
Code before nesting:
function Level1(dep1, dep2, dep3, dep4){
var tempResult1 = dep1 + dep2;
var tempResult2 = tempResult1/2;
var tempResult3 = dep3 + dep4;
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
What it looks like after I try to separate responsibilities into a hierarchy:
function Level1(dep1, dep2, dep3, dep4){
var tempResult2 = getTempResult2(dep1, dep2);
var tempResult3 = getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
function getTempResult2(dep1, dep2){
var tempResult1 = getTempResult1(dep1, dep2);
return tempResult1/2;
function getTempResult1(dep1, dep2){
return dep1 + dep2;
}
}
function getTempResult3(dep3, dep4){
return dep3 + dep4;
}
}
Obviously for the operations used here, functions are a bit excessive, but it does help make the ones in my project a lot more manageable. I'm unfamiliar with any other way to do this, as this is my first javascript project. The suggestions I found on here only dealt with 1 level of nested functions, not 2, and I didn't see any good examples of how to implement nested scoping. If someone could give me an example of a way to accomplish the organization I'm looking for here, I'd be very greatful. Thanks.
have ended up with a bunch of nested functions
You can simply unnest them, since they're not used as closures (you pass everything necessary as arguments). You will even get a little performance advantage by not creating a local function object every time the outer function is called (which is well optimized though and probably negligible).
I just read a bunch about how nested functions were bad practice
Notice that sometimes nested functions are necessary, when you want to create a closure.
I don't like the fact that getTempResult1, 2, and 3 are accessible outside of Level1, or that getTempResult1 is accessible outside of getTempResult2.
You could use an IEFE to create an extra scope from which only Level1 is exported:
var Level1 = (function() {
function Level1(dep1, dep2, dep3, dep4) {
var tempResult2 = getTempResult2(dep1, dep2);
var tempResult3 = getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
var getTemptResult2 = (function() {
function getTempResult2(dep1, dep2) {
var tempResult1 = getTempResult1(dep1, dep2);
return tempResult1/2;
}
function getTempResult1(dep1, dep2) {
return dep1 + dep2;
}
return getTempResult2;
})();
function getTempResult3(dep3, dep4) {
return dep3 + dep4;
}
return Level1;
}());
Maybe this is what you want:
function Level1(dep1, dep2, dep3, dep4){
var tempResult2 = Level1.getTempResult2(dep1, dep2);
var tempResult3 = Level1.getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
Level1.getTempResult2 = function (dep1, dep2) {
var tempResult1 = Level1.getTempResult2.getTempResult1(dep1, dep2);
return tempResult1/2;
}
Level1.getTempResult2.getTempResult1 = function (dep1, dep2){
return dep1 + dep2;
}
Level1.getTempResult3 = function (dep3, dep4){
return dep3 + dep4;
}
Currently I tried
function a(val1, val2) { return a.foo(val1, val2) }
a.foo = function (x,y) { return x + y }
in my browser. The command a(1,2) prints 3 as aspected. Other example:
function a() { return a.foo(1,2) }
a.foo = function (x,y) { return a.foo.bar(x,y) }
a.foo.bar = function (x,y) { return x+y }
a(1,2) // -> 3
This is a design question. Since a good and elegant design depends always on quite a number of aspects of your problem domain, it is impossible from the simplified code in your question to really estimate what the best solution would be. I'll try to show you some options which in each case address ways to do data hiding and avoid nested functions or functions that are created multiple times.
Since you ask for data hiding and keeping getTempResult1 hidden from anything other than getTempResult2, I will assume that each of these functions are reasonably complex and might be written by different people, and you want to keep the internals hidden. That warrants creating a different class for each of these rather than just a function.
I will substitute your example code with a more tangible example and use a proper OOP approach to solve the problem. Let's say you are building an e-commerce application. Level1 will be an invoice class, and dep1-4 might be things like: purchase price, profit rate, discount rate, tax rate. We will make a very simple application which will calculate: purchase price - discount + profit + taxes = total price
I hope this ressembles your problem faithfully enough so you can appreciate some of the OOP techniques used (it's still way overkill in structure for the calculations done, but it's a lesson in OOP and allows for a great deal in scalability should the problem domain get more complex in the future, say you go international and must calculate taxes for different countries etc).
I will use the OoJs library to be able to do proper OOP in JavaScript. See the code below working on jsfiddle.
The idea of an ecommerce app is inspired from the book "Dessign patterns explained" by Shalloway and Trott
In conclusion you will find that this solution:
hides implementation details
there are no nested functions
every function is created only once
is scalable and maintainable and flexible in case of changing
requirements
So the code using our classes will look as follows:
// Create your namespace to avoid polluting global
//
var eComm = eComm || {}
// this will be some factory code which will return the needed objects, it won't actually use them.
// Normally this should be a class living in our eComm namespace
//
function factory( db, clientID )
{
// we would assume here that the hardcoded rates would be found in the database using the client id.
//
var discount = new eComm.Discount( 5 ) // in %
var profit = new eComm.Profit ( 20, discount ) // in %
var taxRate = new eComm.TaxRate ( 5 , profit ) // in %
// note that I use a simple aggragation approach, because I don't know the
// actual complexity of your problem domain. It makes this very simple ecommerce
// code not entirely ideal. If we would just perform a chain of operations on
// a number, other design patterns would be more suited, like a decorator.
// It is not appropriate to just pass taxRate to Invoice, because it is no different
// than profit or discount, it just comes later in a chain of calculations.
// I have taken this approach to show that it is possible to hide steps of the
// implementation down a hierarchy.
//
return new eComm.Invoice( taxRate )
}
// now when we will actually use it, it looks like this
// wrapped it in a function call because on global scope
// we would have to put this entirely at the bottom
// if you put all your code in classes you don't have this
// problem. They can occur in any order
//
function usage()
{
var invoice = factory( "database", 1654 /* the client id */ )
invoice.addPurchase( 1574 ) // price in some currency
invoice.addPurchase( 1200 ) // a second purchase
// in reality you would probably also pass an object representing an output
// device to Invoice (a printer, or a pdf generator, ...)
//
console.log( invoice.total() )
}
The actual classes. It looks long, but that's because the less they do, the bigger the overhead (relatively speaking). I ommit more and more code as we go down for brevity as the classes all look very much alike.
;( function class_Invoice( namespace )
{
'use strict'; // recommended
if( namespace[ "Invoice" ] ) return // protect against double inclusions
namespace.Invoice = Invoice
var Static = OoJs.setupClass( namespace, "Invoice" )
// constructor
//
function Invoice( taxRate )
{
// should do validation as javascript is loosely typed
//
if( "TaxRate" !== OoJs.typeOf( taxRate ) )
;// throw an error
// Data members
//
this.taxRate = taxRate
this.totalPrice = 0
this.Protected( "taxRate", "totalPrice" ) // if you want them available to subclasses
var iFace = this.Public( total, addPurchase ) // make these methods public
return iFace
}
// all your method definitions go here
//
function addPurchase( price )
{
this.totalPrice += this.taxRate.calculate( price )
}
function total()
{
return this.totalPrice
}
})( eComm )
;( function class_TaxRate( namespace )
{
namespace.TaxRate = TaxRate
var Static = OoJs.setupClass( namespace, "TaxRate" )
// constructor
//
function TaxRate( rate, profit )
{
// do your validation on profit and rate as above
this.rate = rate
this.profit = profit
this.Protected( "profit" ) // if you want
return this.Public( calculate )
}
function calculate( price )
{
return this.profit.calculate( price ) * ( 1 + this.rate / 100 )
}
})( eComm )
;( function class_Profit( namespace )
{
namespace.Profit = Profit
var Static = OoJs.setupClass( namespace, "Profit" )
// constructor
//
function Profit( rate, discount )
{
this.rate = rate
this.discount = discount
return this.Public( calculate )
}
function calculate( price )
{
return this.discount.calculate( price ) * ( 1 + this.rate / 100 )
}
})( eComm )
;( function class_Discount( namespace )
{
namespace.Discount = Discount
var Static = OoJs.setupClass( namespace, "Discount" )
// constructor
//
function Discount( rate )
{
this.rate = rate
return this.Public( calculate )
}
function calculate( price )
{
return price - price * this.rate / 100
}
})( eComm )
usage()
you don't need to worry about the call stack getting a few levels deep.
this is an example of premature optimization
Try looking at the step module, which is intended for node.js. I use it all the time.
However, you might be to use the step.js script even outside of the node.js environment (note: I have not tested this). At the very least, it shows how you can flatten any number of levels of nesting.
I know this is already answered but I thought I would leave you with some additional resources to help you on this adventure. I think this is a perfect time for you to look deeper into javascript design patterns.
Learning JavaScript Design Patterns by Addy Osmani is a fantastic read / resource to learn about multiple patterns for creating javascript applications, creating reusable code, closures etc. Anyone who is having this internal disscussion on how to better organize my nested functions / scope, etc should read it.
Here is an example snippet from his article regarding The Factory Pattern
// Types.js - Constructors used behind the scenes
// A constructor for defining new cars
function Car( options ) {
// some defaults
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
// A constructor for defining new trucks
function Truck( options){
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
// FactoryExample.js
// Define a skeleton vehicle factory
function VehicleFactory() {}
// Define the prototypes and utilities for this factory
// Our default vehicleClass is Car
VehicleFactory.prototype.vehicleClass = Car;
// Our Factory method for creating new Vehicle instances
VehicleFactory.prototype.createVehicle = function ( options ) {
switch(options.vehicleType){
case "car":
this.vehicleClass = Car;
break;
case "truck":
this.vehicleClass = Truck;
break;
//defaults to VehicleFactory.prototype.vehicleClass (Car)
}
return new this.vehicleClass( options );
};
// Create an instance of our factory that makes cars
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
vehicleType: "car",
color: "yellow",
doors: 6 } );
// Test to confirm our car was created using the vehicleClass/prototype Car
// Outputs: true
console.log( car instanceof Car );
// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );
Hope this article helps you and others looking for similar answers.
It's a good idea to have a function implement as less as possible for optimal re use. For example:
function doChores(){
//actually wash the dishes
//actually walk the dog.
}
Now let's say it's raining and I only want to wash the dishes, since washing the dishes is implemented in doChores I can't call it without walking the dog. Here is how it should be done:
function doChores(){
walkTheDog();
washTheDishes();
}
The function walkTheDog implements walking the dog and washTheDishes implements washing the dishes so they can be called sperately.
The problem you're facing is when you pass variables to a chain of functions. I usually pass one argument to a function and that argument contains an object with the needed parameters. Every function can read or mutate members of the passed object that they are concerned with. If at a later time you need to add more arguments then you don't need to change the signature of your funciton (for example function(arg1, arg2, newArg)) you'll always have function(args)
More info about the parameter passing can be found here: https://stackoverflow.com/a/16063711/1641941 under Passing (constructor) arguments

Replace js namespaced global variable with js closure

I have some shared code in a single-page web application that is currently using a "globals" namespace to store a parameter as a global variable.
Using a namespace is an improvement over polluting the global "window" object, but it seems like this code is a good candidate for a closure to persist the value between invocations. I've messed around with some ideas but can't seem to get the syntax for a closure right.
Here's pseudo-code for the current version. All the code lives inside a "um" namespace. When my shared function is initially called by a new virtual page in my app, I need to store the contents of a JS object called 'extraData'. Subsequent invocations of the function don't have access to 'extraData', so I'm currently storing it in "um.globals.extraData" if underscore.js determines that the parameter is an object.
//***************************
// IMPLEMENTATION SAMPLE
//***************************
// Define namespaces (not showing: um.grid, um.ajax, um.classes, um.constants, etc.)
window.um = window.um || {};
um.globals = um.globals || {}; /* container for namespaced 'global' variables */
um.grid.loadOrUpdate = function (iOffset, isUpdate, extra) {
var ajaxParams = new um.classes.AjaxParams();
//-----
// If 'extra' is an object, store it in a global for subsequent invocations
if (_.isObject(extra)) {
// This seems like it could be a closure candidate...
um.globals.extraData = extra;
}
ajaxParams.values = [um.constants.urlPathParams.grid];
ajaxParams.verb = um.constants.httpVerbs.GET;
// Use the global variable 'extraData'
ajaxParams.extraData = um.globals.extraData;
um.ajax.callMessaging(ajaxParams);
};
And here's some pseudo-code for actually invoking the function:
//***************************
// INVOCATION SAMPLES
//***************************
// 1st invocation from virtual page 'Alpha'
um.grid.loadOrUpdate(0, false, { "alpha-key": "alpha-value" });
// 2nd invocation from virtual page 'Alpha'
um.grid.loadOrUpdate(1, true); // will re-use the "alpha" object
// 1st invocation from virtual page "Beta'
um.grid.loadOrUpdate(0, false, { "beta-key": "beta-value" });
// 2nd invocation from virtual page 'Beta'
um.grid.loadOrUpdate(1, true); // will re-use the "beta" object
How can I kill um.globals.extraData and replace this with some kind of closure inside of um.grid.loadOrUpdate?
EDIT
Here's some code from "JavaScript Patterns" that prompted me to ask this question:
var setup = function () {
var count = 0;
return function () {
return (count += 1);
}
};
// usage
var next = setup();
next(); // returns 1
next(); // returns 2
next(); // returns 3
To me, it's unclear what you're trying to achieve through closures. Closures allow you to encapsulate the state of variables within the current scope, which might be handy if you were trying to create various instances of your object, each with their own extra state.
You could do this by implementing loadOrUpdate in such a way that returns a reference to a function that can be called later. When said function is called, all the variables within that scope will be enclosed and retain the values from when the function was created.
For example:
um.grid.loadOrUpdate = function (iOffset, extra) {
var ajaxParams = new um.classes.AjaxParams();
//-----
ajaxParams.values = [um.constants.urlPathParams.grid];
ajaxParams.verb = um.constants.httpVerbs.GET;
um.ajax.callMessaging(ajaxParams);
// Return a function used to update this data later
return function (newOffset) // Update function
{
// From within here, you'll have access to iOffset and extra as they exist at this point
window.alert("Key: " + extra.key + " - Changing offset from " + iOffset + " to " + newOffset);
iOffset = newOffset;
};
};
You can then invoke your function like so, keeping in mind it will return a reference to a function:
var alpha = um.grid.loadOrUpdate(0, { "key": "alpha-value" });
var beta = um.grid.loadOrUpdate(0, { "key": "beta-value" });
When you call alpha() or beta(), the value of extra will be retained through a closure, thus there is no need to keep a global reference to it.
alpha(1); // Update from 0 to 1
alpha(2); // Update from 1 to 2
beta(3); // Update from 0 to 3
beta(4); // Update from 3 to 4
Example
However, if you're attempting to keep a single instance of extra that all calls to loadOrUpdate share, you'd probably be better off using your previous technique and just storing that current value as a property of the function itself, or anywhere else within the scope of that function.
Is this kind of approach what you're after?
var ns = {};
(function() {
var globals;
ns.func = function(update,opts) {
if(update)opts=globals;
else globals=opts;
console.log(opts);
}
})();
ns.func(false,"a");
ns.func(true);
ns.func(false,"b");
ns.func(true);
Output:
a
a
b
b
I've scoped the globals variable inside an anonymous function, and made a function declared in that function available on an object in the surrounding (in this case window) scope - so it has access to the 'globals' variable but it's not visible outside it.

Categories