How to use a Javascript Function to name Variables? - javascript

I'd like to be able to create variables using a function, something like:
function createVar(a,b){
var [a]name[b];
}
So if I call the function createVar(prefix,suffix) I'd end up with a variable named prefixnamesuffix.

You can't create a local variable that way, but you can create properties with strings.
function createVar(obj, a, b)
{
obj[a+'name'+b] = foo;
}

function createVar(a, b, value) {
// declare the variable on current context(default is window),
// and set value, default is undefined
this[a + 'name' + b] = value;
}
use as:
createVar('a', 'b');
// variable anameb now is declare, but it's value is undefined
console.log(anameb); // -> undefined
createVar('prefix', 'suffix', 'optional');
// variable prefixnamesuffix now is exist in window
console.log(prefixnamesuffix); // -> 'optional'
or:
var obj = {};
createVar.call(obj, 'pre', 'suf', 'defValue');
// variable prenamesuf is now exist in obj, but not exist in window
console.log(obj.prenamesuf); // -> 'defValue'
console.log(prenamesuf); // ReferenceError: prenamesuf is not defined

This IS possible - sort of as it IS a bit tricky.
This all begins by understanding the scope of a variable. Let's look at a basic, simple example:
var myvar = 'I see';
This creates a varaible, at a basic level named myvar that you can access such as alert(myvar); which will, in this case alert "I see".
What this really does is create a property on the window object. Thus, var myvar = 'I see'; is the same as window['myvar'] = 'I see';.
Complex objects can also be created in this manner.
Some more examples:
window['fred'] = 'howdy fred';// create fred property
var regularfred = 'howdy fred'; // create regularfred property
window['town'] = {}; // create town object
window['town']['george'] = 'georgetown'; //create town.george property
alert(fred + ":" + regularfred); // alerts "howdy fred:howdy fred"
alert(fred == regularfred);// alerts true
alert(this['town']['george']);// alerts "georgetown"
function createvar(a, b) {
this[a + 'name' + b] = "fredling";
alert(this[a + 'name' + b]);// alerts "fredling"
alert(window[a + 'name' + b]);// alerts "fredling"
}
var hi = 'hi';
var lo = 'loook';
createvar(hi, lo);
alert(this[hi + 'name' + lo]);// alerts "fredling"
Requisit working example on this: http://jsfiddle.net/pGWZN/

Related

confusing use of commas and newlines in variable assignment expression makes var look global

