Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to pass undeclared variables as parameters in Javascript?

Let's say I have a variable myvar, and I don't have a variable myvar2. I can run the following without a problem:

typeof myvar
// ⇒ 'string'
typeof myvar2
// ⇒ 'undefined'

typeof and delete are the only functions I know of which don't throw errors when given an undefined parameter like this. I looked at the language spec for typeof and to my uninitiated eyes it seems to use internal functions like IsUnresolvableReference.

Edit: I'd been working in a language that checks type with a synonymous function, and hadn't noticed typeof is actually an operator in JavaScript. I've removed parentheses from the code here but left the above as written.

When I create a function:

function myFunc(input_variable) {
  return("hello");
}

... as expected this throws a ReferenceError when passed myvar2 as a parameter, unless I run var myvar2;.

If I wrap the return in a try/catch statement to handle the myvar2 not defined case, I still get the same error, as the variable seems to be checked for a resolvable reference upon entry into the function (upon runtime?) :

function myFunc(input_var) {
  try {
    return "hello";
  } catch(error) {
    if (error.name === 'ReferenceError'){
      return "world";
    }
  }
}

I was wondering how I can make a function that accepts unresolved references. My general guess is that, if it's a standard behaviour of functions, then perhaps I could modify some prototype for this construction specifically...? I'm aware prototypes are for objects, I'm wondering if this level of control over function is possible somehow?

By way of context, I always find myself writing function(input_var) :

if (typeof input_var == 'undefined' || my_settings.input_var_is_optional === true)
  var input_var = 'Sometimes variables are optional. This is my default value.';
  return dealWith(input_var);
} else if (typeof input_var == 'string') {
    return dealWith(input_var);
} else {
  // Already checked that input_var isn't optional, so we have a problem
  return false; // or throw a TypeError or something like that
}

but the verbosity of all that plain puts me off writing type checking into my code, making it less robust to use functions more freely, or to pass onto other developers.

I'd like to write a type handling function, e.g.

For a function myFunc(input_var), if the variable passed in as parameter input_var has been defined, check if it's a string, else set it as "default_value". If it wasn't defined, also set it as "default_value", else it's a valid string, so just use input_var as is.

...but it's sabotaged by the fact that I can't actually pass anything in that's undefined, effectively stopping me from isolating this complexity in a separate function to which I could just pass 2 parameters: input_var (the real deal, not just its name), and expected_type.

function typeTest(input_var, expected_type) {
  var is_optional_value = (typeof expected_type != 'undefined'
                                                 && expected_type === true);
  var optional_str = is_optional_value ? "|(undefined)" : ''
  var type_test_regex = RegExp('^(?!' + expected_type + optional_str + '$)');
  var is_expected_type = type_test_regex.test(typeof(input_var));
}

For example, to check that an optional variable passed into a function was both defined, and was defined as a string,

var myvar = 'abc'
//  myvar2 is never defined

// Mandatory type (expecting a string):
typeTest(myvar, 'string'); // true
// if (/^(?!string)$)/.test(typeof(myvar))
typeTest(myvar2, 'string'); // throws error

// Mandatory type (expecting a number):
typeTest(myvar, 'number'); // false
typeTest(myvar2, 'number'); // throws error

// Optional type ("expected is true"):
typeTest(myvar, true); // true
// if (/^(?!string|(undefined)$)/.test(typeof(myvar))
typeTest(myvar2, true); // throws error
like image 535
Louis Maddox Avatar asked Mar 17 '15 16:03

Louis Maddox


3 Answers

I was wondering how I can make a function that accepts unresolved references.

You can't. When you access an undeclared variable, the ReferenceError occurs before the function even gets called. There's nothing you can do inside the function to recover from this, because it hasn't even been called.

typeof and delete are the only functions I know of which don't throw errors when given an undefined parameter like this.

typeof and delete are not functions. That's why.

For example, to check that an optional variable passed into a function was both defined, and was defined as a string.

There's nothing stopping you from doing this. There is a difference between:

  • variables with the value undefined
  • parameters that have not been passed a value
  • undeclared variables.

There is no problem in dealing with the first two:

function hasType(val, type) {
  return typeof val === type;
}

function myFunc(param1, param2) {
  console.log('param1: ', hasType(param1, 'string'));
  console.log('param2: ', hasType(param2, 'string'));
}

myFunc('hello');

There is no need to check whether someone is trying to call your functions with undeclared variables. If they are, then the problem is with their code and they need to fix it. If they are taking advantage of optional parameters, that is a different matter, and you can handle for that scenario just fine.

like image 197
JLRishe Avatar answered Oct 17 '22 09:10

JLRishe


as the variable seems to be checked for a resolvable reference upon entry into the function

It is checked before entry.

Given foo(bar), the logic for resolution is "Get foo, then get bar, then call foo with the value of bar as an argument.

If bar isn't declared then you'll get a ReferenceError before the function is called in the first place.

typeof and delete are the only functions I know of which don't throw errors when given an undefined parameter like this.

From the documentation you link to:

The typeof Operator
The delete Operator

They aren't functions.


I was wondering how I can make a function that accepts unresolved references.

You can't.

For example, to check that an optional variable

If you want an argument to be optional then either:

Explicitly pass undefined:

typeTest(undefined, 'string');

Put the optional argument last in the arguments list:

typeTest('string');

Pass an object:

typeTest({ argument_name: 'string' });
like image 3
Quentin Avatar answered Oct 17 '22 09:10

Quentin


You can using a function slide.

function attempt(f){
    console.log(f());
}
attempt( function (){ return  nomansland} );
//later an ajax call declares it:
var nomansland = "ok";
attempt( function (){ return  nomansland} );
like image 1
Radio Avatar answered Oct 17 '22 09:10

Radio