How do I wrap a javascript function with dynamic arguments? - javascript

I'd like to wrap some dynamically created javascript functions, similar to Daniel's accepted answer here:
How do I store javascript functions in a queue for them to be executed eventually
// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
return function() {
fn.apply(context, params);
};
}
The difference is I'd like the argument values to be dynamic at time of execution - is it possible to pass a reference to a variable in the arguments, which could be updated after it is wrapped?
Here's what I'd like to do:
// I have a function to be wrapped
var sayStuff = function(a,b) {
console.log(a);
console.log(b);
}
// Variables I'd like to pass
var randomNumberA = 0;
var randomNumberB = 0;
// Wrap the function
var fun = wrapFunction(sayStuff, this, [*reference randomNumberA*,*reference randomNumberB*]);
// variables get changed
randomNumberA = Math.random()*100;
randomNumberB = Math.random()*100;
// Execute the function using current values of randomNumberA & randomNumberB
fun();
If possible I'd like to do this without changing sayStuff, I have a lot of existing functions like this I'm hoping to wrap, which also get used outside of the wrapping, so ideally I'd like to not replace the arguments with an object.
Hope that makes sense, Thanks!

If the function and the variable will be created in the same scope you can just use that:
var randomNumber = 0;
var fun = function(){ alert(randomNumber); }
randomNumber = 10;
// Now this will alert 10, because when fun is executed
// JS looks in his scope to find what randomNumber is.
fun();
This happens because functions in javascript works as Closures, they carry their environment with them. See: https://en.wikipedia.org/wiki/Closure_(computer_programming)
So if randomNumber will be changed out of the scope where you bind that function, you need to use an object, this is because in javascript we don't have "pointers" or references to pass by. One way is using a object.
function giveMeAFunction(){
var params = { randomNumber: 0 }
var fun = function(){ alert(scope.randomNumber); }
return {fun: fun, scope: scope};
}
var paramsAndFun = giveMeAFunction()
// Now you can change the variables in the scope and call the function
paramsAndFun.params.randomNumber = 10;
paramsAndFun.fun(); // Will alert 10
// Now if you replace the entire params object it will not work
// This is because you will replacing it with a new object while
// The one that is referenced in the scope where fun was created is
// the old one.
paramsAndFun.params = { randomNumber: 15 };
paramsAndFun.fun(); // will still alert 10
Now let's get to binding part of the problem.
There is already Function.prototype.bind function to help you with that.
For example:
var sayStuff = function(opts) {
alert(otions.randomNumber);
}
var options = { randomNumber: 0 };
var fun = sayStuff.bind(this, options);
options.randomNumber = 10;
fun(); // Will print 10
There is a lot going on here. Sorry if I made everything confuse.

If the dynamic arguments are defined in the context argument, a solution can be based passing the name of the variables and then, at execution time, calculate its current value:
var wrapFunction = function(fn, context) {
var xArg = arguments;
return function() {
var argsArray = [];
for (var i = 2; i < xArg.length; i++) {
argsArray.push(context[xArg[i]]);
}
fn.apply(context, argsArray);
};
}
var sayStuff = function() {
for (var i = 0; i < arguments.length; i++) {
console.log('sayStuff func: ' + arguments[i]);
}
}
var randomNumber1 = 0;
var randomNumber2 = 0;
var fun = wrapFunction(sayStuff, this, 'randomNumber1', 'randomNumber2');
randomNumber1 = Math.random()*100;
randomNumber2 = Math.random()*100;
console.log('randomNumber1: ' + randomNumber1);
console.log('randomNumber2: ' + randomNumber2);
fun();

Related

Functions With Global Inputs Return NaN

