Can you dynamically add local variables to a function? - javascript

I'm using objects to namespace my JavaScript code. These objects usually contain functions that are called mapping the this-pointer to the object itself using apply. However, I find it inconvenient to use the this-pointer everytime I want to access other functions or properties of the object, especially because in lots of cases I use the new-operator to use function-objects the way you would use classes. I would prefer writing new Line() instead if new this.Line().
It would be great if you could add local variables to a function the way php does it with extract (pseudocode following, it's a little more complicated)
var sample_object = {
"some_function": function() {}
}
test() {
extract(sample_object);
some_function(); // imported from sample_object
}
Is that even possible?

I'm pretty sure eval is your only answer; but you need to be aware that if there's any input outside of your control involved, it isn't safe
function dynamicArgs (varName, varValue) {
eval("var " + varName + "=" + JSON.encode(varValue) );
alert(a);
}
dynamicArgs("a", "value");
You can see the problem with this. How is your function supposed to call the dynamic variable if it doesn't know its name? I hardcoded it to the a variable since I pass it in when calling it, but that's not a good solution. The only solution would be another eval. You really should think about what you need to do and whether this is useful. But it's doable.
Here it is in action: http://jsfiddle.net/mendesjuan/GG3Wu/
function dynamicArgs (varName, varValue) {
eval('var ' + varName + "='" + varValue + "';");
alert(eval(varName));
}
dynamicArgs("f", "Here I am");
Now here's an example like what you're doing, creating a variable from this.MyConstructor
http://jsfiddle.net/mendesjuan/AK3WD/
var ns = {
MyConstructor: function(val) {
this.prop = val;
},
runConstructor: function(val) {
var Ctor = "MyConstructor";
eval('var ' + Ctor + ' = this.' + Ctor);
return new MyConstructor(val);
}
}
alert( ns.runConstructor("Hello").prop );
And here's an example if you wanted to import all the values from an object into the scope;
http://jsfiddle.net/mendesjuan/AK3WD/1/
var ns = {
MyConstructor: function(val) {
this.val= val;
},
anotherProperty: 5,
runConstructor: function(val) {
// Bring all the variables from this into this scope
for (var prop in this) {
eval('var ' + prop + ' = this.' + prop);
}
alert('Testing var anotherProperty: ' + anotherProperty);
var obj = new MyConstructor(val);
alert('Created MyConstructor: its prop is ' + obj.val)
}
}
ns.runConstructor("Hello");

There is controversial with, which has some great applications, but is marginally slow and prone to errors. It throws an error in the strict mode (which you should always opt into) and is going to be deprecated.
var sampleObject = {
someFunction: function() {},
b: 10
}
with (sampleObject) {
typeof someFunction // "function"
var a = 42
var b = 20
}
sampleObject.a // undefined
sampleObject.b // 20
Note, that new variables defined in a with-block won't be added to the object. Nevertheless, if the object already had an eponymous property in it, this property would be modified (thanks, #Rocket).
Just for fun, here's an implementation of extract using eval (which is even more evil than with). You can do unspeakable things with it, for example if your object has properties like sampleObject['x; while (true) { alert("Hi!") }'].

This is how I did it:
function smObject ( object) {
return function () {
function getter(prop) {
return function() {
return this[prop];
}
}
function setter(prop) {
return function(data) {
this[prop]=data;
}
}
for (var o = 0; o < object.length; o++) {
this[object[o]] = {};
this['get' + object[o]] = getter(object[o]);
this['set' + object[o]] = setter(object[o]);
}
}
}
now you can instantiate a function like this:
var fields = ['Name', 'Id', 'Other', '....' ]
var MyFunction = smObject( fields );
var myObject = new MyFunction();
// getter/setters
myObject.setId(5);
myObject.getId(); // will return 5
Regards,
Emanouil

Related

How does one manipulate a variable in a prototype?

I'm new to Javascript and was wondering how a public variable in a prototype can be modified.
function Thing (val)
{
this.x = val;
this.addToX = function (valIn)
{
this.x += valIn;
};
}
function ChildThing ()
{
this.y = 55;
}
ChildThing.prototype = new Thing(10);
var frank = new ChildThing();
console.log("out1: " + frank.x);
frank.addToX(10);
console.log("out2: " + frank.x);
This code takes the value in the prototype x which is 10 and adds 10 to it in the addToX function. The new x value is stored in the top level object rather than replacing the current x value in the prototype.
Is there a way to overwrite the existing x in the prototype or am I using Javascript wrong?
That depends. What would be the point of altering x on the prototype? Generally you don't want to chang shared properties. But I imagine that there could be a use case (generating new id?).
As for the question: you can simply do:
this.addToX = function(valIn) {
ChildThing.prototype.x += valIn;
};
Again I do not advice doing it.
EDIT You can make it without referencing the child by defining the prototype before setting it as a prototype, i.e.
var my_proto = new Thing(10);
ChildThing.prototype = my_proto;
and then
this.addToX = function(valIn) {
my_proto.x += valIn;
};
Or you can even play with the singleton pattern.
What you seem to be wanting is very similar to what static members are in classical languages. It's very misleading to call a method on an object instance and have that method modify the state of other objects outside of it's scope. Therefore, I believe you shounldn't be relying on prototypes at all for this behavior. Here's what you could do to mimic static members.
function SomeClass() {}
SomeClass.staticMember = 'initial value';
SomeClass.changeStaticMember = function (val) { this.staticMember = val; };
SomeClass.changeStaticMember('another value');
I believe the code above is less cryptic and better at communicating the behavior. However if you still want to share mutable values across instances through the prototype you could simply avoid writing the property directly as a primitive value, but rather wrap it within a mutable shared object like below. Note that the whole inheritance hierarchy will share the same x value.
//Mutable class to encapsulate the value of X
function XValue(val) {
this.value = val;
}
XValue.prototype = {
constructor: XValue,
valueOf: function () { return this.value; },
set: function (val) { this.value = val; },
add: function (val) { this.value += val; }
};
function Thing(x) {
this.x = x;
}
Thing.prototype = {
constructor: Thing,
_x: new XValue(), //shared mutable object representing the value of X
get x() { return this._x.valueOf(); },
set x(val) { this._x.set(val); },
addToX: function (val) { this._x.add(val); }
};
function ChildThing() {
Thing.call(this, 10); //call parent constructor
}
ChildThing.prototype = Object.create(Thing.prototype);
//helper for snippet
function log(text) {
var span = document.createElement('span');
span.innerHTML = text;
document.body.appendChild(span);
document.body.appendChild(document.createElement('br'));
}
var ct = new ChildThing();
ct.addToX(10);
log('ct.x → ' + ct.x);
log('Thing.prototype.x → ' + Thing.prototype.x);

Proper way of defining a javascript variable?

Is the below JavaScript code have the proper variable declaration, or any other way to define that ? may i know this method of variable declarations ?
var JQFUNCS = {
runFunc: {
"jsonp": {
run: function (id) {
var demobox = $('#' + id);
demobox.html('<img id="loading" src="images/loading.gif" />');
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?", {
tags: "jquery",
tagmode: "any",
format: "json"
}, function (data) {
demobox.empty();
$.each(data.items, function (i, item) {
demobox.append('<a href="' + item.link + '" target="_blank"><img style="max-width:150px;" src="' + item.media.m + '" alt="' + item.title + '" title="' + item.title + '" />');
if (i == 10) return false;
});
$('#' + id + ' #loading').hide();
});
},
reset: function (id) {
$('#' + id).empty().hide();
}
}
}
}
This method of variable declaration is called an Object Literal.
var objectLiteral = {
propertyOne: 1,
functionTwo: function() {
return 2;
}
};
Uses: Great for encapsulating data and functionality that belong together in a more traditional way. Protects from cluttering the global namespace from duplicated variable names. Only provides one instance of the object unless you use object copying tatics though.
You can also use a function declaration:
function funcDeclaration() {
this.propertyOne = 1;
this.functionTwo = function() {
return 2;
}
}
var obj = new funcDeclaration();
Uses: Allows for instantiation of objects, very much like classes. Has all the flexibility of a object literal plus some.
There isn't a right or wrong answer here. Some of it is situation, convention, or preference.
Heck you can even combine the two and get really tricky by employing a self executing function (if you are trying to emulate visibility modifiers):
var objectLiteral = (function() {
//currently within a self-executing function, syntax allows this
var privatePropertyOne = 1;
function privateFunctionTwo() { //yes, functions can contain other functions
return 2;
}
//the self-executing function returns and object literal that contains references to the privately scoped items defined above.
return {
PropertyOne: function() { return privatePropertyOne; },
FunctionTwo: privateFunctionTwo
};
})();
Uses: Pro and fun. =P Not necessarily readable and certainly blows the mind of any newbie javascript developer.

