How to call a method in javascript from a variable? - javascript

I found some questions related to my question, but none of the answers solved my problem for some reason.
I want to call a method in javascript dynamically from a variable.
This is my code:
var malt_type;
export function json_handler(type){
malt_type = type;
try {
window[malt_type]();
} catch (e) {
console.log(e);
}
}
function SQL(){
console.log(malt_type);
}
I tried this also, but didn't work either
var malt_type;
export function json_handler(type){
malt_type = type;
try {
var fnName = malt_type + "()";
var fn = new Function(malt_type);
console.log(fn);
fn();
} catch (e) {
console.log(e);
}
}
function SQL(){
console.log(malt_type);
}
In the previous one the console.log(fn); writes this on the DevTools:
ƒ anonymous(
) {
SQL()
}
And the error I catch is like this (SQL is the content of the variable):
ReferenceError: SQL is not defined
at eval (eval at json_handler (json_handler.js:11), <anonymous>:3:1)
at Module.json_handler (json_handler.js:13)
at Show (server.js:39)
at Socket.<anonymous> (server.js:20)
at Socket.emit (events.js:314)
at TCP.<anonymous> (net.js:672)
My reason is that I want to do this is because I want to handle logs and the type of them differently.

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 created.
https://developer.mozilla.org/.../Function
The above basicaly means the fn function doesn't have access to SQL variable.
You could try it like this:
var malt_type;
export function json_handler(type){
malt_type = type;
// if it exists execute it
functions[type] && functions[type]();
}
const functions = {
SQL: function SQL(){
console.log(malt_type);
}
};

You can do it as illustrated below.
var malt_type;
function json_handler(type){
malt_type = type;
try {
window[malt_type](); //assuming your SQL() function is defined on the `window` object
} catch (e) {
console.log(e);
}
}
function SQL(){
console.log(`${malt_type} function ran.`);
}
json_handler("SQL");

Related

Creating JS library with dynamic function calling

I'm creating a JS 'library' file, But I want to encapsulate it in it's entirety within an object, to avoid contaminating namespace of the pages that include the file
The twist to this is within a function inside the library I need to call others functions within library by name, eg using window[]
The code below is just a sample there would actually be several hundred functions that could be called by name. It's this that's caused by trouble as I can't get window[] to reference the function, what's the right way to go about this?
I have tried this, in host page:
<script src= "mylib.js"></script>
var oMyLib = new cMyLib(); //there will only ever be one 'instance' of this
In mylib.js everything is contained in one function:
function cMyLib() {
this.doStuff = function () {
someFunc(this); //call another function in the lib
}
// I tried it with prototypes also
// cMyLib.prototype.doStuff = function () {
// someFunc();
// }
function someFunc(that) {
var s='anotherFunc1'
var f = window[s]; //undefined!
f();
s='anotherFunc2'
f=window[s];
f();
}
function anotherFunc1() {}
function anotherFunc2() {}
}
The functions that you want to reference by name (or actually by number, according to your comments) should be part of that object, and not accessed via window, e.g.:
function cMyLib() {
// allow call without new
if (! (this instanceof cMyLib)) {
return new cMyLib();
}
// enforce singleton
if (this.constructor.singleton) {
return this.constructor.singleton;
} else {
Object.defineProperty(this.constructor, 'singleton', {
value: this
});
}
// instruction array (no need to expose via `this`)
var insn = [];
insn[0x4c] = function lda_immediate() { ... }
// instruction execution
this.step = function() {
var opcode = memory[pc++];
if (opcode in insn) {
// `.call` ensures `this` is set inside the instruction fn.
insn[opcode].call(this);
} else {
hcf();
}
}
}
Note the extra stuff at the top - convenience code to ensure that only one cMyLib can exist.
As long as a function is in parent scope you can just reference it directly, i.e.
function someFunc(that) {
anotherFunc1();
};
will simply work.
Another thing is that classical way to do this is to wrap everything in a self-calling anonymous function, i.e.
(function() {
function anotherFunc1() {};
function anotherFunc2() {};
this.cMyLib = function() { ... };
})();
But your approach is fine as well.
If you wish to call your functions by dynamic name, then you can store them in a top level object:
(function() {
var my_functions = {
anotherFunc1: function() {},
anotherFunc2: function() {}
};
this.cMyLib = function() {
var name = 'anotherFunc1';
my_functions[name]();
};
})();
It's like creating an isolated "global" scope.
Side note: Do not use eval. It is very unsafe and slow. It will backfire at you at some point.

javascript reference to prototype function is undefined in constructor

