Recently I investigated a situation in which a programmer inadvertently passed undefined into addEventListener, thus:
window.addEventListener('load', undefined);
No error was thrown. It's as if JavaScript is willing to invoke undefined. But what in the world is undefined()? I have tried all sorts of things, e.g.:
console.log(undefined() === null);
console.log(typeof undefined());
but I never get anything back.
Edit added for clarity: My original question was based on a mistake, as I had not set my Developer tools to log errors to the console. The above two commands (but not the call to addEventListener) DO throw errors in a browser, as answers and comments below indicate.
It's as if JavaScript is willing to invoke undefined.
No, addEventListener is specified to ignore null, which JavaScript’s undefined is converted to. undefined is never called.
Further proof that JavaScript is not willing to invoke undefined, in a browser:
> undefined()
Uncaught TypeError: undefined is not a function
at <anonymous>:1:1
You can do something like this to find the type of passed arguments:
var myVar;
Object.prototype.toString.call(myVar);
and it will return "[object Undefined]"
same for other use cases like if myVar is a string as below:
var myVar = 'It is a string';
Object.prototype.toString.call(myVar);
it will retrun "[object String]"
It will return:
Undefined is not a function
console.log(typeof undefined());
If you run it console on a browser it will return undefined not a function. Undefined does not have any value unlike null which is an object.
null means that something exists, but has been told it has no value.
undefined means that thing has not been given a value, usually because it hasn't been declared/initialized.
In Javascript, undefined is a primitive. It's falsey, so it evaluates to False if used in conditional.
Javascript is not a strongly typed language, so there's nothing to check that a callback function is a function until it's called. In fact Javascript doesn't care how many arguments are passed or what their type is, everything's just dumped in when a function is invoked, and it's up to the function how to handle the arguments.
For example in many enumerable methods, they pass back to you (index, value, array). It doesn't matter if your function looks for these values or assigns them a temporary variable, they're still passed. Both a.forEach(function(index){}) and a.forEach(function(){}) actually have access to all 3 of the variables mentioned.
Related
I was very surprised to see the following behavior in Node 14.18.0:
> {}?.fun();
Uncaught TypeError: b?.fun is not a function
> undefined?.fun();
undefined
I understand why the first statement throws a TypeError. {}?.fun is undefined, which is not callable. But undefined?.fun is also undefined, so why can it be called without throwing? What part of the ECMAScript specification defines this behavior? Did the ECMAScript working group provide any reasons why it should work this way?
During optional chaining, if the current value within the chain is null or undefined, the expression short-circuits with a return value of undefined.
This is in the official docs:
The ?. operator is like the . chaining operator, except that instead of causing an error if a reference is nullish (null or undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefined if the given function does not exist.
Since {} is an actual object—without a method called fun()—it blows up, because you called a function that did not exist.
To fix your issue, you will need to call the function with optional chaining:
console.log(({})?.fun?.()); // undefined
the work of? and say that possibly the value is undefined
normally used like this in typescript
console.log(myobj?.value ?? 'does not exist');
in javascript "?" it's useless
"?" doesn't do anything, it just signals that the value can be undefined, so when you put an object, it returns an error because this property doesn't exist in your object, whereas in undefined javascript it just ignores everything
similar question in Java: Java: check for null or allow exception handling
related:How to deep check for "null" or "undefined" with JS?
assuming a.foo() is a well-tested function that returns either
undefined or an object with a function such as {bar:()=>log('baz')},
hence, it would seem logical to write
a.foo().bar()
which obviously won't work.
(the undefined is the result of an empty return; when no information can be delivered)
Should
1. The operation be tried,
try{a.foo().bar();}catch(e){}
2. a new variable be declared
const u = a.foo();
if(u) u.bar();
3. or foo() return {bar:()=>{}} instead of undefined?
so that
a.foo().bar();
can be written normally?
what is the industry standard? what is fastest?
As already commented, this is a personal opinion and I would also stick to it that most people would try to avoid the try-catch story...
But anyway I wanted to add that you can also simply check:
a.foo() && a.foo().bar()
in case a.foo() will return undefined, then the right side wont be executed and thus this expression return undefined.
On the other side, if a.foo() is not undefined than the right side will be executed and this expression will evaluate to the result of a.foo().bar()
I have noticed jQuery and related keynote plugins like jQuery.UI pass undefined as a parameter into anonymous functions used in their module definitions, like so:
(function($, undefined) { ... })(jQuery);
Alternatively, I have noticed other plugins recommended by jQuery and/or others do NOT pass undefined in as a parameter.
This is probably a silly question, but...
Shouldn't it always be available anyway? Why pass it in? Is there some sort of other purpose or trick going on here?
There are two reasons for that:
1) If undefined is a variable in the function scope rather than a global object property, minifiers can reduce it to a single letter thus achieving a better compression rate.
2) Before ES5*, undefined was a property of the global object without write-protection. So it could be overwritten, resulting in strange and unexpected behavior. You could do something like this:
var test = 123;
undefined = 123;
if (test === undefined){
// this will actually be true, since undefined now equals 123
}
By having an function argument undefined (the name actually does not matter) which you don't pass a parameter to, you could make sure you have a variable which really is undefined so you can test "undefinedness" against this variable.
Btw. the safest method to test for undefined is: typeof ( var ) === 'undefined'
(*) With EcmaScript 5, the global properties undefined, NaN and Infinity became readonly. So with its general adoption in all modern browsers - of course with the exception of IE 9 - overwriting those values was not possible anymore.
That is done to make sure that undefined always is undefined. In older versions of the ECMAScript spec (prior to ECMAScript 5), undefined wasn't a reserved word but a regular variable. In older browsers this would be allowed for instance:
undefined = 2; // Assign a different value to undefined
// Now this statement would be true
if (undefined == 2)
So to make sure that undefined is in fact undefined, even if some other "evil" script would have reassigned undefined with another value, you create a parameter that you call undefined, and then when you call the function, you make sure to not pass a value to that parameter - thus you can be sure that the variable undefined will always be undefined within your function.
So in the case of jQuery:
(function($, undefined) { ... })(jQuery);
They pass in jQuery and assign it to the $ variable for convenience, but then they don't pass a second value to the undefined parameter, thus undefined will be undefined.
Modern browsers
In modern browsers, undefined is a non-configurable, non-writable property per the ECMAScript 5 specification.
undefined is not a reserved word in javascript, it is simply a variable. jQuery is ensuring that if some bad developer overwrites the value of undefined in their javascript, then jQuery will ignore it and establish it's own variable, undefined, which is never passed a value (see the self-executing (jQuery) at the end) and is therefore actually undefined.
I have recently learned about the magic of fn.apply() in Javascript, and I am using it to save function calls with all their arguments intact and call them at a later date.
However, in my use case, I do not need the first argument, the context (this), and I'd like to avoid passing the this object into it somehow in order to make it clear in my code that I'm not using .apply() for that.
My first thought was passing in null, but I read the following on MDN:
if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
This seems to imply that passing null or even false is bad practice. What would be an appropriately falsy, empty, or otherwise obviously placeholder value to put into fn.apply()'s first argument?
This seems to imply that passing null or even false is bad practice
No, it's not. Admittedly false is a bit weird as a this value, but the problem that MDN warns about are sloppy-mode functions. Examples:
function sloppy() {
console.log(this);
}
function strict() {
"use strict";
console.log(this);
}
sloppy.call(null); // <Window> (or whatever the global object is)
sloppy.call(false); // Boolean {}
strict.call(null); // null
strict.call(false); // false
So just use strict mode and you'll be fine. And don't be surprised that you can't get primitive this values in sloppy mode functions.
Using null or undefined is recommended if you want to pass no value.
I recently had an issue with some javascript that goes against every bone of my programming background. Javascript does this often to me, so I'm not that surprised.
I have a function as such...
function x(param1, booleanParam, arrayParam){
....
}
I was getting a runtime error saying that arrayParam.length was not defined. On debugging I saw this was true and went to find out why. Turns out I had forgotten a comma in my function call as such...
x(param1, true [arrayJunk]);
The problem I'm having is figuring out why this call was made at all? Why isn't this a compile error, how does Javascript see this and think, "Yeah, that seems like it might work!"
Thanks in advance for any enlightenment you can share!
That's an indexing expression.
It's the same syntax as someArray[someIndex].
It will end up passing undefined as the second parameter too, unless arrayJunk happens to be the name of a property of boolean primitives.
What happens is the following:
JavaScript engine converts true into a Boolean object (not the primitive)
It then tries to access the property name stored in arrayParam from that object
Property doesn't exist, so it returns undefined
If arrayParam was the string "toString", it would return a function object
In this case the expression was being interpreted as an index. Essentially the same as
someArray[42]
So it was being seen as a function call with 2 parameters instead of 3
Many dynamic languages don't check if you pass too many or too few arguments to a function.
While this can sometimes mask errors, it also allows you to roll your own defalut parameter scheme.