Javascript closure and "this"

My question is... in CallMeLaterTestObj function in the TestObj the "this" is the window object and not TestObj. How can I restructure this so that within the CallMeLater function I don't have to wrap the call function() { v.CallMeLaterTestObj(); } in a closure or using the bind function since it has limited support to newer browsers. Two objectives:
Keeping "this" in function calls within the object
Maintaining a separate value for "value" for each separate object so they don't share the same value.
// Emulating public api, private methods, private variables, public fields.
// New portion of question
Re-written to include binding function and prototypical notation. How do you move the Binding function into a base object that all new objects would get?
This is as close as I can come to getting this to use the best of both worlds. I have no idea what the pitfalls of this approach are though
var BaseObject = function ()
{
_getBinding = function (method)
{
var _self = this;
return function ()
{
_self[method].apply(_self, arguments);
};
};
return {
CallInline: _getBinding
}
}();
var TestObj = function (value)
{
$.extend(this, BaseObject);
// public var
this._value = value;
};
TestObj.prototype = function()
{
var privateVar = false;
// these are private
_giveMe = function () {
return this._value;
},
_callMeLaterTestObj = function () {
console.log('I am ' + this.constructor.name + ' my value is ' + this._value);
};
// public API
return {
GiveMe : _giveMe,
CallMeLaterTestObj : _callMeLaterTestObj
}
}();
function CallMeLater(v, i)
{
setTimeout(v.CallInline('CallMeLaterTestObj'), 10);
}
var V1 = new TestObj(1);
var V2 = new TestObj(2);
var V3 = new TestObj(3);
console.log('V1= ' + V1.GiveMe());
console.log('V2= ' + V2.GiveMe());
console.log('V3= ' + V3.GiveMe());
console.log('---');
V1.CallMeLaterTestObj();
console.log('---');
I think what you're looking for is this:
function TestObj(value) {
var _value = value;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
return this;
};
function callMeLater(v, i) {
setTimeout(function() {
v.callMeLaterTestObj();
}, 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);​
To access constructor.name, you need to declare the function with function name() syntax, rather than var name = function() syntax.
To keep private variables and expose a public api, expose the public variables as properties of this in the function.
Be sure to return this from the constructor function to make it work.
It's also good practice to follow the naming convention of CamelCase for class names (of which TestObj is one) and lowerCamelCase for variables / methods / objects / etc. Helps keep things clear as to which variables are instances, and which are Classes.
Test and see the console output expected here.
note
Regarding wrapping v.callMeLaterTestObj() in a closure for the setTimeout, this technique is completely cross-browser compatible. You won't have any issues.
The bind method is newer, although there are many libraries that will shim that for you in older browsers. My personal favourite is underscore.
note 2
You can't call a method on an object in setTimeout without wrapping it in a closure somewhere, however if you want to you can abstract the closure in the Class without using a generic bind function (as provided by Underscore or jQuery and others) you can 'roll your own' in the Class like this:
function TestObj(value) {
var _value = value;
var _self = this;
this.giveMe = function() {
return _value;
};
this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};
this.getBinding = function(method) {
var _self = this;
return function() {
_self[method].apply(_self, arguments);
};
};
return this;
};
function callMeLater(v, i) {
setTimeout(v.getBinding('callMeLaterTestObj'), 10);
}
var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);
console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');
callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);​
explanation:
You need to use some sort of binding because, when you pass the method to setTimeout, you pass it by reference. So all setTimeout sees is a function - not the object it was on, which is why you lose the context of this.
Since setTimeout will therefore execute the function in the default scope - i.e. the browser window - you need a way to get this back, by reference, either through an inline anonymous function, or by returning a closure that uses the apply method to 'reset' this.
note 3
If you wanted to have your own bind method, and not include a library that provides it for you or include it in every class then you can use this one from Underscore, which defers to the native method in newer browsers:
function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};
Then use it like this:
function callMeLater(v, i) {
setTimeout(bind(v.callMeLaterTestObj, v), 10);
}
This will work well in all browsers.
No, you can't. That's just the way to do it. Btw, you can easily shim the bind method so that it is available in older browsers, too.
An alternative would be to move the closure into the prototype method, if you know that you always will need to bind the actual function:
TestObj.prototype.getCallMeLaterTestObj = function () {
var that = this;
return function() {
console.log('I am ' + that.constructor.name + ' my value is ' + that._value);
};
};
setTimeout(v.getCallMeLaterTestObj(), 10);
Btw, your prototype has no constructor property so the log will not work as expected.
Your only chance is to avoid the this keyword entirely:
TestObj = function() {
var privateVar = false; // these are private static
function TestObj(value) {
function giveMe() {
return value;
}
function callMeLaterTestObj() {
console.log('I am TestObj my value is ' + giveMe());
}
this._value = value;
this.giveMe = giveMe;
this.callMeLaterTestObj = callMeLaterTestObj;
/* you could do this as well:
return {
_value: value,
giveMe: giveMe,
callMeLaterTestObj: callMeLaterTestObj
}; */
}
return TestObj;
})();
var v = new TestObj;
setTimeout(v.callMeLater, 10);
But this is not very memory-efficient, as it does not use prototypical inheritance at all.

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()