Given the following object:
function MyObject() {
window.myFunc1 = this.myFunc1;
window.myFunc2 = this.__proto__.myFunc2;
}
MyObject.prototype.anotherFunc = function () {
window.myFunc3 = this.myFunc3;
window.myFunc4 = this.__proto__.myFunc4;
}
MyObject.prototype.myFunc1 = function () { console.log(1); }
MyObject.prototype.myFunc2 = function () { console.log(2); }
MyObject.prototype.myFunc3 = function () { console.log(3); }
MyObject.prototype.myFunc4 = function () { console.log(4); }
var o = new MyObject();
o.anotherFunc();
window.myFunc1();
window.myFunc2();
window.myFunc3();
window.myFunc4();
In fiddle I'm getting what is expected, but when testing with an ios app under ionic framework the results (tested with safari debugger) are:
window.myFunc1 -> undefined
window.myFunc2 -> it works!
window.myFunc3 -> it works!
window.myFunc4 -> it works!
Isn't the prototype attached to the object before it is created?
EDIT
attached fiddle and working example, fine tuned the question
It may happen if you create your object in an unusual way, and this is bound to something different from what you expect. In my case I was exporting a constructor from the node module, and creating an object with new require('module')();, which had the same effect of prototype functions being undefined.
I'm getting the following results […]
I cannot reproduce that. Try this:
function MyObject() {
console.log(this.myFunc1);
console.log(Object.getPrototypeOf(this).myFunc2);
}
MyObject.prototype.anotherFunc = function () {
console.log(this.myFunc3);
console.log(Object.getPrototypeOf(this).myFunc4);
}
MyObject.prototype.myFunc1 = function () { }
MyObject.prototype.myFunc2 = function () { }
MyObject.prototype.myFunc3 = function () { }
MyObject.prototype.myFunc4 = function () { }
var o = new MyObject();
o.anotherFunc()
Isn't the prototype attached to the object before it is created?
Uh, no. The prototype cannot really be attached to a non-existing object :-) Best think of it as happening simultaneously, that an object is created with a prototype, it doesn't exist without one.
What you might have meant that the object (with its prototype) is created before the constructor is executed - yes.

IIFE and objects in JS

Trying to do this
/*Javeline Javascript simple forum API by Makerimages v1.0*/
(function(){
Javeline={};
alert("hia");
Javeline.isNameSpace=true;
alert("hia");
Javeline.toString= function() { return "Javeline"; };
Javeline.Application=Application();
Javeline.Application.create();
alert("appmade");
}());
function Application()
{
function create()
{
Javeline.Application=this;
alert(Javeline.Application);
}
}
why wont the code not run Javeline.Application.create() ?
also the toString returns everything on that line after the =
This is probably what you want:
Javeline.Application=new Application();
//....
function Application()
{
this.create = function()
{
Javeline.Application=this;
alert(Javeline.Application);
}
}
Just calling Application will return undefined, since the function doesn't have a return statement. Calling it with the new keyword will give you a new object. However, to add the function create as a property to this new object, you have to declare it as a property of this inside of create.

Calling public method within module javascript

I'm trying to call a public method from within the module pattern.
I'm using the module pattern because it allows for splitting into various different JS files, to make the code more organised.
However when I call the public method, I get a TypeError and also typeof remains undefined.
Please help!! Thanks in advance.
main.js
function MainObject() {
this.notify = function(msg) { console.log(msg); }
}
var connObj = require("./myextobj");
var mainObj = new MainObject();
connObj.connection.handle = mainObj;
console.log(typeof connObj.connection.connect); // undefined
connObj.connection.connect(); // TypeError: Object has no method 'connect'
myextobj.js
module.exports = {
connection: function () {
this.handle = eventhandle;
this.connect = function() {
// connect to server
handle.notify("completed connection....");
}
}
}
It's because you're exporting an object containing connection: function (), which is a constructor function and needs newing-up. Then you can access the this properties attached to that particular instance:
var connection = require("./myextobj").connection; // reference the constructor function
var conn = new connection(); // new-up connection
console.log(typeof conn.connect); // -> function
Edit:
If the only thing exported by myextobj.js is the constructor function, there's no need to wrap it up in a literal object. I.e. you could do:
module.exports = function Connection() {
this.handle = eventhandle;
this.connect = function() {
handle.notify("completed connection....");
}
}
then use like so:
var Connection = require("./myextobj");
Note: .connection is no longer appended to the end to reference the function.
Give this a shot.
var module = {};
module.exports = {
connection: function () {
return {
handle: eventhandle,
connect: function () {
// connect to server
handle.notify("completed connection....");
}
}
}()
}
module.exports.connection.connect()

TypeError xxx is not a function

All, I am struggling with an error which says TypeError: curTemplete.addSection is not a function, Please forgive that I am not familiar with the js OO, Please help to review my problem. thanks.
The code looks like below.
Templete.js
LayoutTemplete=function(currentTmpContainer,templeteId,data)
{
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
this.addSection = function(uiItem, data) {
alert('ddd');
};
};
In the dom ready event.
function loadTempleteContent(templeteId)
{
var jData=[{name: 'jerry'},{name: 'mike'},{name: 'claire'}];
var tmp = new LayoutTemplete($("#currentTmpContainer"),templeteId,jData);
}
You cannot call a function before it was defined. This has nothing to do with OOP. Consider this example:
foo();
var foo = function() {
alert(42);
};
It will throw a similar error.
Define the function/the property before you access it:
this.addSection = function(uiItem, data) {
alert('ddd');
};
this.addSection(null, null);
Better yet, define addSection on the prototype, so that you don't create a new function every time you create an instances of LayoutTemplete.
LayoutTemplete = function(currentTmpContainer,templeteId,data) {
this.addSection(null, null);
};
LayoutTemplete.prototype.addSection = function(uiItem, data) {
alert('ddd');
};
Felix is trying to tell you what your issue is, here it is explicitly:
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
Here you reference and attempt to call curTemplete.addection, which has not been assigned a value yet, so it resolves to undefined. When the call is attempted, undefined is not a function (as the error tells you). addSection is not defined until the assignment below:
this.addSection = function(uiItem, data) {
alert('ddd');
};
Now it's defined. Move the assignment before the call (and if you're going to assign this to a local variable, you may as well use it):
var curTemplete = this;
curTemplete.addSection = function(uiItem, data) {
alert('ddd');
};
curTemplete.addSection(null, null);

Categories

Resources