How to check class and function existence? - javascript

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.

Related

placing function within function javascript

Below code doesn't work, but my idea is to wrap functions into one function, and call the parent function with param. The param will be used by their children function.
_abc(elem){
a(elem){
return elem + 'a';
}
b(elem){
return elem + 'b';
}
}
_abc(elem).b() // doesn't work?
You need to mark your functions as functions, remove the inner elem parameters, and return an object containing the functions:
function _abc(elem){
function a(){
return elem + 'a';
}
function b(){
return elem + 'b';
}
return { a:a, b:b };
}
console.log(_abc('hello').b());
Another way to write this this without repeating the function names multiple times:
function _abc(elem){
return {
a: function () {
return elem + 'a';
},
b: function () {
return elem + 'b';
}
};
}
console.log(_abc('hello').b());
And one more, as suggested by #4castle. This one is only supported by JavaScript environments that support EcmaScript 6:
function _abc(elem){
return {
a() {
return elem + 'a';
},
b() {
return elem + 'b';
}
};
}
console.log(_abc('hello').b());
You might me looking for a Java-oriented object, like so:
function _abc(elem)
{
this.elem = elem;
this.a = function()
{
return this.elem + 'a';
}
this.b = function()
{
return this.elem + 'b';
}
}
console.log(new _abc('Hey ').a());

check if string variable name is a javascript fuction of an object

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

Can I eval expression in object context?

Good day. I need to eval expression in some object context, but the only solution I found is to create stubs for every object function:
var c = {
a : function () {
return 'a';
},
b : function () {
return 'b';
}
};
function evalInObj(c, js) {
function a() {
return c.a();
}
function b() {
return c.b();
}
return eval(js);
};
console.log(evalInObj(c, 'a() + b()'));
Show me the right way, please. Can I do it with prototype?
var C = function(id) {
this.id = id;
}
C.prototype.a = function () {
return 'a' + this.id;
}
C.prototype.b = function () {
return 'b' + this.id;
}
function evalCtx(js) {
console.log(this); // C {id: 1}
return eval(js);
}
var c1 = new C(1);
evalCtx.call(c1, 'a() + b()'); // error: a is not defined
For late-comers who are still looking for the solution of the issue (or the similar). Instead of using eval(), we can create anonymous function dynamically and evaluate the expression in the object context:
function evaluate(expression, context = {}) {
try {
// console.debug("[DEBUG] Dynamic anonymous function to be defined:\n%s", `function(${[...Object.keys(context)].join()}) {\n'use strict'; return (${expression})\n}`)
const fun = Function(...Object.keys(context), `'use strict'; return (${expression})`)
// console.debug("[DEBUG] Dynamically defined anonymous function:\n%o", fun)
const result = fun(...Object.values(context))
// console.debug("[DEBUG] Evaluation result: %o", result)
return result
} catch(error) {
if(error.message === `Unexpected token ')'`) throw SyntaxError('Unexpected token, likely at the end of expression.')
else throw error
}
}
To assert:
console.assert(evaluate('a===1 && b===2', {a: 1, b: 2}) === true)
console.assert(evaluate('a===1 && b===3', {a: 1, b: 2}) === false)
console.assert(evaluate('f()', {a: 1, f: ()=>11}) === 11)
(() =>
{
// 'use strict';
function run(expression, context = {})
{
return function ()
{
return eval(expression);
}.call(context);
}
let context = {a:{b:'Bb'}};
console.log(run('this', context)); // {a:{b:'Bb'}}
console.log(run('this.a', context)); // {b:'Bb'}
console.log(run('this.a.b', context)); // 'Bb'
console.log(run('a.b', context)); // ReferenceError: a is not defined
})();
The most notable advantage of this technique is that it work without the with keyword,
Thus even in strict mode
+function()
{
// jsut pollyfills for backward browsers...
Object.prototype.keys || (Object.defineProperty(Object.prototype, 'keys', {value: function ()
{
var result = []; for (var key in this) result.push(key); return result;
}}));
Object.prototype.entries || (Object.defineProperty(Object.prototype, 'entries', {value: function ()
{
var result = []; for (var key in this) result.push([key, this[key]]); return result;
}}));
// here the magic...
function run(expression, context)
{
var variables = {};
(context instanceof Object) && context.entries().forEach(function(entry)
{
entry[0].match(/^[a-z_$][a-z0-9_$]*$/) && (variables[entry[0]] = entry[1]);
});
return (new Function('return function(' + variables.keys().join(', ') + ') { return ' + expression + '; }'))()// first get the synthetic function
.apply(context, variables.entries().map(function(entry) { return entry[1]; }));
}
var output = run("a + '#' + b", {a: 'Aa', b: 'Bb', 0: 'Zero'});
console.log(output); // Aa#Bb
}();
function runScript(ctx, js){ with(ctx){ return eval(js); }}
closed. thanks all