Update: it was really the comma before the that variable assignment which threw me off, not so much about any patterns. (don't use this notation. see https://stackoverflow.com/a/38893132/244811 for more information)
So I was reading this article about Javascript's inheritance mechanisms, one of which is the "functional inheritance" pattern. The code example given (my //wtf's):
var vehicle = function(attrs) {
var _privateObj = {
hasEngine: true
},
that = {}; //wtf??
that.name = attrs.name || null;
that.engineSize = attrs.engineSize || null;
that.hasEngine = function () {
alert('This ' + that.name + ' has an engine: ' + _privateObj.hasEngine);
};
return that;
}
var motorbike = function () {
// private
var _privateObj = {
numWheels: 2
},
// inherit
that = vehicle({
name: 'Motorbike',
engineSize: 'Small'
}); //wtf??
// public
that.totalNumWheels = function () {
alert('This Motobike has ' + _privateObj.numWheels + ' wheels');
};
that.increaseWheels = function () {
_privateObj.numWheels++;
};
return that;
};
var boat = function () {
// inherit
that = vehicle({
name: 'Boat',
engineSize: 'Large'
}); //wtf??
return that;
};
myBoat = boat();
myBoat.hasEngine(); // This Boat has an engine: true
alert(myBoat.engineSize); // Large
myMotorbike = motorbike();
myMotorbike.hasEngine(); // This Motorbike has an engine: true
myMotorbike.increaseWheels();
myMotorbike.totalNumWheels(); // This Motorbike has 3 wheels
alert(myMotorbike.engineSize); // Small
myMotorbike2 = motorbike();
myMotorbike2.totalNumWheels(); // This Motorbike has 2 wheels
myMotorbike._privateObj.numWheels = 0; // undefined
myBoat.totalNumWheels(); // undefined
with the conclusion:
You can see that it is fairly easy to provide encapsulation. The
_privateObj can not be modified from outside of the object, unless exposed by a public method like increaseWheels(). Similarly, private
values can also only be read when exposed by a public method, such as
motorbike’s totalNumWheels() function.
Each and every function here seems to declare a global variable "that", which you should never do - right? There are no closures that I can see (inner function has access to whatever variables were in scope at the time of the inner function's declaration). Is there a closure mechanism I'm missing? Does this code illustrate a valid pattern?
They aren't declaring global variables, they're declaring closure variables. Every function definition you attach to that is a closure (provided it uses a variable from the surrounding scope).
Example:
function createObj() {
var that = {}; // Not global but will be used in a closure
that.name = 'Bob';
that.doSomething = function() {
return that.name; // Used as a closure variable
};
return that; // Return a new object, not a global one
}
They're applying the same principle except they're also creating a separate object, _privateObj which is never directly exposed. This lets you have private data and methods which no one else can access.
You might think they're declaring a global due to the different syntax for declaring multiple variables.
This:
var a = 1,
b = 2;
is equivalent to this:
var a = 1;
var b = 2;
Notice the use of the , in the previous example. That allows you to declare multiple variables in a single var statement.
Your //wtf's code means:
var that = new Object();

Unexpected behavior using getters and setters

Look this code:
<script>
function dbg (object) {
var _string = "";
for (var a in object) {
_string += a + ":\n";
for (var b in object[a])
if (/^get_/.test (b))
_string += "\t" + b + " - " + object[a][b] () + "\n";
}
return _string;
}
function Order () {
var products = [];
this.get_products = function () {return products;}
this.set_products = function (_products) {products = _products;}
}
function Product () {
var id = null;
var name = null;
this.get_id = function () {return id;}
this.get_name = function () {return name;}
this.set_id = function (_id) {id = _id;}
this.set_name = function (_name) {name = _name}
}
var order = new Order ();
var product = new Product ();
product.set_id (1);
product.set_name ("Banana");
order.set_products (order.get_products ().concat (product));
alert (dbg (order.get_products ())); // Ok
product.set_id (2);
product.set_name ("Orange");
order.set_products (order.get_products ().concat (product));
alert (dbg (order.get_products ())); // Duplicated values! What?
</script>
The first time you push the object "Product" into the object "Order", everything looks fine.
When you set new values to the object "Product", the object itself overwrites the previous values of the object "Order". The final result is a array of duplicated values. Is it normal ? Is there a workaround? Just tried everything I knew without success. Thanks.
Crazy Train has already answered it in the comments. The question is listed having 0 answers so I'll add it as an answer.
When adding a variable containing an object to an array you add a reference to the variable, when you re assign the variable the reference is broken.
Adding a variable containing an object to an array then re assigning the variable doesn't change the object in the array:
var arr=[];
var object={name:"John"};
arr.push(object);
object=33;
console.log(arr);//=[Object {name="john"}]
Adding a variable containing an object to an array then changing the internal values of the object that the variable contains does change the object in the array:
var arr=[];
var object={name:"John"};
arr.push(object);
object.name="Jane";
console.log(arr);//=[Object {name="Jane"}]
So to correct your code you could do the following:
Create a new variable for the product to be added:
var product2=new Product();
product2.set_id (2);
product2.set_name ("Orange");
order.set_products (order.get_products ().concat (product2));
Or break the reference between your product variable and the products array in order:
product=null;//product has no ref to order.products
product=new Product();
product.set_id (2);
product.set_name ("Orange");
order.set_products (order.get_products ().concat (product));
I would not define members of an object in a constructor function with var as JavaScript doesn't support private members. You can simulate them by creating closures but that has it's own problem when you have instance specific privates (as is your case). You can't use prototype if the functions need to access private instance variables, you can't clone it unless you have public accesssors, inheritance and overriding functions will be a pain.
Here is some more info on using constructor functions.
If you have Chrome or Firefox (with Firebug) then you can press F12 to open the console. You an detach the console window (have it's own window) then copy code in the before mentioned answers and paste them in the commandline of the console. There you can run and re run the code, change and see the output to better understand JS behavior.
You are just overriding the variables in object. I'd do it like this, much simpler:
var products = {
set : function(name,id) {
products.list.push({name:name,id:id});
},
get : function(id) {
var r;
if(typeof id === 'number'){
products.list.forEach(function(e,i){ if(e.id==id) r= products.list[i];});
} else {
products.list.forEach(function(e,i){ if(e.name==id) r = products.list[i];});
}
return r;
},
list : []
};
var order={
set : function(p) {
order.list[p.id]=p;
},
get : function(id) {
return order.list[id];
},
delete : function(id) {
return delete order.list[id];
},
list : {}
};
then you can do this
products.set('apple',34);
products.set('orange',4);
products.set('mango',1);
var x = products.get(1);
var y = products.get('orange');
order.set(x);
order.set(y);
working demo:
http://jsfiddle.net/techsin/tjDVv/2/

JavaScript - String.newProperty vs. String.prototype.newProperty?

In the code snippet at http://jsfiddle.net/javascriptenlightenment/QvbDw/, the author augments the builtin String object constructor with 2 new properties - an array property and a function property.
I notice that for the new array property, he did this:
String.newArrayProperty = [];
// Q1: Why not String.prototype.newArrayProperty = []; ?
But for the new function property, he did this:
String.prototype.newFunctionProperty = function() {...};
// Q2: Why not String.newFunctionProperty = function() {...}; ?
What's the difference between String.newProperty and String.prototype.newProperty?
String.newProperty adds a new propery to the String native function, but that property is in no way inherited by the strings it generates, while String.prototype.newProperty adds that new property to all the strings it generates, but not to the native function itself.
String.property just ads the propery to String class as to an object, String.prototype.property adds this property to all instances of this class.
function F() {
}
F.p1 = function () { console.log('F.p1'); } ;
F.prototype.p2 = function () { console.log('F.prototype.p2'); } ;
F.p1(); // 'F.p1'
F.p2(); // error
new F().p1(); // error
new F().p2(); // 'F.prototype.p2'
Also look at:
How does JavaScript .prototype work?
http://www.w3schools.com/jsref/jsref_prototype_math.asp
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/prototype
A method, assigned to the prototype of String can be applied to all instances of String. A method assigned to the String constructor has to be called as a static method with a string as parameter. If the method is in the prototype, within it, this refers to the string instance.
So:
String.prototype.insertLineNr = function(nr){return (nr||1) + ': ' +this;};
// ^instance
String.insertLineNo = function(str,nr){return (nr||1) + ': ' +str;};
var str = 'Some line to be numbered';
//apply to instance
console.log(str.insertLineNr(5); //=> '5: Some line to be numbered'
//can't apply direct String method to instance
console.log(str.insertLineNo(str,5)); //=> TypeError
//Run String method
console.log(String.insertLineNo(str,5); //=> '5: Some line to be numbered'
If the method name is equal, you can have the best of both worlds:
function insrtNr(str,nr){ return (nr||1) + ': ' + str || this;};
String.insertLineNr = insrtNr;
String.prototype.insertLineNr = insrtNr;

Specify scope for eval() in JavaScript?

is there any way I can execute eval() on a specific scope (but NOT global)?
for example, the following code doesn't work (a is undefined on the second statement) because they are on different scope:
eval(var a = 1);
eval(alert(a));
If possible, I would like to create a scope on the fly. for example (the syntax is definitely wrong, but just to illustrate the idea)
var scope1;
var scope2;
with scope1{
eval(var a = 1); eval(alert(a)); // this will alert 1
}
with scope2{
eval(var a = 1); eval(a++); eval(alert(a)); // this will alert 2
}
with scope1{
eval(a += 2); eval(alert(a)); // this will alert 3 because a is already defined in scope1
}
Any idea on how to achieve something like this? Thanks!
you can use the "use strict" to contain the eval'ed code within the eval itself.
Second, eval of strict mode code does not introduce new variables into the surrounding scope. In normal code eval("var x;") introduces a variable x into the surrounding function or the global scope. This means that, in general, in a function containing a call to eval every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that eval might have introduced a new variable that would hide the outer variable). In strict mode eval creates variables only for the code being evaluated, so eval can't affect whether a name refers to an outer variable or some local variable
var x = 17; //a local variable
var evalX = eval("'use strict'; var x = 42; x"); //eval an x internally
assert(x === 17); //x is still 17 here
assert(evalX === 42); //evalX takes 42 from eval'ed x
If a function is declared with "use strict", everything in it will be executed in strict mode. the following will do the same as above:
function foo(){
"use strict";
var x = 17;
var evalX = eval("var x = 42; x");
assert(x === 17);
assert(evalX === 42);
}
Create the variables you want to exist in your scope as local variables in a function. Then, from that function, return a locally-defined function that has a single argument and calls eval on it. That instance of eval will use the scope of its containing function, which is nested inside the scope of your top level function. Each invocation of the top level function creates a new scope with a new instance of the eval function. To keep everything dynamic, you can even use a call to eval in the top level function to declare the variables that will be local to that scope.
Example code:
function makeEvalContext (declarations)
{
eval(declarations);
return function (str) { eval(str); }
}
eval1 = makeEvalContext ("var x;");
eval2 = makeEvalContext ("var x;");
eval1("x = 'first context';");
eval2("x = 'second context';");
eval1("window.alert(x);");
eval2("window.alert(x);");
https://jsfiddle.net/zgs73ret/
Simple as pie.
// Courtesy of Hypersoft-Systems: U.-S.-A.
function scopeEval(scope, script) {
return Function('"use strict";return (' + script + ')').bind(scope)();
}
scopeEval(document, 'alert(this)');
This worked for me the best:
const scopedEval = (scope, script) => Function(`"use strict"; ${script}`).bind(scope)();
Usage:
scopedEval({a:1,b:2},"return this.a+this.b")
You can look into the vm-browserify project, which would be used in conjunction with browserify.
It works by creating <iframe>s, and evaling the code in that <iframe>. The code is actually pretty simple, so you could adapt the basic idea for your own purposes if you don't want to use the library itself.
Here is a 20-line or so JS class that implements an extensible context using eval in a lexical scope:
// Scope class
// aScope.eval(str) -- eval a string within the scope
// aScope.newNames(name...) - adds vars to the scope
function Scope() {
"use strict";
this.names = [];
this.eval = function(s) {
return eval(s);
};
}
Scope.prototype.newNames = function() {
"use strict";
var names = [].slice.call(arguments);
var newNames = names.filter((x)=> !this.names.includes(x));
if (newNames.length) {
var i, len;
var totalNames = newNames.concat(this.names);
var code = "(function() {\n";
for (i = 0, len = newNames.length; i < len; i++) {
code += 'var ' + newNames[i] + ' = null;\n';
}
code += 'return function(str) {return eval(str)};\n})()';
this.eval = this.eval(code);
this.names = totalNames;
}
}
// LOGGING FOR EXAMPLE RUN
function log(s, eval, expr) {
s = '<span class="remark">' + String(s);
if (expr) {
s += ':\n<b>' + expr + '</b> --> ';
}
s += '</span>';
if (expr) {
try {
s += '<span class="result">' + JSON.stringify(eval(expr)) + '</span>';
} catch (err) {
s += '<span class="error">' + err.message + '</span>';
}
}
document.body.innerHTML += s + '\n\n';
}
document.body.innerHTML = '';
// EXAMPLE RUN
var scope = new Scope();
log("Evaluating a var statement doesn't change the scope but newNames does (should return undefined)", scope.eval, 'var x = 4')
log("X in the scope object should raise 'x not defined' error", scope.eval, 'x');
log("X in the global scope should raise 'x not defined' error", eval, 'x');
log("Adding X and Y to the scope object");
scope.newNames('x', 'y');
log("Assigning x and y", scope.eval, 'x = 3; y = 4');
log("X in the global scope should still raise 'x not defined' error", eval, 'x');
log("X + Y in the scope object should be 7", scope.eval, 'x + y');
log("X + Y in the global scope should raise 'x not defined' error", eval, 'x + y');
.remark {
font-style: italic;
}
.result, .error {
font-weight: bold;
}
.error {
color: red;
}
<body style='white-space: pre'></body>
The approach here was to allow a context object to parameterize the evaluation of the expression.
First a function is created using the Function() constructor that accepts every key of the context as well as the expression to evaluate; the body returns the evaluated expression. Then that function is called with all of the values of the context and the expression to evaluate.
function scopedEval(context, expr) {
const evaluator = Function.apply(null, [...Object.keys(context), 'expr', "return eval('expr = undefined;' + expr)"]);
return evaluator.apply(null, [...Object.values(context), expr]);
}
// Usage
const context = {a: 1, b: 2, c: {d: 3}};
scopedEval(context, "a+b+c.d"); // 6
By using Function.prototype.apply the number of arguments and the names don't need to be known beforehand. Because the arguments are scoped to the evaluator function they are directly accessible from the expression (instead of requiring this.a).
The poor man's method:
If your scope is not too dynamic, just a couple of static and read-only declarations, simply put it in a string and concatenate with the string what you wanna execute like this:
const scopeAll = `
const myFunc = (a, b) => a + b + s;
`
const scope1 = `
${scopeAll}
const s = 'c';
`
const scope2 = `
${scopeAll}
const s = 'd';
`
const myStringToExecute = `
myFunc('a', 'b')
`
console.log(eval(scope1 + myStringToExecute));
console.log(eval(scope2 + myStringToExecute));
I'm not sure how much this adds, but I thought I'd post my version of the Function constructor based solution with modern syntactic sugar and what I think is a good solution to avoid polluting the scope with the internal one containing the evaluated text. (By sacrificing the this context, on which properties can be deleted even inside use strict; code)
class ScopedEval {
/** #param {Record<string,unknown>} scope */
constructor(scope) {
this.scope = scope;
}
eval(__script) {
return new Function(...Object.keys(this.scope),`
return eval(
'"use strict";delete this.__script;'
+ this.__script
);
`.replace(/[\n\t]| +/g,'')
).bind({__script})(...Object.values(this.scope));
}
}
Personally I prefer being able to separate when I add or adjust the scope and when I eval some code, so this could be used like:
const context = {
hi: 12,
x: () => 'this is x',
get xGet() {
return 'this is the xGet getter'
}
};
const x = new ScopedEval(context)
console.log(x.eval('"hi = " + hi'));
console.log(x.eval(`
let k = x();
"x() returns " + k
`));
console.log(x.eval('xGet'));
x.scope.someId = 42;
console.log(x.eval('(() => someId)()'))
be careful; it seems some instances will still get access to outside variables. the code below should fail, but if you run it, you can see it works
let exp = 'a+b';
let a = 1;
let b = 2;
function scopeEval(scope, script) {
return Function('"use strict";return (' + script + ')').bind(scope)();
}
console.log(scopeEval({}, exp));
This is the simplest way I found to do that, but it doesn't use eval.
function execInContext(code, context)
{
return Function(...Object.keys(context), 'return '+ code (...Object.values(context));
}
Here we create a Function object. The Function constructor accepts an array of parameters, the last one is the code to be executed by the function and all others are argument names for the function. What we're doing is creating a function that has arguments with the same names as the fields in the context object and then calling this function with the values of the fields in context. So if you call
execInContext('myVar', {myVar: 'hi!'});
it's the same as
((myVar) => { return myVar; })('hi!');
and the result will be hi!
Function
const evaluate = (context, expr) =>
Function(Object.keys(context).join(','), `return ${expr}`)
(...Object.values(context));
Usage
const result = evaluate({a: 1, b: 2, c: {d: 3}}, "a+b+c.d"); // 6
Example
const evaluate = (context, expr) => Function(Object.keys(context).join(','), `return ${expr}`)(...Object.values(context));
const result = evaluate({a: 1, b: 2, c: {d: 3}}, "a+b+c.d");
console.log('result is: ', result);
script evaluation that provides script-scope, app-level-scope and app-level-scripts-this-object. it is safe and not leaking to app
it also provides a console proxy to redirect console output, it is alive in script-scope, so the script call console.log would go to the proxy.
// app level scope, to share additional function and variable that can be used without `this` keyword.
const scope = {};
// app level this obj for all scripts, use this to reference it;
// so we could share data between scripts.
const thisObj = {};
/**
* execute scripts
* #param thisObj 'this' is an app level obj to share data between scripts
* #param scriptsScope app level scope to share some global predefined functions.
* #param localScope we can setup a 'console' proxy is in this scope.
* #param script code to execute.
*/
const scopedEval = function scopedEval(thisObj, scriptsScope, localScope, script) {
const context = { ...scriptsScope, ...localScope };
// create new Function with keys from context as parameters, 'script' is the last parameter.
const evaluator = Function.apply(null, [...Object.keys(context), 'script',
`"use strict";
try{${script}}
catch (e) {
console.error(e);
}`]);
// call the function with values from context and 'script' as arguments.
evaluator.apply(thisObj, [...Object.values(context), script]);
}
/**
* create a proxy for console. that will also write to the consoleElement
* #param consoleElement the ui element to show the console logs, i.e. a div.
* #returns {Proxy}
*/
const consoleProxy = consoleElement => new Proxy(console, {
get: function (target, propKey) {
const originalMethod = target[propKey];
return function (...args) {
// get time with milliseconds
const now = new Date();
const time = now.getHours().toString().padStart(2,'0') + ':' + now.getMinutes().toString().padStart(2,'0') + ':' + now.getSeconds().toString().padStart(2,'0') + '.' + now.getMilliseconds().toString().padStart(3,'0');
// text to show
const text = document.createTextNode(`${time}: ${args.join(' ')}\n`);
const span = document.createElement('span');
span.appendChild(text);
if (propKey === 'error') {
span.style.color = 'red';
} else if (propKey === 'warn') {
span.style.color = 'orange';
} else if (propKey === 'info') {
span.style.color = 'blue';
} else if (propKey === 'debug') {
span.style.color = 'gray';
}
consoleElement.appendChild(span);
// original console logs, if you need
//originalMethod.apply(target, args);
}
}
});
const codes = document.querySelector('.codes');
const script1 = codes.querySelector('.script1').textContent;
const script2 = codes.querySelector('.script2').textContent;
const scriptConsole1 = codes.querySelector('.script-console1');
const scriptConsole2 = codes.querySelector('.script-console2');
scopedEval(thisObj, scope, { console: consoleProxy(scriptConsole1) }, script1);
scopedEval(thisObj, scope, { console: consoleProxy(scriptConsole2) }, script2);
.code {
background: lightgray;
}
<div class="codes">
<div>
<pre class="code">
<code class="script1">
console.log('hello');
this.a = 1
// error
b++
</code>
</pre>
<pre class="script-console1">
</pre>
<div>
<div>
<pre class="code">
<code class="script2">
this.a++
console.log(this.a);
</code>
</pre>
<pre class="script-console2">
</pre>
</div>
<div>

JavaScript: Get Argument Value and NAME of Passed Variable [duplicate]

This question already has answers here:
Determine original name of variable after its passed to a function
(9 answers)
Closed 8 years ago.
What I want to do is get the NAME of a variable passed to a function and the VALUE of that variable, and only have to pass in one variable to the function. So:
var x = "anything";
function showName() {
}
showName(x);
or
showName("x");
Which will return: "x = anything".
Right now, I have to specify the variable twice:
showName("x", x);
In order to get the name and value of the variable I am passing in.
Note that I am not interested in the name of argument in the prototype of showName, but the name of the variable in the calling function. Also, the variable passed may be local, so I can't use the window object to find the variable.
The short answer is that you can't.
The longer, evil answer is that you sort of can with some real nastiness. And it only works when called from another function.
there are two interesting attributes available to you that could help
arguments.callee
caller
for fn to do something like this:
(function(){
var showMe = function(s){
alert(arguments.callee.caller.toString().match(/showMe\((\S)\)/)[1] +
' = '+ s)
}
x = 1
showMe(x)
})()
What arguments.callee.caller.toString().match(..)[1] does is look for the showMe being called in the function calling it and prints it and its value.
But this is still pretty limited because it will only hit the first call of showMe(x). So if there is two calls to it, it won't work.
But, it was fun to play with these arcane things.
Strategy 1:
If you can control the data structure during function invocation then you can pass a dictionary which will encode name as a key, paired with its value, notice the stealth curly braces:
var foo = "bar";
yourfunction({foo});
Which passes a javascript dictionary that looks like this:
{foo : "bar"}
When yourfunction( is executed, unpack name and value thustly:
yourfunction = function(dict) {
var name = Object.keys(dict)[0];
var value = dict[name];
console.log(name); //prints foo
console.log(value); //prints bar
}
Strategy 2:
If you can maintain an as-you-go list of name-value pairs in a global scope, then reflection and introspection is always available for set and get, for example:
var my_global_stack = [];
yourfunction = function() {
//Chomp the stack
var dict = my_global_stack.pop();
//The name is the key at index 0
var name = Object.keys(dict)[0];
//Fetch the value by keyname:
var value = dict[name];
console.log(name); //prints foo
console.log(value); //prints bar
}
foo = "bar";
my_global_stack.push({foo});
yourfunction();
Strategy 3:
If user-hostile input isn't an issue, you can use eval( to rediscover value given variablename, for example:
yourfunction = function(somevariable) {
console.log(somevariable); //prints foo
console.log(eval(somevariable)); //prints bar
}
foo = "bar";
yourfunction("foo");
People say eval( is evil here, because if a hostile user is able to overwrite the value of foo in memory at any point, then they can do OS Command Injection and run any command they want.
http://cwe.mitre.org/top25/#Guidance
var x = "anything";
function showName(s) {
alert(s + " = " + eval(s));
}
showName("x");
Not recommended, but there it is.
You could create a hash and pass that in:
var x = {a: 1,b:2}
function showVars(y) {
for (var z in y) { alert(z + " is " + y[z]); }
}
showVars(x);
This doesn't necessarily show the name of the variable, but it does allow for key-value pairs, which may be more to the point of what you need.
This is what I use for debugging. No global variables, no eval, no arguments.callee or arguments.caller:
var Helpers = (function () {
// ECMAScript 5 strict mode
'use strict';
var Module = {};
Module.debug = function () {
var i;
for (i = 0; i < arguments.length; i++) {
console.log(arguments[i] + ':', this[arguments[i]]);
}
};
Module.SomeObject = function SomeObject() {
this.someMember = 1;
this.anotherMember = 'Whatever';
Module.debug.call(this, 'someMember', 'anotherMember');
var privateMember = {
name: 'Rip Steakface',
battleCry: 'Raaaaaaaaahhhhhhhhhrrrrrrrrrg!'
};
Module.debug.call(privateMember, 'name', 'battleCry');
};
return Module;
}());
For those who are wondering why you would want to do this, it's just a way to efficiently log multiple variables along with their names.
If you want to be able to log nested members, as in Module.debug.call(obj, 'hair.fluffiness'), you can modify the function like so:
Module.debug = function () {
var i, j, props, tmp;
for (i = 0; i < arguments.length; i++) {
tmp = this;
props = arguments[i].split('.');
for (j = 0; j < props.length; j++) {
tmp = tmp[props[j]];
}
console.log(arguments[i] + ':', tmp);
}
};
Unfortunately, I can't find any way to efficiently log multiple private variables that aren't members of an object, e.g. var roll = 3, value = 4; Module.debug.call(???);
Not sure you can directly get what you want from JavaScript, since the variable name is not carried around with the value it references (think of variable names as identifiers only the compiler knows about; but which get thrown away at runtime).
You can, however, do something slightly different which allows for passing around named arguments. Create an anonymous object and pass that to your function:
function showNames(o)
{
for( var ix in o )
{
alert( ix + ":" + o[ix] );
}
}
var z = { x : "Anything" }
showNames( z );
// or
showNames( { a : "ay", b : "bee", c: "see" } )
For iterating object properties, I tend to prefer a functional-style, as in:
Array.iteri = function(o, f)
{
for(var i in o) { f(i, o[i]) }
}
function showNames(o)
{
Array.iteri( o, function(i,v)
{
alert( i + ": " + v )
});
}
showNames( { a : "ay", b : "bee", c: "see" } )
The below code is about the best you can do. Unfortunately local variables in a function are properties of the hidden Call Object so they can't be accessed from Javascript like window[a] where a is a property of the window object.
x = "this is x";
var say = function(a) {
document.write(a + " = " + window[a]);
}
say("x");
var wrapper = function () {
var x = "this is x";
document.write(x + " = " + eval("x"))
}
wrapper()

Categories

Resources