Calling a function by a string in JavaScript and staying in scope

I've been playing around and searching a bit, but I can't figure this out. I have a pseudo private function within a JavaScript object that needs to get called via eval (because the name of the function is built dynamically). However, the function is hidden from the global scope by a closure and I cannot figure out how to reference it using eval().
Ex:
var myObject = function(){
var privateFunctionNeedsToBeCalled = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, SecondPart) {
var functionCallString = firstPart + secondPart + '()';
eval(functionCallString);
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');
I know the example looks silly but I wanted to keep it simple. Any ideas?
The string passed to eval() is evaluated in that eval()'s scope, so you could do
return {
publicFunction: function(firstPart, SecondPart) {
var captured_privateFunctionNeedsToBeCalled = privateFunctionNeedsToBeCalled;
var functionCallString = 'captured_' + firstPart + secondPart + '()';
eval(functionCallString);
}
}
However, a better solution would be to avoid the use of eval() entirely:
var myObject = function(){
var functions = {};
functions['privateFunctionNeedsToBeCalled'] = function() {
alert('gets here');
};
return {
publicFunction: function(firstPart, secondPart) {
functions[firstPart+secondPart]();
}
}
}();
myObject.publicFunction('privateFunctionNeeds', 'ToBeCalled');

Categories

Resources