JS function name interferes with object property

I'm trying to build a polyfill for getting the actual scrollposition.
function getScLPos() {
if (self.pageXOffset) return self.pageXOffset;
if (document.documentElement && document.documentElement.scrollLeft)
return document.documentElement.scrollLeft;
if (document.body.scrollLeft) return document.body.scrollLeft;
return 0;
}
But as it goes through the same condition checking procedure every function call.
I wanted to optimize the function by assigning a function reference to a global variable when it is called for the first time. Afterwards it reads the global variable (containing the funtion) and executes the function, but actually it doesnt work. When i call getScLPos() it still returns a function.
How ca I make getScLPos return an integer value?
Edit: typeof pageXOffset() says "function".
var getScLCallback = null;
function getScLPos() {
if (getScLCallback != null) {
return getScLCallback();
} else {
if (self.pageXOffset) {
getScLCallback = pageXOffset;
//says "function() {...}"
console.log(getScLCallback());
return getScLCallback();
} else if { ... }
} else {
return 0;
}
}
}
function pageXOffset() {
return self.pageXOffset;
}
Yes, function references exist in JavaScript. Functions are just objects. The thing you are doing wrong is you are assigning the result of the function to the variable, instead of assigning the function itself. To assign a function to a variable, simply use the function name, without the () at the end.
So, instead of:
getScLCallback = docScrollLeft();
do this:
getScLCallback = docScrollLeft;
Here is your updated code:
var getScLCallback = null;
function getScLPos() {
if (getScLCallback != null) {
return getScLCallback();
} else {
if (self.pageXOffset) {
// REMOVED the parentheses
getScLCallback = pageXOffset;
//says "function() {...}"
console.log(getScLCallback());
return getScLCallback();
} else if (document.documentElement && document.documentElement.scrollLeft) {
// REMOVED the parentheses
getScLCallback = docScrollLeft;
return getScLCallback();
} else if (document.body.scrollLeft) {
// REMOVED the parentheses
getScLCallback = bodyScrollLeft;
return getScLCallback();
} else {
return 0;
}
}
}
function pageXOffset() {
return self.pageXOffset;
}
function docScrollLeft() {
return document.documentElement.scrollLeft;
}
function bodyScrollLeft() {
return document.body.scrollLeft;
}
I actually made it work by renaming the pageXOffset function to pXOffset.
pageXOffset actually interfered with self.pageXOffset

Knockotjs Validation. Passing function gives undefined, because of property order inside VM

validation works fine if validation properties are placed after "HasError" property in VM.
In the case that the property placed before HasError I will get "parameters.hasError" as undefined. I think it's because the property "HasError" is not defined to that time.
Is there any solution without changing the order of the properties inside VM to make it work.
Thanks!
self._BusTypeDefault = function(param) {
var ret = param.BusType;
if(typeof(ret)==='undefined') {
ret = '';
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.BusType = ko.observable(self._BusTypeDefault(init)).extend({maxLength: {message: $Resources.PCIBUSError(), maxFieldLength: 255,hasError: self.HasError }});
self._HasErrorDefault = function(param) {
var ret = param.HasError;
if(typeof(ret)==='undefined') {
ret = false;
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.HasError = ko.observable(self._HasErrorDefault(init)).extend({errorAggregation: {}});
ko.extenders.maxLength = function (target, parameters) {
//add some sub-observables to our observable
target.hasMaxLengthError = ko.observable();
target.validationMessageMaxError = ko.observable();
//define a function to do validation
function validate(newValue) {
var preValue = target.hasMaxLengthError();
if (newValue.length >= parameters.maxFieldLength) {
target.hasMaxLengthError(true);
target.validationMessageMaxError(parameters.message || "This field is required");
}
else {
target.hasMaxLengthError(false);
target.validationMessageMaxError("");
}
if (parameters.hasError != null && target.hasMaxLengthError() !== preValue && typeof preValue !== 'undefined') {
parameters.hasError(target.hasMaxLengthError());
}
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
You can use a function to delay the interpretation of hasError:
this.myObservable = ko.observable(1).extend({ myExtender : { hasError: function () { return self.hasError } } });
Then in the extender you'll need to call the function to actually get the observable behind:
ko.extenders.myExtender = function (target, params) {
function validate(newValue) {
alert("New Value: " + newValue + " ; Has Error: " + params.hasError()());
}
target.subscribe(validate);
}
See this example: http://jsfiddle.net/7ywLN/

Categories