a.js
// #global-constants
var App = {
constant: function() {
constant.prototype.CONST1 = 'abc';
}
};
module.exports = App;
not able to access in say b.js using App.constant.CONST1, it says undefined why?
there are two problems with you code:
1.) App.constant would return a class(technically a function), but what you want is it's object, can be created using a new keyword, so it becomes, (new App.constant).CONST1.
2.) constant.prototype.CONST1 would not work, because constant is not the name of your anonymous function, so I gave it a name foo and it becomes foo.prototype.CONST1.
the modified code:
var App = {
constant: function foo() {
foo.prototype.CONST1 = 'abc';
}
};
console.log((new App.constant).CONST1);
fiddle demo.
If you just want to create a set of "constants", all you need is an object:
// #global-constants
var App = {
constant: {
CONST1: 'abc';
}
};
To learn more about how prototypes work (so that you know when to use them and when not), I recommend to read this article on MDN.
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);
Apologies for the title but I wasn't sure how to phrase this.
In a normal module you have the following format:
var SomeClass = function() {
...
};
module.exports = SomeClass;
You can shorthand that to:
module.exports = function() {
...
};
There is however a problem with the second notation if you need to use the 'class' name inside itself ( to instantiate a new object of itself for example). Using the 1st example this would be easy ...
var SomeClass = function() {
...
function doSomething() {
var x = new SomeClass();
}
...
};
module.exports = SomeClass;
Is this possible using the 2nd notation? I know I can't use 'this' as that is an instance variable, I also can't use any form of the module.
module.exports = function() {
...
function doSomething() {
var x = new ??????
}
...
};
I'm asking purely from an aesthetic and a uniformity point of view.
Any Help appreciated.
Thanks
It is possible to do this in the form that you describe. Theoretically, to you in that scope, there is no difference between SomeClass and module.exports: both are variables and you give them both the same value.
Therefor, if you wanted, you could have something like this (though it looks odd):
module.exports = function() {
// ...
function doSomething() {
var x = new module.exports();
}
// ...
};
i need to create a javascript function with a private variable that has setter and getter methods. i tried:
function createSecretHolder(secret) {
this._secret = secret;
var getSecret = function(){
return this._secret;
}
var setSecret = function(secret){
this._secret = secret;
}
}
and a version with:
this.getSecret = function()...
and
this.seSecret = function()...
it is not passing the test suite on code wars. something like
var obj = createSecretHolder(secret);
obj.getSecret();
obj.setSecret(newSecret);
and others which are hidden. I get an error TypeError: Cannot read property 'getSecret' of undefined and another cannot call method setSecret
createSecretHolder() doesn't return a value so createSecretHolder(secret) returns undefined.
So var obj = createSecretHolder(secret); sets obj to undefined. Hence the error "Cannot read property 'getSecret' of undefined" when you try to access obj.getSecret().
Even if it returned an object, you have declared getSecret using var inside a function. Variables described that way are scoped to the function. So when you try to access it outside the function, as you do in obj.getSecret(), that won't work.
You also seem to misunderstand how this works. It will not create a private variable.
There are a number of ways to do this. Here's one:
function createSecretHolder(mySecret) {
var secret = mySecret;
return {
getSecret: function(){
return secret;
},
setSecret: function (mySecret){
secret = mySecret;
}
};
}
When you use a Constructor to create an object you need to use the new keyword.
Inside your constructor you set a property with this._secret = secret. This is accessible from outside. It should be var _secret = secret.
Also you create local functions inside your object to get/set _secret. They should be methods of the object. See below.
// object constructor
function createSecretHolder(secret) {
// local variable. it isn't accessible from outside
var _secret = secret;
// method to get the secret
this.getSecret = function() {
return _secret;
}
// method to set the secret
this.setSecret = function(secret){
_secret = secret;
}
}
// create new "createSecretHolder" object
var secret = new createSecretHolder("secret 1");
secret.getSecret(); // returns "secret 1"
secret.setSecret("secret 2");
secret.getSecret(); // returns "secret 2"
Look into prototypejs OO programming.
If you can't use prototypejs because of jQuery conflicts, there is a version of it only with OO support here: https://github.com/Prescia/Prototypejslt
Your could would look like:
createSecretHolder= Class.create();
createSecretHolder.prototype = {
_secret: 0,
othervariable: true,
initialize: function(inSecret) { // this is the constructor on prototypejs
this._secret = inSecret;
}
}
// Create instance:
var myInstance = new createSecretHolder(5);
// so this should alert "5":
alert(myInstance._secret);
I can't live without prototypejs Object Orientation, so I often use this light version that won't conflict with other stuff
I was just not sure how to search this out despite many tries, so forgive me if this has been answered before.
The question is simple: can I create an instance of class window.A.class() as window.B?
To clarify, I have an object literal holding all my data for a browser game:
var gameName = {
environment: function() {
this.place = "...";
// ...
// ...
},
game: function() {
this.player = function() {
// ...
}
}
// and so on...
}
Could I create a window-level gameName.environment() instance with var A = new gameName.environment()? Are there any restrictions to creating an object-bound class's instance outside the class' parent object?
It doesn't really matter in this case how/where a function is defined. Consider these two examples:
function Foo() {}
var obj = {
bar: Foo
};
and
var obj = {
bar: function () { }
};
As far as the function and the object are concerned, those two examples are equivalent. So no, there is no problem calling a function assigned to an object property with new. All you need is a reference to the function, it doesn't matter how you get that reference.
You could do
var Environment = gameName.environment;
var A = new Environment();
if you like that better, but that's totally unnecessary.
How can I hook up an event to a function name I have defined as a string?
I'm using Prototype.js, although this is not Prototype-speficic.
$(inputId).observe('click', formData.fields[x].onclick);
This would result in JavaScript complaining that my handler is not a function. I would prefer not us use eval().
Property accessors can be used to access any object's properties or functions.
If the function is in the global scope, you can get it using the window object:
var myFunc = window[myFuncName];
This also works within the this scope:
var myFunc = this[myFuncName];
I have worked on this problem, as I needed a function like this. Here is my sandbox code, not thoroughly tested, but can be a startpoint for others.
Note that there is one eval() in the code as I couldn't figure out how to bypass that step, maybe a javascript quirk and cannot be done in any other way. Let me know if there is a way to get rid of eval() here!
executeFunctionByName = function(functionName)
{
var args = Array.prototype.slice.call(arguments).splice(1);
//debug
console.log('args:', args);
var namespaces = functionName.split(".");
//debug
console.log('namespaces:', namespaces);
var func = namespaces.pop();
//debug
console.log('func:', func);
ns = namespaces.join('.');
//debug
console.log('namespace:', ns);
if(ns == '')
{
ns = 'window';
}
ns = eval(ns);
//debug
console.log('evaled namespace:', ns);
return ns[func].apply(ns, args);
}
core = {
paragraph: {
titlebar: {
user: "ddd",
getUser: function(name)
{
this.user = name;
return this.user;
}
}
}
}
var testf = function()
{
alert('dkdkdkd');
}
var x = executeFunctionByName('core.paragraph.titlebar.getUser', 'Ikon');
executeFunctionByName('testf');
... or this[myFuncName];
Perhaps?
setTimeout ( "myFunc()", 1 );
Just an eval would do the job
var call = eval("method_name").call(args);
Looks like formData.fields[x].onclick holds the name of a global function? If so try:
$(inputId).observe('click', window[formData.fields[x].onclick]);
window.myFunction === window["myFunction"]
Do you know what the onclick property contains or what type it is? I assume this is prototype specific stuff, as "fields" does not exist in DOM forms.
If you need to call a string function with arguments, do this:
window[stringFunctionName].apply( window, arrayOfArguments )
You can use scope in place of window if preferred
update:---
use ES6 export and import
a.js
const fn = {
aaa: function() {
//code
},
bbb: function() {
//code
},
//codes ....
nnn: function() {
//code
}
}
export default fn
b.js
import someFn from './a'
//eg
const str1='aaa'
const str2 = 'bbb'
someFn[str1]()
eval('str') (obsolete feature https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features )
setTimeout('str') setInterval('str')
window['str'] (but...sometimes,global object is not window)
new Function('str')
These methods above always not be recommend by some reasons, but they are really convenient to use.
These methods below are safe, but really not conveninet to use.
switch...case (or if...else)
switch(str){
case 'str1':
fn1()
break
case 'str2':
fn2
//and so on
}
put functions in a object
const fn={
str1:fn1,
str2:fn2
//and so on
}
fn[str1] //call function