Edit:
I wanted to be more specific about why I'm doing it this way. The code below is something I've been attempting to get working.
function newClass(self) {
this.invest;
this.interest;
function method1() {
return this.invest + this.interest;
}
}
var newC = new newClass();
newC.invest = prompt("Enter investment");
newC.interest = prompt("Enter interest");
alert(newC.method1());
End Of Edit:
I'm fairly new to the javascript language and can not figure out why my functions are always returning NaN. I have attempted many different fixes but nothing I have tried works. Below is an example.
function investment() {
var iniInvest;
var interest;
return iniInvest + interest;
}
investment.iniInvest = 10;
investment.interest = 20;
console.log(investment())
This returns a NaN. I have attempted creating classes and methods and attempted to parse the variables but they still all return NaN.
Unless the variables values are assigned to the var in the function
var iniInvest = 10;
or args are given
function investment(args1, args2) {
return args1 + args2;
}
console.log(investment(10, 20));
it will return NaN.
I appreciate the help.
You cannot access the variable inside functions like
investment.iniInvest = 10;
investment.interest = 20;
Since, you need that variables globally accessed so you can keep that variables outside the function and initialize them from anywhere in the code:
var iniInvest;
var interest;
function investment() {
return iniInvest + interest;
}
iniInvest = 10;
interest = 20;
console.log(investment())
The code investment.iniInvest = 10; is creating an iniInvest property on investment, not a local variable. This code does not modify the variable var iniInvest created within the function's scope.
function investment() {
return investment.iniInvest + investment.interest;
}
investment.iniInvest = 10;
investment.interest = 20;
console.log(investment())
This code achieves what you are asking, but this is not a good way to solve the problem.
The following is more likely what you are looking for:
function investment( iniInvest, interest) {
this.iniInvest = iniInvest;
this.interest = interest;
this.investment = function() {
return this.iniInvest + this.interest;
};
}
var inv = new investment( 10, 30 );
console.log( inv.investment() );
inv.iniInvest = 5;
inv.interest = 10;
console.log( inv.investment() );
As you are declaring iniInvest interest in function so you can not use that variable out of that function as they are out of scope. Make that variable global.
You can go through https://www.w3schools.com/js/js_scope.asp for scope of variables.
The problem is that when you declare a variable inside of a function, it exists only within that function, and is only local. Therefore, it can not be referenced from outside of the function.
In the example that you gave, you attempt to reference the variable investment.iniInvest and investment.interest, but those variables only exist within the local reference of the investment function, and are destroyed after the function ends, so you can not reference them. You're probably better off using args anyways.
You can try something like
var investment = function () {
this.iniInvest;
this.interest;
this.sum = function() {
return this.iniInvest + this.interest;
}
}
var i = new investment()
i.iniInvest = 10;
i.interest = 20;
console.log(i.sum());
Thanks everyone for all your answers! After reading everyones answer I was able to fix my syntax and resolve the problem.
This is my finished code.
function newClass() {
this.invest;
this.interest;
this.investment = function() {
return parseFloat(this.invest) + parseFloat(this.interest);
}
}
var newC = new newClass();
newC.invest = prompt("Enter investment");
newC.interest = prompt("Enter interest");
alert(newC.investment());
It returns the proper answer. Please do let me know if this code requires fixing.
Thanks Again!

Equivalent of interfaces in javascript

I have a function object in javascript called BlinkyTextBox Inside of that I have 2 Shape objects that act as scroll buttons. I need a something very simple to happen which is just increment or decrement a variable called scrollY.
I tried it with an anonymous inner function, but the function couldn't recognize the member variables. Now I tried it with a member function, but it doesn't work with that either...
Here are both samples of what I am talking about.
function BlinkyTextBox(textdata, font, w, h)
{
this.scrollY = -50;
this.scrollBarYTop = new Button();
this.scrollBarYTop.callFunction = this.scrollUp;
this.scrollBarYBottom = new Button();
this.scrollBarYBottom.callFunction = function()
{
this.scrollY -= 10;
}
}
BlinkyTextBox.prototype.scrollUp = function()
{
this.scrollY += 10;
}
The problem here is that once you assign a function to another object the this inside that function will refer to the new object instead of the object the function came from.
For example:
var a = {
message : 'Hello!',
say : function () { return this.message }
}
var b = {
message : 'Goodbye'
}
b.say = a.say;
console.log(a.say()); // Hello!
console.log(b.say()); // Goodbye
Notice that we didn't do anything to the function say(). We just assigned it to b and it now print's the message from b instead of a.
Now, let's look at your code:
this.scrollBarYBottom.callFunction = function()
{
this.scrollY -= 10; // refers to scrollBarYBottom.scrollY
// not BlinkyTextBox.scrollY
}
Same thing happens to the other method:
this.scrollBarYTop.callFunction = this.scrollUp;
// the this inside scrollUp will now refer to scrollBarYTop
Traditionally, to fix this you'd use an alias for this:
var myself = this;
this.scrollBarYBottom.callFunction = function()
{
myself.scrollY -= 10;
}
But with ES5 you can use the .bind() method:
this.scrollBarYBottom.callFunction = (function()
{
this.scrollY -= 10;
}).bind(this);
and:
this.scrollBarYTop.callFunction = this.scrollUp.bind(this);
Refer to this answer for a more detailed explanation of this: How does the "this" keyword in Javascript act within an object literal?

`this` is undefined when calling method from another context

