I am reading a config file which contains a mapping of Angular Factories/Function names. The Factory/Function names are stores as strings in the mapping. I am wondering how would I be able to execute the Factory/Function I have read from config?
None of these factories are accessible on window otherwise I could call window[factory][functionName]().
Would I have to resort to something like:
var factory;
var factoryName = getFactory(config.sendTelemetry);
if (factoryName === 'TelemetryFactory') {
factory = TelemetryFactory;
} else if (factoryName === 'DebugFactory') {
factory = DebugFactory;
}
factory[functionName]();
Sample config file:
// Sample config file
var config = {
'sendTelemetry': {
'factory': 'TelemetryFactory',
'functionName': 'sendTelemetry'
},
'logDebug': {
'factory': 'DebugFactory',
'functionName': 'logDebug'
}
}
If the functions are just normally scoped functions, you can do a one-off creation of a lookup map from name to function reference to avoid the long switch statement:
var funcMap = {
TelemetryFactory: TelemetryFactory,
DebugFactory: DebugFactory
};
or to avoid the (potentially error-prone) repetition, by using each function's .name property and constructing the map from an array of function references:
// build lookup map
var funcs = [ TelemetryFactory, DebugFactory ];
var funcMap = {};
funcs.forEach(function(f) {
funcMap[f.name] = f;
});
In ES6 it becomes even simpler, because ES6 has an object literal syntax where you can pass the name of a variable (or function) and it automatically creates a key with that variable's name and value:
let funcMap = { TelemetryFactory, DebugFactory };
Whichever of the three methods above you use to build the map, dispatch is then a trivial operation via the map:
funcMap[factoryName]();
It looks like you'd need to evaluate the strings first:
eval(factory[functionName])();
Hope this helps :)
Related
I am trying to create a dynamic function in TypeScript which calls an already existing function like:
let dynamicFunction = new Function("existingFunction(\"asdf\");");
function existingFunction(name: string) {
console.log(name);
}
While debugging in chrome dynamicFunction looks like this:
(function() {
existingFunction("asdf");
})
When I try to execute dynamicFunction, it says "Uncaught ReferenceError: existingFunction is not defined", which is no surprise because it's a different scope, but how can I actually call exisitingFunction inside dynamicFunction?
Any help would be greatly appreciated!
Edit:
to be more precise: I've got a typescript file which contains one module.
This module exports a function which should return the created dynamic function.
The created dynamicFunction is then used in another module which actually contains the exisitingFunction.
I've chosen this approach because I need to convert a given string to an executable condition, which will be executed many times.
For example: convert string "VALUE==1" to:
function () {
return exisitingFunction("VALUE") == 1;
}
A short example of how it should look like:
parser.ts:
export module Parser {
export function getFunction(expression: string) {
// Calculating condition...
let condition = "existingFunction(\"VALUE\") == 1;"
return new Function(condition);
}
}
condition.ts:
import { Parser } from "./parser";
class Condition {
// getting the DynamicFunction
private _dynamicFunction = Parser.getFunction("VALUE==1");
someFunctionInsideCondition() {
// Calling the DynamicFunction
this._dynamicFunction();
}
}
// Maybe this function should be somewhere else?
function existingFunction(name: string) {
console.log(name);
return 1;
}
I hope this explains my problem a little bit better.
From the Function documentation
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called. This is different from using eval with code for a function expression.
so you'll have to pass existingFunction as an argument or define it in the global space.
try with
var existingFunction = function(name: string) {
console.log(name);
}
Also have a look at eval which will give you access to the current scope ...
--- Update
After the question update and considering your comment about not wanting to use eval because of security concerns (with which i totally agree)
The problem is that in the generated function's scope, this is undefined. Making your existingFunction part of the global scope is already a bad idea and between Typescript and the modules architecture doesn't seem possible at all.
So why not passing a context to the generated function?
This will allow you to control how much of your application to expose to the generated function, while giving it access to external methods.
Something along the lines of:
class Parser {
static getFunction(expression) {
let condition = new Function("context", "context.existingFunction(\"VALUE\") == 1;");
return condition;
}
}
class Condition {
constructor() {
this._dynamicFunction = Parser.getFunction("VALUE==1");
}
someFunctionInsideCondition() {
// Calling the DynamicFunction
this._dynamicFunction(this);
}
existingFunction(name) {
console.log("hello " + name);
return 1;
};
}
let c = new Condition();
c.someFunctionInsideCondition();
Of course your context can be a different object instead of this, where you keep all your utility functions.
I had to donwpile (compile it down, my own word) to es2015 to make the example run here, but I made it originally in Typescript and works fine
I would skip the usage of new Function and instead do it as follows.
The parser.ts file would contain this:
export class FunctionGenerator {
constructor(private fn: Function) {}
makeFunction(args: string): Function {
const [variable, val] = args.split("==");
return () => this.fn(variable) == val;
}
}
This is basically a factory that allows creating a series of functions that call the function passed when the factory is created. You can then use makeFunction for the specific checks you want to perform. (Note that I used == like in your question. I much prefer using === unless there's a reason against it.)
It can then be used like this:
import * as parser from "./parser";
let vars = {};
// This is a simulation of your funciton. It just plucks values from `vars`.
function existingFunction(name: string) {
return vars[name];
}
function resetVars() {
vars = {
"VALUE": 1,
"FOO": 2,
"BAR": 3,
};
}
function test(gen) {
const fn1 = gen.makeFunction("VALUE==1");
console.log(fn1(), "should be true");
const fn2 = gen.makeFunction("BAR==3");
console.log(fn2(), "should be true");
vars["BAR"] = 7;
// Call the same function again, but with a new value in `vars`.
console.log(fn2(), "should be false");
const fn3 = gen.makeFunction("BAR==1000");
console.log(fn3(), "should be false");
}
resetVars();
const gen = new parser.FunctionGenerator(existingFunction);
test(gen);
When creating an object to use JS in an OO manner, is there any difference within a JS engine between (with the exception of being able to define a constructor:
var Uploader = Uploader || {};
and
var Uploader = function() {
}
and
function Uploader() {
}
Especially when later, you wish to do something along the lines of
Uploader.DOM = {
Create: function(file) {
}
};
Is it all down to personal preference? Or is there a real difference?
Objects:
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
}
}
In MyObj.find function this keyword will point to MyObj (which somewhat resembles how this works in languages those have classes). You can use this functionality to do mix-ins:
var MyObj2 = {
myArr: [4,2,6]
}
MyObj2.find = MyObj.find;
In MyObj2.find function this keyword will point to MyObj2.
Also objects support getters and setters (works on IE9+ and all good browsers):
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
},
get maxValue() {
return Math.max.apply(null, this.myArr);// maxValue is calculated on the fly
},
a_: null,
get a () {
return this.a_;
},
set a (val) {
//fire a change event, do input validation
this.a_ = val;
}
}
Now max value in the array can be accessed like this: MyObj.maxValue. I also added a property a_. It can't be named the same as its getter and setter so appended an underscore. Appending or prepending underscores is a naming convention for private variables which should not be accessed directly.
var qwe = MyObj.a // get a_
MyObj.a = 'something'; //set a_
Functions:
var u = new Uploader(); // will throw an exception
var Uploader = function() { }
Uploader is defined in runtime here. It does not exist yet when I try to instantiate it.
var u = new Uploader(); //will work
function Uploader() {}
Uploader is defined in compilation time here so it will work.
Functions can be used with revealing pattern to conceal some members. Functions don't support getters and setters but you can put objects inside functions.
function myFunc() {
function privateFunc() {};
function publicFunc() {};
var obj = {
//members, getters, setters
};
return {
publicFunc: publicFunc,
obj: obj
}
}
You can call muFunc.publicFunc() outside of myFunc because it is returned. But you can not use privateFunc outside because it is not returned.
Revealing pattern functions are not meant to be instantiated usually. This is because when you instantiate it everything inside will be copied to a new instance. So it will use up more memory than if you would add functions using prototype.
myFunc.prototype.someFunc = function() {};
Like this all instances of myFunc will share the same instance of someFunc.
Conclusion: with functions you can simulate a private access modifier but in objects the this keyword acts somewhat similar of what you'd expect in a language that have classes. But you always can use call, apply and bind to change the context (i.e. what 'this' keyword will be) of the function.
In JavaScript, I may begin writing a 'library' or collection of functionality using a top level object like this:
window.Lib = (function()
{
return {
// Define Lib here.
//
};
})();
I may also add some functions within Lib which serve to create objects related to it:
window.Lib = (function()
{
return {
ObjectA: function()
{
var _a = 5;
return {
getA: function(){ return _a; }
};
},
ObjectB: function()
{
var _b = 2;
var _c = 1;
return {
getB: function(){ return _b; }
};
}
};
})();
Which would be used like so:
var thing = Lib.ObjectA();
var thing2 = Lib.ObjectA();
var thing3 = Lib.ObjectB();
And I can use the methods within each of those created above to get the values of _a defined within ObjectA() or _b defined within ObjectB():
alert(thing.getA()); // 5
alert(thing3.getB()); // 2
What I want to achieve is this:
Say I want to access the property _c (defined within ObjectB()) but only within the scope of Lib. How could I go about that? By this I mean, I want to make the property readable within any function that I define within the object returned by Lib(), but I don't want to expose those values outside of that.
Code example:
window.Lib = (function()
{
return {
ObjectA: function(){ ... },
ObjectB: function(){ ... },
assess: function(obj)
{
// Somehow get _c here.
alert( obj.getInternalC() );
}
};
})();
Which would work like so:
var thing = Lib.ObjectB();
alert( thing.getInternalC() ) // error | null | no method named .getInternalC()
Lib.assess(thing); // 1
Hope this makes sense.
So you want per-instance protected properties? That is, properties on the instances created by ObjectA, ObjectB, etc., but which are only accessible to the code within your library, and not to code outside it?
You cannot currently do that properly in JavaScript, but you'll be able to in the next version using private name objects. (See "Almost doing it" below for something similar you can do now in ES5, though.)
It's easy to create data that's shared by all code within Lib, but not per-instance properties, like so:
window.Lib = (function()
{
var sharedData;
// ...
})();
All of the functions defined within there (your ObjectA, etc.) will have access to that one sharedData variable, which is completely inaccessible from outside. But it's not per-instance, each object created by ObjectA, ObjectB, etc. doesn't get its own copy.
Almost doing it
If your code will be running in an environment with ES5 (so, any modern browser, where "modern" does not include IE8 or earlier), you can have obscured but not actually private properties, via Object.defineProperty. This is similar to how private name objects will work in ES.next, but not genuinely private:
Live Example | Source
window.Lib = (function() {
// Get a random name for our "c" property
var c = "__c" + Math.round(Math.random() * 1000000);
// Return our library functions
return {
ObjectA: function() {
// Create an object with a couple of public proprties:
var obj = {
pub1: "I'm a public property",
pub2: "So am I"
};
// Add our obscured "c" property to it, make sure it's
// non-enumerable (doesn't show up in for-in loops)
Object.defineProperty(obj, c, {
enumerable: false, // false is actually the default value, just emphasizing
writable: true,
value: "I'm an obscured property"
});
// Return it
return obj;
},
ObjectB: function(){ /* ... */ },
assess: function(obj) {
// Here, we access the property using the `c` variable, which
// contains the property name. In JavaScript, you can access
// properties either using dotted notation and a literal
// (`foo.propName`), or using bracketed notation and a string
// (`foo["propName"]`). Here we're using bracketed notation,
// and our `c` string, which has the actual property name.
display( obj[c] );
},
alter: function(obj, value) {
// Similarly, we can change the value with code that has
// access to the `c` variable
obj[c] = value;
}
};
})();
And use it like this:
// Create our object
var o = Lib.ObjectA();
// Play with it
display("pub1: " + o.pub1); // displays "pub1: I'm a public property"
display("c: " + o.c); // displays "c: undefined" since `o` has no property called `c`
Lib.assess(o); // displays "I'm an obscured property"
// Note that our obscured property doesn't show up in for-in loops or Object.keys:
var propName, propNames = [];
for (propName in o) {
propNames.push(propName);
}
display("propNames: " + propNames.join(","));
display("Object.keys: " + Object.keys(o).join(","));
// Our Lib code can modify the property
Lib.alter(o, "Updated obscured property");
Lib.assess(o);
The object returned by Lib.ObjectA has a property whose name will change every time Lib is loaded, and which is not enumerable (doesn't show up in for-in loops). The only way to get at it is to know it's name (which, again, changes every time Lib is created — e.g., every page load). The code within Lib knows what the property name is, because it's in the c variable which is shared by all of the Lib code. Since you can access properties using bracketed notation and a string, we can use instance[c] to access the property.
You see how these are pretty well obscured. Code outside of Lib don't see the obscured property when enumerating the property in the object, and they don't know the semi-random name we assigned it, so can't find the property. Of course, you could find it via inspection using a debugger, but debuggers can do lots of things.
And in fact, this is how private properties will work in ES.next, except that c won't be a string, it'll be a private name object.
Well, you would "just" need to declare those variables within the Context of Lib
window.Lib = (function()
{
var _c = 42;
return {
};
});
Notice that I removed the automatic invocation of that pseudo constructor function. That means, you would need to create multiple calls to Lib() for multiple instances, each would have its own unique set of values.
var inst1 = Lib(),
inst2 = Lib();
If you only want to have shared access from all child-context's (functions), you can just use the same pattern you already do (only with moving the var declarations to the parent context like shown above).
I'm trying to prototype a custom logger with different levels (debug, info, warn...) each one with different properties like color, name etc.
What I'm trying to do is build dynamically all those levels, getting them from a Hashmap where I store all the properties.
So for example I have my custom logger object with logger.debug('test'), logger.info('text), and so on. You get the idea.
BUT, I'm having problems with this particular code:
var MyLogger = function(opts) {
this.level = opts.level || 0
this.loggers = {}
var self = this
for (l in LEVELS) {
this.addLogger(l, new loggerOutput(LEVELS[l]))
this[l] = function(message) {
self.getLogger(l).output(message)
}
}
}
The problem is with self.getLogger(l), as it always point to my last logger (ERROR). If I replace the variable with a static string, it works: self.getLogger('info')
The workaround is to prototype by hand all loggers, and obviosly that works, but I was expecting to find a better solution:
MyLogger.prototype = {
debug: function(message) {
this.getLogger('debug').output(message)
},
info: function(message) {
this.getLogger('info').output(message)
}
...
}
Thank you in advance.
Use the prototype solution, but assign the functions in a loop by passing the current "level" to a function factory.
for (var L in LEVELS)
MyLogger.prototype[L] = loggerMaker(L)
function loggerMaker(l) {
return function(message) {
this.getLogger(l).output(message)
};
}
Here I used a function to create a new variable scope that references the current L in the loop.
If you're coding only for modern JavaScript environments, I'd use an Array instead of an Object to hold the levels, and then use forEach with an anonymous function.
;['debug','info','warn'].forEach(function(L) {
MyLogger.prototype[L] = function(message) {
this.getLogger(L).output(message);
};
});
I want to implement setter and getter on local
javascript variable. Here is an example function:
function someThing() {
var someLocalvariable = '';
}
// with this function I want to
// return value of someLocalvariable
// also if it is possible to implement
// setter in this way.
someThing.prototype.getLocalVar = function() {
}
I want variable to be 'realy' private. I don't wont
to use something like this:
someThing.prototype.someLocalvariable =
or
function someThing() {
this.someLocalvariable = '';
}
or attaching function inside someThing() like this:
function someThing() {
var someLocalvariable = '';
this.getLocalvariable = function() {
return someLocalvariable;
}
}
I would be very grateful for any guidance and assistance.
Your last example of what you don't want to do won't work (it has syntax errors), (it's been fixed) but I think you may have meant the usual way of doing this, which is to make the getter and setter closures within the constructor function (below).
Unfortunately, if you want truly private variables, this is just about your only option. There is no other way to get truly private, instance-specific variables. However, see "hack" below.
Here's the correct version of the usual way of doing this (which I think you said you don't want, but for completeness):
function SomeThing() {
var privateVar;
this.setPrivateVar = function(val) {
privateVar = val;
};
this.getPrivateVar = function() {
return privateVar;
};
}
// use:
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar()); // "foo"
Like most, I first read of this pattern on Douglas Crockford's site.
This option does carry a downside: Every instance created via the SomeThing constructor function gets its own two functions. They cannot be shared between instances. So if there are going to be hundreds or thousands of SomeThing instances in your app, that's something to be considered from a memory perspective. If there are going to be a couple of hundred or fewer, it probably doesn't matter. (Those numbers are pulled out of a hat and you should not trust them, you'll have to review your code's memory use when/if there's some kind of issue; but you get the idea.)
The hack: If your instances will already have some kind of unique identifier on them as public data (or you're willing to add one, again it will be public), and if you're willing to add a fair bit of complication into the use of the instances, you can have a private cache that holds the data for all of your instances that only your code can access, and key into that cache via the unique identifier of the object. Like this (in this example, I'm allocating the id values, but you can use existing unique IDs if you have them):
var SomeThing = (function() {
var cache = {}, idAllocator = 0;
function SomeThing() {
this.id = ++idAllocator; // The unique identifier, can be a string if desired
cache[this.id] = {};
}
SomeThing.prototype.getPrivateVar = function() {
var data = cache[this.id];
return data && data.privateVar;
};
SomeThing.prototype.setPrivateVar = function(value) {
cache[this.id].privateVar = value;
};
SomeThing.prototype.destroy = function() {
delete cache[this.id];
};
return SomeThing;
})();
Here's how that works: All of the functions are closures over the cache local variable in the outer scoping function. We index into that using the unique ID of the object, which gives us an object on which we put our private data members. When the code using the instance is done using it, that code must call destroy (which is a major downside to this pattern) so we remove the private data object from cache by deleting the property for our id.
Caveats and costs:
You still have a public piece of data that is the key to your private data (id in the above)
Users of the instances created by SomeThing must call destroy on those instances when they're done with them. This is anathema to the way JavaScript's garbage handling works, but it's a requirement of the pattern above because otherwise you end up with cruft building up in the cache object.
(I wouldn't worry about this one) Eventually, if you're using the automatic id values above, you'll run out of them, if your app creates and destroys a lot of these instances. But JavaScript numbers go very high up indeed, and if that's an issue just find a different way to allocate IDs rather than the simplistic always-increasing system above.
I haven't had to use the pattern above in my work yet, but I expect there are use-cases for it involving thousands of SomeThing instances and thus the desire not to have per-instance functions.
Side note: In the above, I changed someThing to SomeThing. In JavaScript, the standard practice is for the names of normal functions to start with a lower-case letter, and for the names of constructor functions (ones you use with new) to start with a capital letter. Since SomeThing is meant to be used with new, I capped it. This is only convention, but it's an overwhelmingly popular one and, of course, it's used within the language definition itself (Date is a constructor, setHours is a function).
Use Object.defineProperty() in the function constructor in order to define your getter and setter more info here..
To make truly private (not visible to the outside) some values use a Closure,
more info can be found here.
In the following example we define a getter and setter for property temperature, where the inner "private" value is stored in a variable var temperature.
var temperature will never be visible/accessibly from the outside of Archiver() has it is a Closure.
Please note that this pattern works on ES5 as Object.defineProperty() it is not supported on ES3.
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function () {
console.log('get!');
return temperature;
},
set: function (value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function () {
return archive;
};
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
Something like this:
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
Check ref: http://ejohn.org/blog/javascript-getters-and-setters/
Douglas Crockford has written this on implementing private members in JavaScript
That's not possible. If you have a local variable in someThing(), the function you attach to the prototype can't read its value (it's private, remember?). Your last example is the normal solution to this problem, why isn't this good enough for you?
Try these two ways to achieve setter and getter
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
//Other setter and getter
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);
First method
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
Second method
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);