Executing a function in an object from a variable - javascript

Suppose I have a variable that contains the name of a function I want to run, I can run it by using window, like so;
var func = "myFunc",
myFunc = function(){ ... };
window[func](); // run the function in the func var
However, this doesn't work if the intended function is deep inside an object;
var obj = {
foo: {
hey: function(){ ... }
}
};
obj.foo.hey(); // this runs
var func = "obj.foo.hey";
window[func](); // this doesn't
I could use eval(), but I wonder if it's possible to avoid that, so as to not introduce the many security considerations that eval() comes with.
How can I run a function specified in a variable, when the function is in an object as described above?

You could iterate the splitted func and return the result of an walked object.
function getValue(object, path) {
return path.split('.').reduce(function (o, k) {
return (o || {})[k];
}, object);
}
var obj = { foo: { hey: function () { console.log('hey'); } } },
func = "obj.foo.hey";
getValue(window, func)();
(getValue(window, 'bar') || function () {})(); // default function, prevent exception

You can's pass nested properties under a single string. It must be done dynamically like.
var obj = {
foo: {
hey: function(){console.log("i run")}
}
};
obj.foo.hey(); // this runs
var route = ["obj","foo","hey"],
func = route.reduce((f,r) => f[r], window);
func()

Related

Determine if a JavaScript function is a bound function

