How to check if the string parameter passed in a function is too callable/function but not directly under window..
I know the open/ directly callable function can be checked using the syntax window['functionName']
But how about the member function declared inside an object to be checked?
In below example openFunction() can be called but how to call obj1.foo()?
Prefer not to use eval()
Example Code:
var obj1 = {
foo: function() {
alert("I'm a function");
}
}
function openFunction() {
alert("I know i am easily callable");
}
function callSomeone(txtcallback) {
var fn = window[txtcallback];
if (typeof fn === 'function') {
fn();
}
console.log(typeof fn);
}
callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined
It returns undefined because, your code is equivalent to window["obj1.foo"] which is not correct.
The correct way to access to foo function is window["obj1"]["foo"].
So you have to "cycle" through the string obj1.foo.
Here I added a GetProp function that do that cycle and is recursive, so the level of nesting is not a problem.
var obj1 = {
foo: function() {
alert("I'm a function");
}
}
function openFunction() {
alert("I know i am easily callable");
}
function callSomeone(txtcallback) {
var fn = GetProp(window, txtcallback.split("."));
if (typeof fn === 'function') {
fn();
}
console.log(typeof fn);
}
function GetProp(obj, props) {
if(props.length == 0) {
return obj;
} else if(obj[props[0]] != undefined) {
obj = obj[props[0]];
return GetProp(obj, props.slice(1));
}
}
callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined
try this
var obj1 = {
foo: function() {
alert("I'm a function");
}
}
function openFunction() {
alert("I know i am easily callable");
}
function callSomeone(txtcallback) {
str =txtcallback.split(".");
temp = window;
for(check in str){
temp = temp[str[check]];
if (typeof temp === 'function') {
temp();
break;
}else if(typeof temp === 'undefined'){
break;
}
}
console.log(typeof temp);
}
callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //function
If you ant to look for members inside nested maps you have to use a recursive approach.
function callSomeone(txtcallback) {
var keyPath = txtcallback.split(".");
var fn = keyPath.reduce(function (member, key) {
return member[key];
}, window);
if (typeof fn === 'function') {
fn();
}
console.log(typeof fn);
}
the downside in this example is that the function is executed in the global scope. If you need to keep the scope of the container object you need to also save the scope.
var obj1 = {
foo: function() {
alert("I'm a function");
return this;
}
}
function openFunction() {
alert("I know i am easily callable");
return this;
}
function callSomeone(txtcallback) {
var keyPath = txtcallback.split(".");
var scope = null;
var context = null;
var fn = keyPath.reduce(function (member, key) {
scope = member;
return member[key];
}, window);
if (typeof fn === 'function') {
context = fn.call(scope);
}
console.log(typeof fn, context);
}
callSomeone('openFunction'); //function
callSomeone('obj1.foo'); //undefined
Related
Node.js
I have a function that works with different callbacks. Now I'm wondering if there is a better solution handling different callback functions.
My situation:
function prepare(type, callback){
let obj = {}; //in real is this an external database
for(let i=1; i<= 10; i++){
obj['progress_'+i] = 0;
}
if(type === 'createNewUser'){
callback(obj); //callback for function createNewUser(obj);
}
if(type === 'addToExistingUser'){
callback(obj); //callback for function addToExistingUser(obj);
}
}
My callback functions are:
createNewUser(obj){
//create new user with obj;
}
addToExistingUser(obj){
//add obj to existing user
}
2 ways to use prepare();
prepare('createNewUser', createNewUser);
prepare('addToExistingUser', addToExistingUser);
What is the best practice for this case? I would like to write good code.
How about this?
Basically it's called bracket notation you create a map that has REFERENCE to the function, you can call that function with the desired params.
var callbacks = {
createNewUser : createNewUserCallback,
addToExistingUser: addToExistingUserCallback
}
function prepare(type){
let obj = {};
for(let i=1; i<= 10; i++){
obj['progress_'+i] = 0;
}
callbacks[type](obj)
}
function addToExistingUserCallback(obj) {
// Do stuff
}
function createNewUserCallback(obj) {
// Do stuff
}
OR
var callbacks = {
createNewUser : (obj) => { // function code goes here.} ,
addToExistingUser: (obj) => {// function code goes here.}
}
function prepare(type){
let obj = {};
for(let i=1; i<= 10; i++){
obj['progress_'+i] = 0;
}
callbacks[type](obj)
}
To be fair option 1 is more readable.
You can try below example and add multiple callbacks in the same function according to your requirement -
function prepare(type, callback, secondcallback) {
let obj = {};
for (let i = 1; i <= 10; i++) {
obj['progress_' + i] = 0;
}
if (type === 'createNewUser') {
callback(obj); //callback for function createNewUser(obj);
}
if (type === 'addToExistingUser') {
secondcallback(obj); //callback for function addToExistingUser(obj);
}
}
prepare('createNewUser', function (data) {
console.log('First Callback data:', data);
}, function (data) {
console.log('Second Callback data:' + data);
})
prepare('addToExistingUser', function (data) {
console.log('First Callback data:', data);
}, function (data) {
console.log('Second Callback data:' + data);
})
If type is a string containing the name of the function to call, you can use window[functionName]()
function foo()
{
console.log("called foo");
}
function bar()
{
console.log("called bar");
}
function baz(str)
{
window[str]();
}
baz('foo');
baz('bar');
Or you can create your own object and store the functions in it :
const FunctionObject = {}
FunctionObject.foo = function ()
{
console.log("called foo");
};
FunctionObject.bar = function ()
{
console.log("called bar");
};
function baz(str)
{
FunctionObject[str]();
}
baz('foo');
baz('bar');
replace
if(type === 'createNewUser'){
callback(obj); //callback for function createNewUser(obj);
}
if(type === 'addToExistingUser'){
callback(obj); //callback for function addToExistingUser(obj);
}
With
fnc = window[callback];
if( fnc && typeof fnc === "function" ) { //make sure it exists and it is a function
fnc(); //execute it
}
I am not sure why you need type when you know what method to call or clarify if the type is not hardcoded, you simply can use prototypes as per your defined requirements.
function Prepare(obj) {
this.obj = obj;
}
Prepare.prototype = {
createNewUser(obj = this.obj) {
console.log('existing', obj);
},
addToExistingUser(obj = this.obj) {
console.log('new', obj)
}
}
let prep = new Prepare({a:1});
prep.createNewUser();
//or
prep.createNewUser({c: 3});
prep.addToExistingUser({b:2})
If the type is not hardcoded
function Prepare(type, obj) {
this.obj = obj;
this.callback = this[type];
}
Prepare.prototype = {
createNewUser(obj = this.obj) {
console.log('existing', obj);
},
addToExistingUser(obj = this.obj) {
console.log('new', obj)
}
}
//if type is not hardcoded
let prep = new Prepare('createNewUser');
prep.callback({d: 4});
I know I can run the following to determine if a normal Javascript function exists:
if (typeof yourFunctionName == 'function') {
yourFunctionName();
}
How does this work when I have the following:
Interface.prototype.yourFunctionName = function() { //ok };
You can simply check typeof Interface.prototype.yourFunctionName === "function", like so:
function Interface () {
this.a = "foo";
this.b = "bar";
}
Interface.prototype.yourFunctionName = () => "baz";
console.log(typeof Interface.prototype.yourFunctionName === "function");
I have following javascript code
function MyFunc () {
var add = function () {
return "Hello from add";
};
var div = function () {
return "Hello from div";
};
var funcCall = function (obj) {
if (!obj) {
throw new Error("no Objects are passed");
}
return obj.fName();
};
return {
func: function (obj) {
funcCall(obj);
}
};
}
var lol = new MyFunc();
When lol.func({fName: add}); is passed it should invoke the function private function add or when lol.func({fName: div}); is passed it should invoke the private div function. What i have tried does not work. How can i achieve this.
DEMO
In this case it's better to store your inner function in the object so you can easily access this with variable name. So if you define a function "map"
var methods = {
add: add,
div: div
};
you will be able to call it with methods[obj.fName]();.
Full code:
function MyFunc() {
var add = function () {
return "Hello from add";
};
var div = function () {
return "Hello from div";
};
var methods = {
add: add,
div: div
};
var funcCall = function (obj) {
if (!obj) {
throw new Error("no Objects are passed");
}
return methods[obj.fName]();
};
return {
func: function (obj) {
return funcCall(obj);
}
};
}
var lol = new MyFunc();
console.log( lol.func({fName: 'add'}) );
When you pass lol.func({fName: add}) add is resolved in the scope of evaluating this code, not in the scope of MyFunc. You have to either define it in that scope like:
function MyFunc () {
var add = function () {
return "Hello from add";
};
var div = function () {
return "Hello from div";
};
var funcCall = function (obj) {
if (!obj) {
throw new Error("no Objects are passed");
}
return obj.fName();
};
return {
add: add,
div: div,
func: function (obj) {
funcCall(obj);
}
};
}
var lol = new MyFunc();
lol.func({fName: lol.add});
Or use eval.
I have created a function to us for namespace but how to extend its functionality
code:
MY.property = function (str, obj, prevent) {
var ns = obj || MY,
k = str.split(".");
while (k.length > 1) {
if (!prevent && typeof ns[k[0]] === "undefined") {
ns[k[0]] = {};
}
if (ns[k[0]]) {
ns = ns[k.shift()];
} else {
return;
}
}
return [ns, [k[0]]];
};
MY.namespace = function (str) {
var ns = this.property(str),
k = str.split(".");
if (k[0] === "MY") {
k.shift();
}
if (ns && ns[0][ns[1]]) {
return;
} else {
ns[0][ns[1]] = {};
}
return true;
};
This only works for MY.namespace("test") , var My.test = function(){}; but how can I extend it like this MY.namespace("test", function(){ }); and MY.namespace("test", {});
Thanks for any help or advice.
example
The special operator typeof should be enough to accomplish this:
My.namespace = function (str, obj) {
if (obj) {
this[str] = obj;
}
....
My.namespace('test', function () {console.log('here');});
My.test()
EDIT: An updated example: http://jsfiddle.net/qk6Kj/1/
var a, kdApi;
a = (function() {
function a() {}
a.prototype.b = function() {
return "foo";
};
return a;
})();
kdApi = (function() {
function kdApi(className, funcName) {
if (typeof [className] !== "undefined" && ([className] != null)) {
eval("cu= new " + className + "()");
if (cu[funcName]) {
console.log("class and function exists");
} else {
console.log("class does, function doesn't");
}
} else {
console.log("both class and function doesn't.");
}
}
return kdApi;
})();
new kdApi("w", "b");
When I run this, I want to get both class and function doesn't exist message but instead I get w is not defined error. What am I doing wrong? Also, can I do it without eval?
var a, kdApi;
a = (function() {
function a() {}
a.prototype.c = 1;
a.prototype.b = function() {
return "foo";
};
return a;
})();
kdApi = (function() {
function kdApi(className, funcName) {
if (className != null && className in window) {
if (funcName != null && funcName in window[className].prototype &&
typeof window[className].prototype[funcName] == "function") {
document.write("class and function exists");
} else {
document.write("class does, function doesn't");
}
} else {
document.write("both class and function doesn't.");
}
}
return kdApi;
})();
function testCF(clazz, func) {
document.write("test for " + clazz + "." + func + "(): ");
new kdApi(clazz, func);
document.write("<br/>");
}
testCF("a", "b");
testCF("a", "c");
testCF("k", "b");
testCF("k", "c");
testCF(null, "c");
testCF("a", null);
Live demo: http://jsbin.com/ufubi5/5
Tested under Chrome 10.0.642.2 dev
The standard way of seeing it a function exists in JavaScript is to test if it is in the current scope. Hence the idiom:
if (funcName) {
funcName();
}
I believe there is something similar to see if it is a constructor function, but I'm not sure.