In PHP we can define the argument value for the functions if it's not set(called), so for example:
<?php
function blah($arg = false){
var_dump($arg);
}
?>
In the above example if we call the function like:
<?php
blah();
// ==> out put will be: false;
blah(true);
// ==> out put will be: true;
?>
So we can define a value for the arguments if they are not settled while we call the function, how this could be achieved in javascript functions?
I have it exactly like PHP:
<script>
function blah(arg = false){
//...
}
</script>
The above code works just fine in Mozilla Firefox, but in Chrome, the function is not working and gets fixed when I remove = false in the parenthesis, Chrome developer tools says:
Uncaught Syntax Error: Unexpected token =
This is not possible in Javascript.
Try this Conditional Operator statement instead:
<script>
function blah(arg){
arg = typeof arg !== 'undefined' ? arg : 'someValue';
}
</script>
Where 'someValue' is the default value that the arg variable will get when there are no arguments passed to the blah() function.
This is the cleanest pattern for implementing default arguments in javascript IMO.
function (arg) {
arg = arg || 'defaultVale';
}
However this can fail if you expect the value of arg to be some falsy value, e.g 0, false, NaN, null using it is not really recommended.
This version protects against this case by explicitly comparing with undefined.
function (arg) {
arg = arg === undefined ? 'defaultVale' : arg;
// As T.J Crowder pointer out if not in strict mode or if the code will run
// in an IFrame use typeof arg === "undefined" instead of directly
// comparing with undefined
}
Another nice pattern is using objects for arguments instead. This has two benefits
Order of arguments is not important
It's easy to implement default arguments
Code
var defaults = {
arg1: 10,
arg2: 20
};
var f = function (args) {
args = jQuery.extend(true, args, defaults); //jQuery
args = _.defaults(args, defaults); // Underscore
};
f({
a: 25 //Use a non default value
});
In JavaScript there is no default parameter.
Just write the code like:
function test(arg) {
if(arg) {
// do something as arg is defined.
} else {
// do something as arg is undefined.
}
}
test(true); // arg is defined
test(); // arg is undefined
Simple variation
function defaulter(p1) {
p1 = p1 || "default";
}
In Js you can't have default values for parameters. You can check if the data is of a known type with typeof operator:
function blah(arg)
{
if (typeof arg === 'undefined')
{
arg = false;
}
}
or setting his value in a short-circuit way
function blah(arg)
{
arg = arg || false;
}
For example in coffeescript you can set it by using
blah = (arg = "mydefaultvalue") ->
that is translated into
blah = function(arg)
{
if (arg == null)
{
arg = "mydefaultvalue";
}
}
Related
This is weird! I am struggling hard with the problem that javascript Proxy handler's apply trap does not get the Proxy itself passed as an argument, only the naked function. But I need to pass along some metadata to use for re-wrapping function results.
So I thought I could just use Object.create to make a specialization of the function to which I could stick additional information. But that doesn't work! And that's surprising!
function test() { return "hi!"; }
test() // 'hi!'
test1 = test // ƒ test() { return "hi!"; }
test1() // 'hi!'
test2 = Object.create(test) // Function {}
test2() // Uncaught TypeError: test2 is not a function
test3 = new Function([], "return 'lo!';") // ƒ anonymous() { return 'lo!'; }
test3() // 'lo!'
test2.prototype.constructor() // 'hi!'
test3.prototype.constructor() // 'lo!'
Object.getPrototypeOd(test2)() // 'hi!'
So I guess I can could help myself evaluate a function if I unwrapped it somehow:
while(fn instanceof Function && typeof fn != 'function')
fn = Object.getPrototypeOf(fn);
But that doesn't work if I just want to call it, i.e., make my special function transparent to any downstream user.
OK, here is a workaround, instead of using Object.create(fn) I can just wrap it:
fn = function() { return fn.apply(this, arguments); }
now I can stick my special metadata to this fn and I can also wrap it in a Proxy.
But my question is: what is the meaning of Object.create(fn) if you don't get an actual callable function?
Short answer: Function can be called; Object cannot be called.
See Function like inheritance of Object. Functions are object but objects are not function.
See this:
function test() { return "hi!"; }
test() // 'hi!'
typeof test // 'function'
test instanceof Object // true
test2 = Object.create(test)
typeof test2 // 'object'
test2 instanceof Object // true
typeof test2.prototype.constructor // 'function'
// something else that works
sample1 = Object.create({test})
typeof sample1 // 'object'
typeof sample1.test // 'function'
sample1.test() // 'hi!'
If you insist to make an Object callable, maybe your closest option is to create your own class that have function behaviour. There're some suggestions here: Can you make an object 'callable'?
I need the current function name as a string to log to our log facility. But arguments.callee.name only works in loose mode. How to get the function name under "use strict"?
For logging/debugging purposes, you can create a new Error object in the logger and inspect its .stack property, e.g.
function logIt(message) {
var stack = new Error().stack,
caller = stack.split('\n')[2].trim();
console.log(caller + ":" + message);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
You can bind function as its context then you can access its name via this.nameproperty:
function x(){
console.log(this.name);
}
x.bind(x)();
After little research here is a good solution :
function getFnName(fn) {
var f = typeof fn == 'function';
var s = f && ((fn.name && ['', fn.name]) || fn.toString().match(/function ([^\(]+)/));
return (!f && 'not a function') || (s && s[1] || 'anonymous');
}
function test(){
console.log(getFnName(this));
}
test = test.bind(test);
test(); // 'test'
Source : https://gist.github.com/dfkaye/6384439
Building on #georg solution, this one returns just the function name. Note though that it may fail if called from an anonymous function
function getFncName() {
const stackLine = (new Error())!.stack!.split('\n')[2].trim()
const fncName = stackLine.match(/at Object.([^ ]+)/)?.[1]
return fncName
}
function Foo() {
console.log(getFncName()) // prints 'Foo'
}
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables, and the Function.name property.
{
function foo() {
alert (a.name);
}; let a = foo
}
{
function foo2() {
alert(a.name)
}; let a = foo2
};
foo();//logs foo
foo2();//logs foo2
Note: Nested functions cease to be source elements, and are hence not hoisted. Also, this technique cannot work with anonymous functions.
If (like me) you want to define this elsewhere and call it generically, you can store the code as a string somewhere global or import it, then eval() it wherever to access the current function name. (Using eval keeps the context at the point of invocation.)
There's gotta be a way to do this without using a string, but whatever.
SomeObject.whatFunc =
'const s = new Error().stack;' +
"const stackLine = new Error().stack.split('\\n')[2].trim();" +
'const fncName = stackLine.match(/(?<=at )(.*)(?= \\()/gm)[0];' +
'console.log(fncName);'
// Whereever you want the func name
function countBananas('weeee') {
eval(SomeObject.whatFunc)
// blah blah blah
}
countBananas() // logs 'countBananas'
just an update to get the full name :
function logIt(message) {
var stack = new Error().stack,
// update is on this line
caller = stack.split('\n')[2].trim().split(/\s+/)[1];
console.log(caller.trim().split(/\s+/)[1];);
}
function a(b) {
b()
}
a(function xyz() {
logIt('hello');
});
I know if you want to check if a variable a is defined you can do this
if (typeof a !== 'undefined') {
// the variable is defined
}
but what if you want to make a function out of it, like this
function checkDefined(name) {
return typeof name !== 'undefined';
}
checkDefined("a");
this wouldn't work, but how can I get it to work if I have to pass a string version of the variable name?
Thanks
Checking in global scope(window):
var a = 'test';
var b = function() {};
function checkDefined(name) {
return typeof this[name] !== 'undefined';
}
console.log(checkDefined("a"));
console.log(checkDefined("b"));
console.log(checkDefined("c"));
If you want check if variable or function is declared in class object you should pass new context to checkDefined method:
function MyCustomClass() {
this.c = 'test';
}
function checkDefined(name) {
return typeof this[name] !== 'undefined';
}
// Create new object of type MyCustomClass
var myCustomClassObject = new MyCustomClass();
// In this way you can check if variable/function is defined in object
console.log(checkDefined.apply(myCustomClassObject, ["a"]));
console.log(checkDefined.apply(myCustomClassObject, ["b"]));
console.log(checkDefined.apply(myCustomClassObject, ["c"]));
apply will call a function immediately letting you specify both the value of this and any arguments the function will receive
Inspired by this answer. I think you can try to return with eval:
function checkDefined(name) {
return eval("typeof " + name) !== 'undefined';
}
Example:
var a = 1;
checkDefined("a") // true
checkDefined(a) // true
checkDefined("b") // false
Local variables are properties of the currently scoped this object.
const log = output => document.querySelector('pre')
.innerText += output + '\n'
/* In this example, running in the browser, `this` points to `window`, but
in other environments would still point to whatever is the global object.
Bind `this` to the ``checkDefined` so to ensure it keeps the same value
as where you are calling from. */
const checkDefined = function chkDef(v) {
return typeof this[v] !== 'undefined'
}.bind(this)
a = 5
log(checkDefined('a'))
log(checkDefined('b'))
/* This is the same basic idea, but we make it a little more portable by
not binding until right before we use it, so `this` has the correct
scope. */
unboundCheckDefined = function chkDef(v) {
return typeof this[v] !== 'undefined'
}
newScope()
function newScope() {
c = 5
const checkDefined =
unboundCheckDefined.bind(this)
log(checkDefined('a'))
log(checkDefined('b'))
log(checkDefined('c'))
}
<pre></pre>
You should also pass on which object context you need to check if the variable is defined or not. If it's global pass the window object
function checkDefined(name, ref) {
if(!ref) {
ref = window;
}
return !!ref[name]
}
checkDefined("a"); //false if already not defined
var obj = { a: 1, b:2};
checkDefined("a",obj);//true
I am trying to work out how to test if a variable is an instance of a specific bound function. Consider the following example:
var func = function( arg ) {
// code here
}
myFunc = func.bind( null, 'val' );
if( myFunc == func ) {
console.log( true );
} else {
console.log( false );
}
Unfortunately this results in false. Is there some sort of way of testing the variable to find out what function it is bound to?
No, there is not a way to do this. .bind() returns a new function that internally calls the original one. There is no interface on that new function to retrieve the original one.
Per the ECMAScript specification 15.3.4.5, the returned "bound" function will have internal properties for [[TargetFunction]], [[BoundThis]] and [[BoundArgs]], but those properties are not public.
If you tell us what higher level problem you're trying to solve, we might be able to come up with a different type of solution.
If you yourself control the .bind() operation, you could put the original function on the bound function as a property and you could test that property:
var func = function( arg ) {
// code here
}
myFunc = func.bind( null, 'val' );
myFunc.origFn = func;
if( myFunc === func || myFunc.origFn === func) {
console.log( true );
} else {
console.log( false );
}
Demo: http://jsfiddle.net/jfriend00/e2gq6n8y/
You could even make your own .bind() replacement that did this automatically.
function bind2(fn) {
// make copy of args and remove the fn argument
var args = Array.prototype.slice.call(arguments, 1);
var b = fn.bind.apply(fn, args);
b.origFn = fn;
return b;
}
You can't do this directly because functions, just like Objects, have their equality tested by their reference which no longer matches, §11.9.3, point 1. f. or §11.9.6, point 7.
However, you could create some custom properties to test for, e.g.
function myBind(fn) { // takes 2+ args, the fn to bind, the new this, any other args
var bind = Function.prototype.bind,
bound = bind.call.apply(bind, arguments);
bound.unbound = fn;
return bound;
}
and then examle usage
function foo(bar) {
console.log(this, bar);
}
// binding
var fizz = myBind(foo, {buzz:0}, 'baz');
fizz(); // logs {buzz: 0} "baz"
// testing
fizz.unbound === foo; // true
If you want to test in both directions, then you will need to OR them together, and perhaps even consider looping over these properties if you will be binding already bound functions
fizz.unbound === foo || fizz === foo.unbound; // true
Please also consider that the whole chain of unbound versions of the function will not be released from memory as long as a bound version exists, whereas some browsers would have been able to free this memory, depending on their implementation of bind
Bind prepend "bound " before the source function's name.
If you can give a explicite name to the source function then you can do :
var func = function func( arg ) {
// code here
}
var myFunc = func.bind( null, 'val' );
if( myFunc.name.match(/^(bound\ )*(.*)$/i)[2] === func.name ){
console.log(true);
}
Thanks for your input #jfriend00 and #PaulS. I am using a function that automatically adds an unbound property to the bound function. Here is a refined version of what I wrote. Let me know what you think.
// My function
var myFunc = function() {
return 'This is my function';
};
// Function I'm wrapping my function in
var wrapper = function( fn ) {
var result;
if( fn ) {
result = fn.apply( null, arguments );
}
// Any additional logic I want to run after my function
console.log( 'Ran wrapper logic' );
return result;
};
// Modified binder method
var binder = function( fn, ths, args ) {
args = [].concat( ths, args );
var bound = fn.bind.apply( fn, args );
bound.unbound = fn;
return bound;
};
// Bind a wrapped version of my function
myFunc = binder( wrapper, null, myFunc );
// I can test if my function has ben wrapped
console.log( myFunc.unbound == wrapper );
// And I can run a wrapped version of my function
console.log( myFunc() );
If I have the function:
function(foo, bar, baz);
And I want to allow for both named arguments and normal function calls, what is the best way of handling this? In php you can extract the variables into the local namespace but as far as I know the only way to handle this in javascript is by handling both scenarios separately. I've given a code example below:
function(foo, bar, baz)
{
if(typeof(foo) == 'object') // Named args
{
alert(foo.foo);
alert(foo.bar);
alert(foo.baz);
}
else
{
alert(foo);
alert(bar);
alert(baz);
}
}
myFunc('a', 'b', 'c');
myFunc({ foo: 'a', bar: 'b', baz: 'c' });
Any javascript gurus out there who can teach me the ways of javascriptFu?
Since you cannot access the local scope dynamically (without evil eval), you should consider the following approach:
var myFunc = function (foo, bar, baz) {
if (typeof(foo) === 'object') {
bar = foo.bar;
baz = foo.baz;
foo = foo.foo; // note: foo gets assigned after all other variables
}
alert(foo);
alert(bar);
alert(baz);
};
You simply translate the named args to regular variables manually. After that, your code will run for both cases without changes.
Do it with elegance:
var myFunc = (function (foo, bar, baz) {
// does whatever it is supposed to do
}).
withNamedArguments({foo:"default for foo", bar:"bar", baz:23 });
myFunc({foo:1}); // calls function(1, "bar", 23)
myFunc({}); // calls function("default for foo", "bar", 23);
myFunc({corrupt:1}); // calls function({corrupt:1})
myFunc([2,4], 1); //calls function([2,4], 1)
Even this one works
Array.prototype.slice =
Array.prototype.slice.withNamedArguments({start:0, length:undefined});
[1,2,3].slice({length:2}) //returns [1,2]
[1,2,3].slice(1,2) //returns [2,3]
... or here, parseInt()
parseInt = parseInt.withNamedArguments({str:undefined, base:10});
parseInt({str:"010"}); //returns 10
Just enhance the Function object:
Function.prototype.withNamedArguments = function( argumentList ) {
var actualFunction = this;
var idx=[];
var ids=[];
var argCount=0;
// construct index and ids lookup table
for ( var identifier in argumentList ){
idx[identifier] = argCount;
ids[argCount] = identifier;
argCount++;
}
return function( onlyArg ) {
var actualParams=[];
var namedArguments=false;
// determine call mode
if ( arguments.length == 1 && onlyArg instanceof Object ) {
namedArguments = true;
// assume named arguments at the moment
onlyArg = arguments[0];
for ( name in onlyArg )
if (name in argumentList ) {
actualParams[idx[name]] = onlyArg[name];
} else {
namedArguments = false;
break;
}
}
if ( namedArguments ) {
// fill in default values
for ( var i = 0; i < argCount; i++ ) {
if ( actualParams[i] === undefined )
actualParams[i] = argumentList[ids[i]];
}
} else
actualParams = arguments;
return actualFunction.apply( this, actualParams );
};
};
This is always awkward and not very rigourous but it's far safer to check the arguments for the absence of data than for a particular positive expectation, especially typeof on object.
Some variation on the below, the strategy here being to translate a DTO style input into a named argument style input (the opposite is also reasonable but I find less obvious). The advantage of this strategy is once you've passed this translation block, the rest of the code doesn't care how you got there.
// translate to named args - messy up front, cleaner to work with
function(foo, bar, baz)
{
// Opt 1: default to named arg, else try foo DTO
bar = (typeof(bar) != 'undefined' ? bar : foo.bar);
// Opt 2: default to named arg, else check if property of foo, else hard default (to null)
baz = (typeof(baz) != 'undefined' ? baz : typeof(foo.baz) != 'undefined' ? foo.baz : null);
// the first argument is always a problem to identify in itself
foo = (foo != null ? typeof(foo.foo) != 'undefined' ? foo.foo : foo : null);
}
// translate to object - cleaner up front, messier to work with
function(foo, bar, baz)
{
var input = (typeof(foo.foo) != 'undefined' ? foo : { 'foo' : foo, 'bar' : bar, 'baz' : baz });
}
The first arg (foo here) is always a problem because you expect it to be in one of two complex states (where the other args are always a single complex state or undefined) and you cannot process it until you've dealt with all the other args because obviously once you've changed it it's unreliable to use it for initialising anything else.