This is my first time creating OOP for JS. I followed some tutorials but I can't wrap my head around this issue. I know the problem, but i dont know the solution
function NewApp(name){
this.name = name;
this.currentPage = 1;
this.customObjectWithMethods = //init with options and so on
}
NewApp.prototype.logic = function(){
// Note 1.
var app = this
//Note 3.
this.customObjectWithMethods.method{
if(app.currentpage < 3)
// Note 2.
app.navigate(app.logic)
}
}
NewApp.prototype.navigate = function(sender){
var app = this;
this.customObjectWithMethods.method{
app.currentpage++;
this.method(function() {
return app.currentPage === 2;
}, sender(), this.terminate);
}
}
Note 1: I need to create a reference because after that, this doesn't
work anymore to refer to the current object.
Note 2: After the check I want to do some logic in another method and repeat the current function, but when the function runs again it breaks on the method (this.customObjectWithMethods) because this doesn't exists.
Note 3: This is where it breaks because "this" works the first time not the second time.
It gets very complicated like this with the this-keyword, which makes me think that my design may be flawed.
Is there any solution for this problem, or should I refactor it ?
Surely it will become complicated, thiskeyword doesn't always refer to the main object but to the scope where it is used, take a look at Scope and this in JavaScript for further information.
This is your way to go, make a variable that contains your constructor and add these two methods to this variable, after that you can call your functions:
var newApp = function newApp(name){
this.name = name;
this.currentPage = 1;
//Make a reference to your object here
var THIS = this;
this.logic = function(){
var sender = this;
THIS.customObjectWithMethods.method = function(){
if(THIS.currentpage < 3)
THIS.navigate(sender);
}
}
this.navigate = function(sender){
this.customObjectWithMethods.method = function(){
THIS.currentpage++;
this.method(function() {
return THIS.currentPage === 2;
}, sender(), this.terminate);
}
}
}
And this is how to use your constructor and its methods:
var app = newApp("Test");
//Call the first method
app.customObjectWithMethods();
//Thenn call the second one
app.logic();
Some syntax errors & style issues - here is a short correction
var myFunction = function(){
//code here
};
var mySecondFunction = function(){
//code here
};
function NewApp(name){
this.name = name;
this.currentPage = 1;
this.customObjectWithMethods = function(){}; //empty function so calling doesnt resolve in error
}
NewApp.prototype.logic = function(){
this.customObjectWithMethods.method = mySecondFunction.bind(this);
}
NewApp.prototype.navigate = function(sender){
this.customObjectWithMethods.method = myFunction.bind(this);
}
I have moved the 2 functions outside of the constructor Function so they dont get recreated every time you call the constructor functions.
with _.bind(this) the "this"-reference gets passed into the scope of your functions (i think this is more pretty than creating another var).
with
var reff = new NewApp('namename');
you can get started calling your functions now:
ref.logic();
maybe this approach works for you?

Dynamically firing a named-spaced method via JavaScript

I have multiple external JavaScripts that are namespaced based on the section of the site. I am trying to dynamically fire methods, but am unable to get the methods to fire. Can anyone tell me what the problem is?
If I add this, the method fires:
Namespace.Something.init()
But when I try to do it like this, nothing happens (note: namespace equals Namespace.Something and functionname equals init):
namespace[functionname]();
Unless you want to use eval which I am sure you don't the following works.
This assumes that all your methods are the same level deep i.e namespace.somename.somemethod
var Namespace = {
Something: {
init: function() {
console.log('init called');
}
}
};
Namespace.Something.init();
var namespace = "Namespace";
var section = "Something";
var method = "init";
this[namespace][section][method]();
as Namespace is part of the global scope you can access it from this[namespace]
I asked the same question a few weeks ago, though I think I phrased it slightly differently. See this.
Basically, you need to parse the string functionname one piece at a time.
By the way, using the walk_path code from that answer, here's a general purpose function I wrote to run a function from a string including arguments.
// run an arbitrary function from a string. Will attempt to parse the args from parenthesis, if none found, will
// use additional arguments passed to this function.
utils.runFunction = function (funcdef) {
var argPos = funcdef.indexOf('(');
var endArgPos = -1;
var args = undefined;
var func = funcdef;
if (argPos > 0) {
endArgPos = funcdef.indexOf(')', argPos);
if (endArgPos > 0) {
args = funcdef.substring(argPos + 1, endArgPos).split(',');
func = funcdef.substring(0, argPos - 1);
}
} else {
args = Array.prototype.slice.call(arguments, 1);
}
var func = walk_path(window, func);
return !args ? func() : func.apply(null, args);
};
var methodName = 'Namespace.Something.init';
var methodParts = methodName.split('.');
var method = this;
for (var i=0; i < methodParts.length; i++) {
method = method[methodParts[i]];
};
method(the arguments you want);

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