Is there a way to determine if a JavaScript function is a bound function?
Example:
var obj = {
x:1
};
function printX() {
document.write(this.x);
}
function takesACallback(cb) {
// how can one determine if this is a bounded function
// not just a function?
if (typeof cb === 'function') {
cb();
}
}
takesACallback(printX.bind(obj)); // 1
takesACallback(printX); // undefined
Perhaps this is an important point. I am not asking why the second call prints undefined.
Both bound functions and arrow functions do not have a prototype property:
typeof (function() {}).prototype // 'object' as usual
typeof (function() {}).bind(null).prototype // 'undefined'!
typeof (() => {}).prototype // 'undefined'!
This is not 100% safe since you could still manually assign this property (although that'd be weird).
As such, a simple way to check for bindability would be the following:
// ES5
function isBindable(func) {
return func.hasOwnProperty('prototype');
}
// ES6
const isBindable = func => func.hasOwnProperty('prototype');
Usage:
isBindable(function () {}); // true
isBindable(() => {}); // false
isBindable(
(function () {}).bind(null)
); // false
This way you can make sure that the function that has been passed can deal with a dynamic this.
Here is an example usage for which the above fails:
const arrowFunc = () => {};
arrowFunc.prototype = 42;
isBindable(arrowFunc); // true :(
Interestingly, while bound functions do not have a prototype property they can still be used as constructors (with new):
var Animal = function(name) {
this.name = name;
};
Animal.prototype.getName = function() {
return this.name;
};
var squirrel = new Animal('squirrel');
console.log(squirrel.getName()); // prints "squirrel"
var MutatedAnimal = Animal.bind({}); // Radiation :)
console.log(MutatedAnimal.hasOwnProperty('prototype')); // prints "false"
var mutatedSquirrel = new MutatedAnimal('squirrel with two heads');
console.log(mutatedSquirrel.getName()); // prints "squirrel with two heads"
In that case, the original function prototype (Animal) is used instead.
See JS Bin, code and link courtesy of Dmitri Pavlutin.
This of course won't work with arrow functions since they can't be used as constructors.
Unfortunately, I don't know if there is a way to distinguish a bound function (usable as constructor) from an arrow function (not usable as constructor) without trying them out with new and checking if it throws (new (() => {}) throws a "is not a constructor" error).
In environments that support ES6, you can check whether the name of the function starts with "bound " (the word "bound" followed by a space).
From the spec:
19.2.3.2 Function.prototype.bind ( thisArg , ...args)
[...]
15. Perform SetFunctionName(F, targetName, "bound").
Of course that could result in false positives if the name of the function was manually changed.
One could override the existing prototype bind, tagging functions that have been bound.
A simple solution. This will likely kill certain optimizations in V8 (and possibly other runtimes) because of hidden classes, though.
(function (bind) {
Object.defineProperties(Function.prototype, {
'bind': {
value: function (context) {
var newf = bind.apply(this, arguments);
newf.context = context;
return newf;
}
},
'isBound': {
value: function () {
return this.hasOwnProperty('context');
}
}
});
}(Function.prototype.bind));
In motion:
(function (bind) {
Object.defineProperties(Function.prototype, {
'bind': {
value: function (context) {
var newf = bind.apply(this, arguments);
newf.context = context;
return newf;
}
},
'isBound': {
value: function () {
return this.hasOwnProperty('context');
}
}
});
}(Function.prototype.bind));
var a = function () {
console.log(this);
};
var b = {
b: true
};
var c = a.bind(b);
console.log(a.isBound())
console.log(c.isBound())
console.log(c.context === b);
a();
c();
You would need to write your own bind function on the prototype. That function would build an index of what has been bound.
You could then have another function to perform a lookup against the object where that index is stored.
Based on previous answers, I create a function to determine:
function isBoundFunction(func) {
if(typeof func.prototype === 'object') return false
try {
new func()
}
catch(e) {
return false
}
return true
}
This function determine three type of functions: 1. original function, whose prototype is object, 2. arrow function, which can not be used as constructor, 3. bound function.
There is a module that can help you solve this problem : bind2.
Here's a use case :
const bind2 = require('bind2');
function testFunc() {
return this.hello;
}
const context = { hello: 'world' };
const boundFunc = bind2(testFunc, context);
console.log(boundFunc.bound); // true
Full disclosure : I wrote this module.

Bind a function to String.prototype so it's always bound to the string

String.prototype.contains = function(str) {
return this.indexOf(str) !== -1;
};
This snippet does extend String.prototype.
It works well with function calls like 'foobar'.contains('foo');
But it doesn't work well if it's passed as a function, not invoking it:
var str = 'foobar';
['foo', 'bar'].every(str.contains);
TypeError: Object [object global] has no method 'indexOf'
I know you could do:
['foo', 'bar'].every(str.contains.bind(str));
or something like:
['foo', 'bar'].every(function(item) { return str.contains(item); });
But they just make me feel awkward.
In a Constructor function I created, although it doesn't work this way:
function Foo(myStr) {
this.myStr = myStr;
this.contains = function(fragment) {
return this.myStr.indexOf(fragment) !== -1;
};
}
var someFoo = new Foo('foobar');
['foo', 'bar'].every(someFoo.contains)
TypeError: Cannot call method 'indexOf' of undefined
I could do this to make it work:
function Foo(myStr) {
var self = this; // Line added
this.myStr = myStr;
this.contains = function(fragment) {
return self.myStr.indexOf(fragment) !== -1; // this changed to self
};
}
I'm wondering if there's a way to extend String.prototype so that I don't have to bind 'someString'.contains to 'someString' every time I use it as a function without invoking it.
Try this:
Object.defineProperty(String.prototype, "contains", {
get: function () {
return (function(str) {
return this.indexOf(str) !== -1;
}).bind(this);
}
});
It defines a new property with a getter, meaning every time you "get" the function, for example in ['foo', 'bar'].every(str.contains);, the function defined above would get called and the return value of that function would be returned as str.contains, in this case. The function is the same as yours, only we bind this in the getter which is the string, which is what we want.
If Object.defineProperty isn't defined in your browser (or anyone to use your code), you can use __defineGetter__ instead.
A complete solution would look like this:
addPropertyWithGetter = function(object, property) {
getter = function () {
return (function(str) {
return this.indexOf(str) !== -1;
}).bind(this);
}
if (_.isFunction(Object.defineProperty)) {
return Object.defineProperty(object, property, {
get: getter,
});
} else {
object.__defineGetter__(property, getter);
}
}
And the usage:
addPropertyWithGetter(String.prototype, "contains")
The second parameter for Array.prototype.every() is the thisArg(Value to use as this when executing callback).
So you could do with:
['foo', 'bar'].every(str.contains, str);
For fixing your code:
function Foo(myStr) {
this.contains = function(fragment) {
// myStr is accessible here
return myStr.indexOf(fragment) !== -1;
};
}
var someFoo = new Foo('foobar');
['foo', 'bar'].every(someFoo.contains);

Rewiring a JavaScript function

Let's say I have a function named fna() that does a simple thing such as:
var fna = function(ar) {
console.log("argument: ", ar);
return "return value is argument too: " + ar;
}
fna() is coded by some other developer and I can't access to it. He didn't bother casting any events and when it is called, I have to be aware of it. Hopefully, his method is accessible by window.fna().
I want some additional code to be executed. Let's say, add this console.log
var fna = function(ar) {
console.log("Hola, I am some additional stuff being rewired");
console.log("argument:", ar);
return "return value is argument too: " + ar;
}
And I want this to be executed even when called from fnb() by some other part of the code.
var fnb = function() {
return fna("Bonjour, I am fnb and I call fna");
}
Here is a way I found, using the utils.rewire() method. utils is just some utility belt, and it could be added to your favorite framework as a plugin. Unfortunately, it only works on Firefox.
var utils = utils || {};
// Let's rewire a function. i.e. My.super.method()
utils.rewire = function(functionFullName, callback) {
var rewired = window[functionFullName];
console.log("%s() is being rewired", functionFullName)
window[functionFullName] = function() {
callback();
return rewired.apply(this, arguments);
}
}
Use it like this.
utils.rewire("fna",function(){
console.log("Hola, I am some additional stuffs being rewired");
});
This seems to work such as shown in this jsbin, but (and here is my question:) How do I rewire obja.fna()?
var obja = {
fna = function(ar) {
console.log("argument:", ar);
return "return value is argument too: " + ar;
}
};
I cannot make it work to rewire the some.object.method() method.
Extra bonus question: Is there a more cleaner way to do this? Out-of-the-box clean concise and magic library?
Refactor rewire into a rewireMethod function which acts on any given object:
var utils = utils || {};
utils.rewireMethod = function (obj, functionName, prefunc) {
var original = obj[functionName];
obj[functionName] = function () {
prefunc();
return original.apply(this, arguments);
};
};
Note that rewire can now be written as:
utils.rewire = function (functionName, prefunc) {
utils.rewireMethod(window, functionName, prefunc);
};
Then you just call it as:
utils.rewireMethod(obja, "fna", function () {
console.log("Hola, I am some additional stuff being rewired");
});
Note that nothing special is required if you have a method like window.ideeli.Search.init(). In that case, the object is window.ideeli.Search, and the method name is init:
utils.rewireMethod(window.ideeli.Search, "init", function () {
console.log("Oh yeah, nested objects.");
});
Add a parameter to rewire that is the object containing the function. If it's a global function, pass in window.
var utils = utils || {};
// let's rewire a function. i.e. My.super.method()
utils.rewire = function(object, functionName, callback) {
var rewired = object[functionName];
console.log("%s() is being rewired", functionName)
object[functionName] = function() {
callback();
return rewired.apply(this, arguments);
}
}
utils.rewire(some.object, "method", function(){} );
You can simply use a closure to create a generic hook function that allows you to specify another function to be called immediately before or after the original function:
function hookFunction(fn, preFn, postFn) {
function hook() {
var retVal;
if (preFn) {
preFn.apply(this, arguments);
}
retVal = fn.apply(this, arguments);
if (postFn) {
postFn.apply(this, arguments);
}
return retVal;
}
return hook;
}
So, for any function that you want to hook, you just call hookFunction and pass it the function you want to hook and then an optional pre and post function or yours. The pre and post function are passed the same arguments that the original function was.
So, if your original function was this:
var fna = function(ar) {
console.log("argument:",ar);
return "return value is argument too:"+ar;
}
And, you want something to happen every time that function is called right before it's called, you would do this:
fna = hookFunction(fna, function() {
console.log("Hola, I am some additional stuff being rewired right before");
});
or if you wanted it to happen right after the original was called, you could do it like this:
fna = hookFunction(fna, null, function() {
console.log("Hola, I am some additional stuff being rewired right after");
});
Working demo: http://jsfiddle.net/jfriend00/DMgn6/
This can be used with methods on objects and arbitrary nesting levels of objects and methods.
var myObj = function(msg) {
this.greeting = msg;
};
myObj.prototype = {
test: function(a) {
log("myObj.test: " + this.greeting);
}
}
var x = new myObj("hello");
x.test = hookFunction(x.test, mypreFunc2, myPostFunc2);
x.test("hello");
Based on Claudiu's answer, which seems to be the most appreciated way, here is a solution using a for loop and proxying the context... But still, I find this ugly.
var utils = utils || {};
// Let's rewire a function. i.e. My.super.method()
utils.rewire = function(method, callback) {
var obj = window;
var original = function() {};
var tree = method.split(".");
var fun = tree.pop();
console.log(tree);
// Parse through the hierarchy
for (var i = 0; i < tree.length; i++) {
obj = obj[tree[i]];
}
if(typeof(obj[fun]) === "function") {
original = obj[fun];
}
var cb = callback.bind(obj);
obj[fun] = function(ar) {
cb();
return original.apply(this, arguments);
}
}
Well, this looks strange. Consider this
function wrap(fn, wrapper) {
return function() {
var a = arguments;
return wrapper(function() { return fn.apply(this, a) })
}
}
Example:
function foo(a, b) {
console.log([a, b])
return a + b
}
bar = wrap(foo, function(original) {
console.log("hi")
var ret = original()
console.log("there")
return ret
})
console.log(bar(11,22))
Result:
hi
[11, 22]
there
33
To wrap object methods, just bind them:
obj = {
x: 111,
foo: function(a, b) {
console.log([a, b, this.x])
}
}
bar = wrap(obj.foo.bind(obj), function(fn) {
console.log("hi")
return fn()
})

avoid needing to declare 'var me = this' for javascript prototype functions

Currently, I create objects in javascript by declaring a construction (regular function) then add methods to the prototype like so
function Test(){
}
Test.prototype.test1 = function(){
var me = this;
}
However, I would like to avoid having to declare var me = this at the top of every function. The following seems to work, but seems like it would be very inefficient:
$(document).ready(function(){
var n = 0;
(function(){
function createTest(){
var me;
function Test(){
this.n = n;
this.testArr = [1, 2, 3, 4];
n++;
}
Test.prototype.test1 = function(){
me.test2();
};
Test.prototype.test2 = function(){
alert(me.n);
$.getJSON('test.php', {}, function(reply)
//want to be able to use 'me' here
me.newField = reply;
});
};
var t = new Test();
me = t;
return t;
}
window['createTest'] = createTest;
})();
var t = createTest();
t.test1();
var t2 = createTest();
t2.test1();
t.test1();
});
This code outputs the expected, but is it actually as inefficient as it looks (the Test object being re-declared every time you call createTest())?
Anyhoo, this would seem a bit hacky... is there a completely different way to do this that is better?
EDIT: The real reason I would like to do this is so that callbacks like the one in test2 will have references to the correct this.
What you can do is bind the current this value to a function and store a copy somewhere. (For the sake of efficiency.)
if (!Function.prototype.bind) {
// Most modern browsers will have this built-in but just in case.
Function.prototype.bind = function (obj) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () { },
bound = function () {
return self.apply(this instanceof nop ? this : (obj || {}),
args.concat(slice.call(arguments)));
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
function Test(n) {
this.n = n;
this.callback = (function () {
alert(this.n);
}).bind(this)
}
Test.prototype.test1 = function () {
this.test2();
}
Test.prototype.test2 = function () {
doSomething(this.callback);
}
function doSomething(callback) {
callback();
}
var t = new Test(2);
t.test1();
I realize your question was not tagged with jQuery, but you are using it in your example, so my solution also utilizes jQuery.
I sometimes use the $.proxy function to avoid callback context. Look at this simple jsfiddle example. Source below.
function Test(){
this.bind();
}
Test.prototype.bind = function(){
$('input').bind('change', $.proxy(this.change, this));
// you could use $.proxy on anonymous functions also (as in your $.getJSON example)
}
Test.prototype.change = function(event){
// currentField must be set from e.target
// because this is `Test` instance
console.log(this instanceof Test); // true
console.log(event.target == $('input')[0]); // true
this.currentField = event.target; // set new field
};
function createTest(){
return new Test();
}
$(function(){ // ready callback calls test factory
var t1 = createTest();
});
Most of the time, I just declare a local variable that references this, wherever I need a reference to this in a callback:
function Foo() {
}
Foo.prototype.bar = function() {
var that=this;
setTimeout(function() {
that.something="This goes to the right object";
}, 5000);
}
Alternatively, you can use bind() like this:
Function Foo() {
this.bar = this.bar.bind(this);
// ... repeated for each function ...
}
Foo.prototype.bar = function() {
}
What this gives you is that every time you create a new Foo instance, the methods are bound to the current instance, so you can use them as callback functions for setTimeout() et al.

How do I compute a variable in JavaScript if and only if it is used?

This is what I'm doing right now.
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = function() { return x; };
return x;
}
It works but only if foo is called as a function like so
foo();
But what if I want to call it as a normal variable with a value? I could modify the code to be
var foo = function() {
var x = someComplicatedComputationThatMayTakeMoreTime();
this.foo = x;
return x;
}
That would allow me to only call it once as a function and after that as a regular variable. But it's still not what I want. Plus it gets complicated if it accidentally gets called as a function again, returning an error.
Is this even possible in JavaScript?
BTW, this is for a Chrome/Firefox extension, so IE compatibility does not matter.
Ended up using toString because getters don't allow me to redefine the whole attribute, a function must be associated with it. And toString has cleaner syntax.
How about using toString?
var foo = function() {
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
}
More about Object-to-Primitive Conversions in JavaScript
EDIT based on comment. Use a singleton (I think it's called):
myObject.prop = (function(){
function someComplicatedComputationThatMayTakeMoreTime() {
//your calculations
}
return {
toString: function() {
return someComplicatedComputationThatMayTakeMoreTime();
}
}
})()
If only Internet Explorer didn't exist, you could use getters and setters as described by John Resig in this blog article:
John Resig: JavaScript Getters and Setters
... They allow you to bind special functions to an object that look like normal object properties, but actually execute hidden functions instead.
Using a function is your best option for now, however the new JavaScript standard (ECMAScript 5th Ed.) which is being implemented now by all major browser vendors, gives you a method to create accessor properties, where you can define a property with a get and set functions that will be internally called, without worrying to treat this properties as functions, e.g.:
var obj = {};
Object.defineProperty(obj, 'foo', {
get: function () { // getter logic
return 'foo!';
},
set: function (value) {
// setter logic
}
});
obj.foo; // "foo!", no function call
This new standard will take some time to be implemented for all browsers, (the IE9 preview version really disappointed me), and I wouldn't recommend you to use it for production, unless you have total control on the environment where your application will be used.
What I think you want is a lazily instantiated variable, which can be implemented like this.
var myProperty = null;
function getMyProperty() {
return (myProperty = myProperty || builder());
}
This is not practical on the web because IE does not support it, but you can look at
https://developer.mozilla.org/en/defineGetter for examples how to do this.
There are a couple ways to do it, here is one example:
var data = {};
data.__defineGetter__("prop",
(function () {
var value = null;
return function () {
if (null == value) {
value = getYourValueHere();
}
return value;
};
})());
and now you can use it like:
var a = data.prop;
var b = data.prop;
I would recommend a variation on ChaosPandion's answer, but with a closure.
var myProperty = (function () {
var innerProperty = null;
return function() {
return (innerProperty = innerProperty || someComplicatedComputationThatMayTakeMoreTime());
};
})();
and then use myProperty() every time you need to access the variable.
You could define a JavaScript getter. From the Apple JavaScript Coding Guidelines:
myObject.__defineGetter__( "myGetter", function() { return this.myVariable; } );
var someVariable = myObject.myGetter;
See John Resig's post, JavaScript Getters and Setters, and the Defining Getters and Setters page at the Mozilla Developer Centre for more information.
I would use explicit lazy evaluation. Here's my implementation of it based on Scheme's take:
var delay, lazy, force, promise, promiseForced, promiseRunning;
(function () {
var getValue = function () {
return this.value;
};
var RUNNING = {};
var DelayThunk = function (nullaryFunc) {
this.value = nullaryFunc;
};
DelayThunk.prototype.toString = function () {
return "[object Promise]";
};
DelayThunk.prototype.force = function () {
if (promiseRunning (this)) {
throw new Error ("Circular forcing of a promise.");
}
var nullaryFunc = this.value;
this.value = RUNNING;
this.value = nullaryFunc ();
this.force = getValue;
return this.value;
};
var LazyThunk = function (nullaryFunc) {
DelayThunk.call (this, nullaryFunc);
};
LazyThunk.prototype = new DelayThunk (null);
LazyThunk.prototype.constructor = LazyThunk;
LazyThunk.prototype.force = function () {
var result = DelayThunk.prototype.force.call (this);
while (result instanceof LazyThunk) {
result = DelayThunk.prototype.force.call (result);
}
return force (result);
};
delay = function (nullaryFunc) {
return new DelayThunk (nullaryFunc);
};
lazy = function (nullaryFunc) {
return new LazyThunk (nullaryFunc);
};
force = function (expr) {
if (promise (expr)) {
return expr.force ();
}
return expr;
};
promise = function (expr) {
return expr instanceof DelayThunk;
};
promiseForced = function (expr) {
return expr.force === getValue || !promise (expr);
};
promiseRunning = function (expr) {
return expr.value === RUNNING || !promise (expr);
};
}) ();
Example Syntax:
var x = lazy (function () { return expression; });
var y = force (x);
var z = delay (function () { return expression; });
var w = force (z);
Note values are stored once evaluated, so repeated forcing will not do extra computations.
Example usage:
function makeThunk (x, y, z) {
return lazy (function () {
// lots of work done here
});
}
var thunk = makeThunk (arg1, arg2, arg3);
if (condition) {
output (force (thunk));
output (force (thunk)); // no extra work done; no extra side effects either
}
You can use the javascript Proxy class for creating such functionality.
var object = {};
var handler = {
resolvers: {},
get ( target, property, proxy ) {
if ( ! target.hasOwnProperty( property ) && this.resolvers.hasOwnProperty( property ) ) {
// execute the getter for the property;
target[ property ] = this.resolvers[ property ]();
}
return target[ property ];
},
set ( target, property, value, receiver ) {
// if the value is function set as a resolver
if ( typeof value === 'function' ) {
this.resolvers[property] = value;
// otherwise set value to target
} else {
target.property = value;
}
},
has ( target, property, receiver ) {
//true when proxy handler has either a resolver or target has a value;
return this.resolvers.hasOwnProperty( property ) || target.hasOwnProperty( property );
}
};
var lazyObject = new Proxy( object, handler );
Now you can use it like this:
'exampleField' in lazyObject; //returns false
lazyObject.exampleField = function(){ return 'my value' }; // add a resolver function
'exampleField' in lazyObject; //returns true
lazyObject.exampleField; //executes your resolver function and returns 'my value'
This example is to demonstrate the working. You can change after your needs.
Here is a fiddle with a demonstration

Categories

Resources