How to check if function exists inside another function using Javascript - javascript

I`m trying to build an function that load script on-demand. That is my current code:
function loadScript(src, name = null)
{
var dfd = jQuery.Deferred();
if (name === null) {
name = src.split(/\\|\//); // split by folder separator
name = name[(name.length - 1)].split('.'); // catch last index & split by extension
name.splice(name.length - 1, 1) // Remove last
name = name.join('.'); // add points in the middle of file name
}
if ( typeof name === 'function' ) return dfd.promise().resolve(name);
$.getScript( src )
.done(function( script, textStatus ) {
dfd.resolve(name);
})
.fail(function( jqxhr, settings, exception ) {
dfd.reject(exception);
});
return dfd.promise();
}
My problem is on this part of code:
if ( typeof name === 'function' ) return dfd.promise().resolve(name);
Where name is a variable that contains desired function name to check, but not the real function name, causing function never evaluate as 'function'.
I tried:
typeof `${name}` // resulting a "string"
eval("typeof name === 'function'") // But my node system not accept eval due to a potentially security risk
How many alternatives that I have ?

You could do typeof eval(name) === function or if the function is a global, typeof window[name] === function
Demo:
(function() {
function test() {}
(function(name) {
console.log(typeof eval(name) === 'function');
})('test');
})();

Quick and dirty:
if ( typeof name === 'string' && typeof eval(name) === 'function' ) return dfd.promise().resolve(name);
since you probably want to double-check that name is actually a before passing it to eval. You probably also want to further validate it if it's coming from user input as you could be opening yourself up to script injections.

Hope this could helps anyone;
const getFunc = (s) => {
const a = s.split(".");
let obj = window, i = 0;
while (i < a.length && (obj = obj[a[i++]]) !== undefined);
if (typeof obj === "function") return obj;
};
console.log(getFunc("Infinity.isFloat"));

Related

Typescript .forEach and for in behavior

I made a Typescript playground to show you the code and the output. I don't understand why I don't have the same result in my code when I'm using .forEach and for in loop.
I made 2 functions to trim all body parameters. The first function use .forEach() and the 2nd use for in.
Here is the functions:
function trimWithForEach(obj: any): any {
if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach(function (prop) {
// if the property is an object trim it
if (typeof obj[prop] === 'object') {
return trimWithForEach(obj[prop]);
}
// if it's a string remove begin and end whitespaces
if (typeof obj[prop] === 'string') {
obj[prop] = obj[prop].trim();
}
});
}
}
function trimWithForIn(obj: any): any {
if (obj !== null && typeof obj === 'object') {
for (var prop in obj) {
// if the property is an object trim it
if (typeof obj[prop] === 'object') {
return trimWithForIn(obj[prop]);
}
// if it's a string remove begin and end whitespaces
if (typeof obj[prop] === 'string') {
obj[prop] = obj[prop].trim();
}
}
}
}
With the forEach() I have the good result that I want, it will trim all my body. But with for in I have a problem because only the first object conditon is triggered to make my recursive call and if I have other object types they are ignored. The recursive call works only once in all my body object in the for in loop and I don't know why.
Can you help me to understand ?
In for..in loop the return is returning you out of function at the very first time it encounters the condition to be true. That's why the later items never get processed.
I am not quite sure what you are trying to do here but there is a basic difference between the way 'forEach' and 'for...in' works with regards to 'return'.
In for...in return returns the value out of function, but in forEach the return doesn't work.
Look at the following simple example for more clarity
var testfn = function() {
let a = [1,2,3]
let b = a.forEach(el => {
if ( el == 2 )
return el
})
console.log("Came here!")
console.log({b})
}
var testfn1 = function() {
let a = [1,2,3]
for ( let i in a ){
if ( a[i] == 2 )
return a[i]
}
console.log("Came here!")
console.log({a})
}
testfn()
testfn1()

Checking if variable exist JavaScript & jQuery in best and quick and smallest way

Hey guys i have an some jQuery-JavaScript code and its made by some undefined variable.
I trying to skip (undefined) error by doing this code :
if(typeof undefined_var !== "undefined"){
/*My code is here*/
}else{
/*create variable*/
/*My code is here*/
}
But the problem is i have a lot of variable and i have to use a big code like this :
if(typeof undefined_var1 !== "undefined" && typeof undefined_var2 !== "undefined" && typeof undefined_var3 !== "undefined" /* && more */ ){
And its not optimized i looking for something better than it like this :
if(undefined_var1 && undefined_var2 && undefined_var3)
Is there anyway?
You can make an array containing all those variables and then make a function which takes that array as an argument. Then inside the function loop through the array using the conditional (if statement) to determine if any are false. For example arr.reduce((bln, myVar) => typeof myVar === 'undefined' && bln, true). Call the function and it will return true or false depending on if any were undefined.
var _0;
var _1;
var _2 = 'not undefined';
var _3 = 'again not undefined';
const test0 = [_0, _1]; //should return true (contains undefined)
const test1 = [_2, _3]; //should return false (doesn't contain undefined)
const test2 = [_0, _1, _2, _3]; //should return true (contains undefined)
function containsUndefined(arr){
//loop array to determine if any are undefined
return arr.reduce((bln, myVar) => typeof myVar == 'undefined' && bln, true);
}
console.log('test0', containsUndefined(test0));
console.log('test1', containsUndefined(test1));
console.log('test2', containsUndefined(test2));
At whatever point that the variables are defined, put them onto a single object instead, then all you have to do is check if the object exists yet:
if (!window.myObj) {
// Define properties:
window.myObj = {
prop1: 'val1',
prop2: 'val2',
// ...
};
}
// proceed to use `window.myObj.prop1`, etc

JS: And if every function return "this" as a default value?

I have a code design question. Consider the following code:
thatObj.doThis().setThat().add().update();
To allow chaining, I'm often writing return this;, and sometimes, here or there I forget to do it, then I got an error.
In many cases, I'm not asking for a particular result (e.g. thatObj.getName() or thatObj.getChildren()), but instead wanting to do some updates or calling setters (e.g. thatObj.setName("foo") or thatObj.addChild(child) or thatObj.update()), I was wondering if it would be more convenient to return this; for any call of methods, I mean as a javascript default behaviour, and if not, what could be the reasons not to do so.
JS returns undefined if you don't return something explicitely,
JS constructors return this unless your constructor returns an Object.
CoffeeScript returns the last expression by default,
You want this to be returned by default by all methods on an object
everybody has it's own opinion what's the "right" way to do it.
could it be a good idea to say from now JS will always return this from any methods ?
And from one moment to the other, at least 2/3 of the web will be broken. So, tell me, is it a good idea?
JS has set its rules a long time ago, and something that basic is not going to change (as Pointy already mentioned). So why don't you take care of that behaviour:
//extracted that from the function to avoid memory leakage
function wrapFunction(fn) {
return function() {
let result = fn.apply(this, arguments);
return result === undefined ? this : result;
}
}
//filter === false => only own methods
//filter === true => own methods and inherited methods
//filter is Array => only the passed keys (if they are methods)
//filter is RegExp => use the RegExp to filter the keys
//filter is function => regular filterFunction
function returnThisAsDefault(objectOrConstructor, filter = false) {
if (objectOrConstructor !== Object(objectOrConstructor))
throw new TypeError("Passed argument must be an object or a constructor. Got ", typeof objectOrConstructor);
const validKey = key => typeof proto[key] === "function" && key !== "constructor" && key !== "prototype";
let proto = typeof objectOrConstructor === "function" ?
objectOrConstructor.prototype :
objectOrConstructor;
let filterFn = Array.isArray(filter) ? filter.includes.bind(filter) :
filter === false || filter === true ? () => true :
filter instanceof RegExp ? filter.test.bind(filter) :
typeof filter === "function" ? filter :
() => false;
let wrapped = {};
for (let p = proto, done = new Set(["constructor", "prototype"]); p != null && p !== Object.prototype;) {
for (let key of Object.getOwnPropertyNames(p)) {
if (typeof proto[key] !== "function" || done.has(key) || !filterFn.call(p, key)) continue;
done.add(key);
let d = Object.getOwnPropertyDescriptor(p, key);
//typeof d.value !== "function" means that proto[key] contains a getter returning a function
if (!d.writable && !d.configurable || typeof d.value !== "function") {
console.log(`function ${JSON.stringify(key)} not fit to be wrapped`, d);
continue;
}
d.value = wrapFunction(d.value);
wrapped[key] = d;
}
if (filter === false) break;
else p = Object.getPrototypeOf(p);
}
Object.defineProperties(proto, wrapped);
return objectOrConstructor;
}
let thatObject = returnThisAsDefault({
doThis() {
console.log("doThis()");
},
setThat() {
console.log("setThat()");
},
add() {
console.log("add()");
},
update() {
console.log("update()");
return "success";
},
});
let result = thatObject.doThis().setThat().add().update();
console.log("result: ", result);
.as-console-wrapper {
top: 0;
max-height: 100%!important
}

SendBird create GroupChannel with file as cover

I'm trying to create a group Channel with a cover photo,
this.sendBirdInstance.GroupChannel.createChannelWithUserIds(userIds, true, this.groupName, this.groupPhotoFile, '', function (createdChannel, error) {
...
}
According to the documentation I can add a url or a file
coverUrl : the file or URL of the cover image, which you can fetch to
render into the UI.
But when adding a file, I'm always getting : "SendBirdException", code: 800110, message: "Invalid arguments."
Is there a way to create a group with a file instead of a url (since I want the user to upload the file) ?
Thanks,
As you have already experienced (I saw that you have created an issue in GitHub several days ago) the support of SendBird is kinda unreliable.
The fact that they offer just a minified version of their JavaScript SDK (which personally I find very poor) is helping either.
Anyway, I could isolate the createChannelWithUserIds function:
! function (e, n) {
// ...
}(this, function () {
// ...
var h = function (e) {
for (var n in e) if (e.hasOwnProperty(n)) return !1;
return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
},
// ...
A = function () { // it returns SendBird function
// ...
var w = function (e) { // w is this.GroupChannel
// ...
w.createChannelWithUserIds = function () {
// ...
// here comes the param validation (I've added spaces for a better lecture):
if (!Array.isArray(e) || "boolean" != typeof n || "string" != typeof t && null !== t && void 0 !== t || "string" != typeof r && h(r) && null !== r && void 0 !== r || "string" != typeof a && null !== a && void 0 !== a || "string" != typeof i && null !== i && void 0 !== i) return void U(null, new p("Invalid arguments.", J.INVALID_PARAMETER), s);
// It will return "Invalid arguments." if any of the conditions evaluates to true
// ...
}
}
}
return function () {
// ...
}().SendBird
});
You are using the function like this:
createChannelWithUserIds(o, n, t, r, a, s);
So the fourth parameter (r) is coverURL: the file with the cover picture (this.groupPhotoFile);
Its validation is basically saying that:
"string" != typeof r // if `r` is not a string (a URL)
&& h(r) // and the returned value of function h(r) is true
&& null !== r // and it is not null
&& void 0 !== r // and it is not undefined
that parameter is invalid.
Your file is not a string, not null and not undefined, so everything boils down to the h() function:
var h = function (e) {
for (var n in e) if (e.hasOwnProperty(n)) return !1;
return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
}
The function above check in first place if the object has any property what is a member of the object itself (i.e. not properties belonging to the prototype chain).
Then, if it doesn't have any own property, it checks if the stringify object/array is equal to an empty object/array.
I can't say what is the intention of the developers when validating files though this function, but a standard FILE object:
has properties in its prototype chain, but not directly assigned to the instance, so the first condition is true.
when stringify returns a empty object in all major browsers nowadays (it was not always like so), so the second condition is also true.
As we saw before, we need h() to return false: the validation fails if it returns true.
To fix this behavior you could change the h() function to something like:
var h = function( e ){
return !(e instanceof File);
// or return e.constructor != File;
// or return Object.getPrototypeOf( e ) != File.prototype );
// or return e.__proto__ != File.prototype )
// or return e.constructor.prototype != File.prototype )
}
but I won't mess with it. It could be used in future versions with a different purpose.
So your best bet is to change the createChannelWithUserIds() function to:
remove the call to the h() function from the validation.
replace it with a call to your own file validation
To do that, you could override the function in a SendBird instance:
var sb = new SendBird( { appId: ... } );
sb.GroupChannel.createChannelWithUserIds = function(){ ... };
But it is not guarantee to work and could break in future releases, so I would just edit the SendBird.min.js file.
In other words, replace:
if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof r&&h(r)&&null!==r&&void 0!==r||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);
with:
if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);
In the current version (v3.0.41) you will find two coincidences of the code above: one for createChannel and other for createChannelWithUserIds, you can replace both.
Of course, editing the .js file is annoying because you will need to take care to replace the code everytime you upgrade SendGrid.
You could create an automatic task inside your CI pipeline to do it for you, thought.
Hopefully, the SendGrid developers will acknowledge your issue and fix it in a future release.

How to check if function exists in JavaScript?

My code is
function getID( swfID ){
if(navigator.appName.indexOf("Microsoft") != -1){
me = window[swfID];
}else{
me = document[swfID];
}
}
function js_to_as( str ){
me.onChange(str);
}
However, sometimes my onChange does not load. Firebug errors with
me.onChange is not a function
I want to degrade gracefully because this is not the most important feature in my program. typeof gives the same error.
Any suggestions on how to make sure that it exists and then only execute onChange?
(None of the methods below except try catch one work)
Try something like this:
if (typeof me.onChange !== "undefined") {
// safe to use the function
}
or better yet (as per UpTheCreek upvoted comment)
if (typeof me.onChange === "function") {
// safe to use the function
}
I had this problem. if (obj && typeof obj === 'function') { ... } kept throwing a reference error if obj happened to be undefined, so in the end I did the following:
if (typeof obj !== 'undefined' && typeof obj === 'function') { ... }
However, a colleague pointed out to me that checking if it's !== 'undefined' and then === 'function' is redundant, thus:
Simpler:
if (typeof obj === 'function') { ... }
Much cleaner and works great.
Modern JavaScript to the rescue!
me.onChange?.(str)
The Optional Chaining syntax (?.) solves this
in JavaScript since ES2020
in Typescript since version 3.7
In the example above, if a me.onChange property exists and is a function, it is called.
If no me.onChange property exists, nothing happens: the expression just returns undefined.
Note - if a me.onChange property exists but is not a function, a TypeError will be thrown just like when you call any non-function as a function in JavaScript. Optional Chaining doesn't do any magic to make this go away.
How about:
if('functionName' in Obj){
//code
}
e.g.
var color1 = new String("green");
"length" in color1 // returns true
"indexOf" in color1 // returns true
"blablabla" in color1 // returns false
or as for your case:
if('onChange' in me){
//code
}
See MDN docs.
If you're using eval to convert a string to function, and you want to check if this eval'd method exists, you'll want to use typeof and your function string inside an eval:
var functionString = "nonexsitantFunction"
eval("typeof " + functionString) // returns "undefined" or "function"
Don't reverse this and try a typeof on eval. If you do a ReferenceError will be thrown:
var functionString = "nonexsitantFunction"
typeof(eval(functionString)) // returns ReferenceError: [function] is not defined
Try typeof -- Look for 'undefined' to say it doesn't exist, 'function' for a function. JSFiddle for this code
function thisishere() {
return false;
}
alert("thisishere() is a " + typeof thisishere);
alert("thisisnthere() is " + typeof thisisnthere);
Or as an if:
if (typeof thisishere === 'function') {
// function exists
}
Or with a return value, on a single line:
var exists = (typeof thisishere === 'function') ? "Value if true" : "Value if false";
var exists = (typeof thisishere === 'function') // Returns true or false
Didn't see this suggested:
me.onChange && me.onChange(str);
Basically if me.onChange is undefined (which it will be if it hasn't been initiated) then it won't execute the latter part. If me.onChange is a function, it will execute me.onChange(str).
You can even go further and do:
me && me.onChange && me.onChange(str);
in case me is async as well.
For me the easiest way :
function func_exists(fname)
{
return (typeof window[fname] === 'function');
}
Put double exclamation mark i.e !! before the function name that you want to check. If it exists, it will return true.
function abc(){
}
!!window.abc; // return true
!!window.abcd; // return false
//Simple function that will tell if the function is defined or not
function is_function(func) {
return typeof window[func] !== 'undefined' && $.isFunction(window[func]);
}
//usage
if (is_function("myFunction") {
alert("myFunction defined");
} else {
alert("myFunction not defined");
}
function function_exists(function_name)
{
return eval('typeof ' + function_name) === 'function';
}
alert(function_exists('test'));
alert(function_exists('function_exists'));
OR
function function_exists(func_name) {
// discuss at: http://phpjs.org/functions/function_exists/
// original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Steve Clay
// improved by: Legaev Andrey
// improved by: Brett Zamir (http://brett-zamir.me)
// example 1: function_exists('isFinite');
// returns 1: true
if (typeof func_name === 'string') {
func_name = this.window[func_name];
}
return typeof func_name === 'function';
}
function js_to_as( str ){
if (me && me.onChange)
me.onChange(str);
}
I'll go 1 step further to make sure the property is indeed a function
function js_to_as( str ){
if (me && me.onChange && typeof me.onChange === 'function') {
me.onChange(str);
}
}
I like using this method:
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
Usage:
if ( isFunction(me.onChange) ) {
me.onChange(str); // call the function with params
}
I had the case where the name of the function varied according to a variable (var 'x' in this case) added to the functions name. This works:
if ( typeof window['afunction_'+x] === 'function' ) { window['afunction_'+x](); }
The Underscore.js library defines it in the isFunction method as this (which comments suggest may cater for some browser bugs)
typeof obj == 'function' || false
http://underscorejs.org/docs/underscore.html#section-143
If you're checking for a function that is a jQuery plugin, you need to use $.fn.myfunction
if (typeof $.fn.mask === 'function') {
$('.zip').mask('00000');
}
Here is a working and simple solution for checking existence of a function and triggering that function dynamically by another function;
Trigger function
function runDynamicFunction(functionname){
if (typeof window[functionname] == "function") { //check availability
window[functionname]("this is from the function it"); // run function and pass a parameter to it
}
}
and you can now generate the function dynamically maybe using php like this
function runThis_func(my_Parameter){
alert(my_Parameter +" triggerd");
}
now you can call the function using dynamically generated event
<?php
$name_frm_somware ="runThis_func";
echo "<input type='button' value='Button' onclick='runDynamicFunction(\"".$name_frm_somware."\");'>";
?>
the exact HTML code you need is
<input type="button" value="Button" onclick="runDynamicFunction('runThis_func');">
In a few words: catch the exception.
I am really surprised nobody answered or commented about Exception Catch on this post yet.
Detail: Here goes an example where I try to match a function which is prefixed by mask_ and suffixed by the form field "name". When JavaScript does not find the function, it should throw an ReferenceError which you can handle as you wish on the catch section.
function inputMask(input) {
try {
let maskedInput = eval("mask_"+input.name);
if(typeof maskedInput === "undefined")
return input.value;
else
return eval("mask_"+input.name)(input);
} catch(e) {
if (e instanceof ReferenceError) {
return input.value;
}
}
}
With no conditions
me.onChange=function(){};
function getID( swfID ){
if(navigator.appName.indexOf("Microsoft") != -1){
me = window[swfID];
}else{
me = document[swfID];
}
}
function js_to_as( str ){
me.onChange(str);
}
I would suspect that me is not getting correctly assigned onload.
Moving the get_ID call into the onclick event should take care of it.
Obviously you can further trap as previously mentioned:
function js_to_as( str) {
var me = get_ID('jsExample');
if (me && me.onChange) {
me.onChange(str);
}
}
I always check like this:
if(!myFunction){return false;}
just place it before any code that uses this function
This simple jQuery code should do the trick:
if (jQuery.isFunction(functionName)) {
functionName();
}
I have tried the accepted answer; however:
console.log(typeof me.onChange);
returns 'undefined'.
I've noticed that the specification states an event called 'onchange' instead of 'onChange' (notice the camelCase).
Changing the original accepted answer to the following worked for me:
if (typeof me.onchange === "function") {
// safe to use the function
}
I have also been looking for an elegant solution to this problem. After much reflection, I found this approach best.
const func = me.onChange || (str => {});
func(str);
I would suggest using:
function hasMethod(subject, methodName) {
return subject != null && typeof subject[methodName] == "function";
}
The first check subject != null filters out nullish values (null and undefined) which don't have any properties. Without this check subject[methodName] could throw an error:
TypeError: (undefined|null) has no properties
Checking for only a truthy value isn't enough, since 0 and "" are both falsy but do have properties.
After validating that subject is not nullish you can safely access the property and check if it matches typeof subject[methodName] == "function".
Applying this to your code you can now do:
if (hasMethod(me, "onChange")) {
me.onChange(str);
}
function sum(nb1,nb2){
return nb1+nb2;
}
try{
if(sum() != undefined){/*test if the function is defined before call it*/
sum(3,5); /*once the function is exist you can call it */
}
}catch(e){
console.log("function not defined");/*the function is not defined or does not exists*/
}
And then there is this...
( document.exitPointerLock || Function )();
Try this one:
Window.function_exists=function(function_name,scope){
//Setting default scope of none is provided
If(typeof scope === 'undefined') scope=window;
//Checking if function name is defined
If (typeof function_name === 'undefined') throw new
Error('You have to provide an valid function name!');
//The type container
var fn= (typeof scope[function_name]);
//Function type
If(fn === 'function') return true;
//Function object type
if(fn.indexOf('function')!== false) return true;
return false;
}
Be aware that I've write this with my cellphone
Might contain some uppercase issues and/or other corrections needed like for example functions name
If you want a function like PHP to check if the var is set:
Window.isset=function (variable_con){
If(typeof variable_con !== 'undefined') return true;
return false;
}
To illustrate the preceding answers, here a quick JSFiddle snippet :
function test () {
console.log()
}
console.log(typeof test) // >> "function"
// implicit test, in javascript if an entity exist it returns implcitly true unless the element value is false as :
// var test = false
if(test){ console.log(true)}
else{console.log(false)}
// test by the typeof method
if( typeof test === "function"){ console.log(true)}
else{console.log(false)}
// confirm that the test is effective :
// - entity with false value
var test2 = false
if(test2){ console.log(true)}
else{console.log(false)}
// confirm that the test is effective :
// - typeof entity
if( typeof test ==="foo"){ console.log(true)}
else{console.log(false)}
/* Expected :
function
true
true
false
false
*/

Categories

Resources