Deleting a subfield of a field that doesn't exist - javascript

I just observed the following weird behavior:
Deleting a variable that was not defined
> delete a
true
> delete a[0]
ReferenceError: a is not defined
> delete a.something
ReferenceError: a is not defined
> delete a.something[0]
ReferenceError: a is not defined
Deleting a subfield of a field that doesn't exist
> a = {}
{}
> delete a.foo
true
> delete a.bar.something
TypeError: Cannot convert null to object
> a.bar
undefined
I have two questions:
Why delete a works while a is not defined?
Why does deleting a.bar.something throw the error Cannot convert null to object instead of Cannot read property 'something' of undefined (because a.bar is undefined)?
According to documentation The delete operator removes a property from an object., so the answer for the first question would be that a is supposed to be a property of this object?
When using delete a; in c++ app, this error appears (and it's supposed to do) error: ‘a’ was not declared in this scope.

The answer is split into two. The first doesn't describe much but answer the question, while the latter goes into the nitty gritty details of the specification.
tl;dr
The first line works because in non-strict mode, trying to delete a variable just works.
The rest of the examples in the first section don't work because a isn't defined
delete a.foo works because there's no reason it shouldn't
delete a.bar.something throws because it's first trying to turn a.bar into an object before trying to access a.bar.something.
And now for something completely different
First, let's make clear that the two sections of code are conceptually different since the first talks about a variable which was not declared.
We'll be looking at how delete is specified quite a bit.
Let's start with the easier to understand parts:
> delete a[0]
ReferenceError: a is not defined
> delete a.something
ReferenceError: a is not defined
> delete a.something[0]
ReferenceError: a is not defined
All these lines are trying to do something with a, a variable which was not declared. Therefore, you get a ReferenceError. So far so good.
> delete a
true
This goes into the 3rd clause of the delete statement: a is an "unresolved reference", which is a fancy way of saying "it wasn't declared". Spec says to simply return true in that case.
> a = {}
{}
> delete a.foo
true
This one's intuitive as you expect (probably), but let's dive into it anyway. delete obj.property goes into the 4th clause:
Return the result of calling the [[Delete]] internal method on ToObject(GetBase(ref)) providing GetReferencedName(ref) and IsStrictReference(ref) as the arguments.
Welp that's a whole lot of uninteresting stuff. Let's just ignore everything after the [[Delete]] part, and just look at how [[Delete]] is specified. If I were to write it in js, it's be like this:
function Delete (obj, prop) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
if (!desc) {
return true;
}
if (desc.configurable) {
desc.magicallyRemove(prop);
return true;
}
throw new TypeError('trying to delete a non-configurable property, eh!?');
}
In the example, a does not have a property named foo, so nothing special happens.
Now it gets interesting:
> delete a.bar.something
TypeError: Cannot convert null to object
This happens because of some of the uninteresting things we ignored earlier:
Return the result of calling the [[Delete]] internal method on ToObject(GetBase(ref)) [...]
I highlighted the portion relevant to this specific snippet. Before we try to delete anything, spec tells us to call ToObject(GetBase(ref)), where ref = a.bar.something. Let's do that, then!
GetBase(a.bar.something) === a.bar
ToObject(a.bar) === ToObject(undefined) which throws a TypeError
Which explains the final behaviour.
Final note: The error message you've shown is misleading, since it says it tried to convert null into an object, which it didn't, as it tried to convert undefined into one. Latest chrome and firefox throw a more accurate one, but I think v8 only recently fixed the error message, so perhaps upgrading to node v11 will show a correct version.

I'm sharing experiments and readings, hope this will help!
1. Why delete a works while a is not defined?
If you try to read a property that isn’t there, JavaScript returns
“undefined”. This is convenient, but can mask errors if you’re not
careful, so watch out for typos!
Source: http://www.w3.org/wiki/Objects_in_JavaScript
"Delete" will remove both the value and the property, so as long as JavaScript returns a value for a, delete will work the same way that this example:
var a;
delete a;
Besides, as you said a is a property of this object. You can see this by testing this code:
> var a = {}
undefined
> a
{}
> this.a
{}
2. Why does deleting a.bar.something throw the error Cannot convert null to object instead of Cannot read property 'something' of undefined?
Please look at these examples:
NodeJS:
> var a = {}
undefined
> typeof a.b
'undefined'
> typeof a.b.c
TypeError: Cannot read property 'c' of undefined
at repl:1:12
at ......
> delete a.b.c
TypeError: Cannot convert null to object
at repl:1:10
at ......
Chrome console:
> var a ={}
undefined
> typeof a.b
"undefined"
> typeof a.b.c
Uncaught TypeError: Cannot read property 'c' of undefined VM335:2
> delete a.b.c
Uncaught TypeError: Cannot convert undefined or null to object
As you can see, both will manage a.b as an undefined value when testing typeof. But when deleting, chrome says that it may be undefined or null, while NodeJS consider this is a null value.
Would it be possible that NodeJS error is wrong formated?

Related

How to solve cannot read property "length"? [reactjs]

I am trying to get the length of an object but am getting this error message:
Uncaught TypeError: Cannot read property 'length' of undefined
I am trying to get the length and getting a popup when the length is zero.
I tried using this.props.storyboardTargets.length === 0
case 1: data not available so (!this.props.storyboardTargets)--> undefined
case 2: data was there and later deletd or cleared so need to check the length
Here is my code below:
handleShowPopupTarget = () => {
if (this.props.storyboardTargets && !this.props.storyboardTargets.length) {
console.log(this.props.storyboardTargets);
toastWarning(WARNING_MSG_NO_TARGET);
}
};
The way you have it written now does not handle the issue that this.props.storyboardTargets may be undefined. You need to update it like so:
handleShowPopupTarget = () => {
if (!this.props.storyboardTargets || !this.props.storyboardTargets.length) {
console.log(this.props.storyboardTargets);
toastWarning(WARNING_MSG_NO_TARGET);
}
};
This means if storyboardTargets is undefined, or its length is 0, toastWarning will fire.
As an alternative, you could define a default prop for your component of an empty array for storyboardTargets. That way it would never be undefined.
The error message means that storyboardTargets in undefined. Try seeing if storyboardTargets is being passed in to the component that contains your handleShowPopupTarget method.
use lodash's get, it simplifies a lot those kind of buggy checks:
_.get(this.props, 'storyboardTargets.length', 'default'); // you could use 0 instead of 'default' in your case
Your original code was
if (!this.props.storyboardTargets.length) {
And it fails because this.props.storyboardTargets is undefined and well you can not read properties of something that is undefined so it throws an error.
So after that you listened to advice and changed your code to be
if (this.props.storyboardTargets && !this.props.storyboardTargets.length)
So now this stops the undefined error from happening on this line because the truthy check on this.props.storyboardTargets prevents the evaluation of the second half of the code. So that means the code will not go into the if. but you WANT it to go into the if statement if it is not defined.
So what you need to do is change it to be an OR check so if it is NOT defined OR it does not have a length
if (!this.props.storyboardTargets || !this.props.storyboardTargets.length)
Now it goes into the if statement id it is undefined and will not throw the error.
The other solution is to see that it is undefined and set it to a default value
this.props.storyboardTargets = this.props.storyboardTargets || []
if (!this.props.storyboardTargets.length)
Now if the array is undefined, it sets it to an empty array and the if check will work correctly. Changing the data might not be the best solution if other things rely on undefined.

Error when Javascript 'or' || operator used in this case

So i have this situation basically
var a = someUndefinedVariable.name || "";
In this case why 'a' is not equal to an empty string???
This expression throws an error so I think execution just stops and Interpreter does not reaching to the part with the OR statement. Is it right?
However, without property name everything works fine.
Thanks a lot for attention.
Because someUndefinedVariable, being undefined, doesn't have the property name, so it crashes. Replace it with:
var a = (someUndefinedVariable && someUndefinedVariable.name) || "";
This expression throws an error so I think execution just stops and Interpreter does not reaching to the part with the OR statement. Is it right?
Yes. Exceptions halt execution (unless you catch them).
However, without property name everything works fine.
If a variable is not declared and you try to read from it, then you will get an exception: Uncaught ReferenceError: foo is not defined.
If a variable is declared, and has the undefined value, then you can access it freely. It is just undefined.
Trying to access a property of an undefined value throws an exception:
Uncaught TypeError: Cannot read property 'bar' of undefined
You are dealing with cases 2 and 3.
You might check someUndefinedVariable first, to prevent an access to a property of a undefined variable
var a = someUndefinedVariable && someUndefinedVariable.name || "";
you should use
var a = (someUndefinedVariable && someUndefinedVariable.name) || "";
since you are referring to a property of an undefined variable, it crashes, instead check if the variable exists before hand

Why does reading a property sometimes throw an error in javascript?

Suppose I have some variables:
var s = 's', i = 0, o = {}, a = [], n = null, nan = NaN, u;
How can I make any sense of when reading x.p will return undefined, and when it will throw a TypeError?
s.p; // undefined
i.p; // undefined
o.p; // undefined
a.p; // undefined
n.p; // TypeError!
nan.p; // undefined
u.p; // TypeError!
P.S. Are null and undefined the only weird values in this way? Are there others?
Edit
I'm aware that by declaring variables as I have, several of my values have been automatically wrapped by objects (e.g. Number), despite being primitives. Therefore I can treat them like "proper" objects (e.g. {}, []) and attempt to read their properties. But I can't find much explaining what is and isn't wrapped this way.
Yes, null and undefined are the only values that throw an exception when being used in a property access. The dot and bracket property accessors do invoke the internal CheckObjectCoercible function, which is defined as following:
The abstract operation CheckObjectCoercible throws an error if its
argument is a value that cannot be converted to an Object using
ToObject. It is defined by Table 15:
Table 15 — CheckObjectCoercible Results
Argument Type | Result
--------------+------------------
Undefined | Throw a TypeError exception.
Null | Throw a TypeError exception.
Boolean | Return
Number | Return
String | Return
Object | Return
null and undefined being the values that represent Nothing cannot be converted to objects ("wrapped" as you say). Notice that you could of course have an object with an existing property that throws on access, like
var o = {get p() { throw new TypeError("you may not access this"); }};
o.p // TypeError
When you're reading the property of something that's undefined. You're basing saying:
What is undefined of undefined? or in the case of null what is undefined of null ? Neither undefined nor null are objects, therefore you can't set or get properties on/from them. With that in mind, an error will be thrown.
When the object is null/undefined, it'll throw an error because it'll try to access a property of an object that does not exist in first place.
On the other cases, it'll try to access a property of an existing object and will return undefined because the property is not found.
Please note that almost everything in js is an object, as you can see here.
let's firstly start with
why undefined on:
var s='s';
You assigned s to string which is primitive type. Javascript is tricky here in one sense. Though primitive type, when you try to access the property by doing:
s.p
It firstly does this internally:
String(s)
and creates the object and then tries to see if it has that property which is, of course not defined and thus you get undefined. Almost similar things happen with numerical assignment and NAN.
For n=null:
If you do:
var n=null;
typeof n;//"object"
n.p// throws typeerror
In fact,null can be thought of special kind of object without any properties or method to represent absence of value and thus, you get typeerror when you try to access any properties of null.
a.p
o.p
Easily, you can see that you are trying to access the property of an object than is not defined or not built-in and thus it should say, undefined. You should be surprised to see other than that :D.
To add to the other answers here, there is an easy way to check if a property access will throw an exception. Simply loosely compare the value you're unsure of to null, like so:
if(x != null) { // note the LOOSE equality, rather than !==
// do something with x.prop
}
The reason this works is that only null and undefined * throw errors on property access, and they are only loosely equal to each other. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_when_to_use_them.
* There is also a case where some JS objects can apparently "emulate" being undefined, in which case they also are loosely equal to null and undefined.

What should search method return if nothing found?

I have this method
var link = this.find_first_link(selectedElem);
which should return an object. I'm not sure what should it return if no element is found - null, undefined or false? I've rejected 'false' option since I don't think it suits here so I'm choosing betwen null or undefined. I've read that 'undefined' should be used where some kind of exception or error occurs, so currently this method returns null. Is that OK?
Look at what is done in methods you have in your browser.
getElementById returns null when there is no element with the id provided.
That's what null has been designed for : to represent the absence of an object (typeof null is "object"). Use it when the expected returned type is "object" but you have no object to return. It's better than undefined here because you would have undefined before you even decided what to put in the variable or before you even call the function.
From the description of null in the MDN :
In APIs, null is often retrieved in place where an object can be
expected but no object is relevant.
Yes, use null.
Yes,
var link = this.find_first_link(selectedElem);
It will return NULL.

When JavaScript returns null & undefined?

I have been using JavaScript for couple of years and never cared about the difference between null & undefined earlier, I always use undefined to validate the object existence.
But recently I came through this article. Here they said
JavaScript distinguishes between null, which is an object of type 'object' that indicates a deliberate non-value, and undefined, which is an object of type 'undefined' that indicates an uninitialized value — that is, a value hasn't even been assigned yet. We'll talk about variables later, but in JavaScript it is possible to declare a variable without assigning a value to it. If you do this, the variable's type is undefined.
I am completely confused now, what exactly is non-value here. How this non-value differs from undefined. And what are the circumstances javascript returns null.
I have tried the below sample
var sam;
alert(sam); // returns undefined
And
try {
//var sam;
alert(sam);
} catch(ex) { } // exception says: sam is undefined
And I am not sure about when js returning nulls. Can someone clarify me.
alert(sam); // returns undefined
Nope, that's an exception.
You get undefined when you access an unset property; you get an error when you use an unset name directly.
Global variables are interesting because they can be accessed either using a simple variable name, or by using properties of the window global object:
alert(window.sam); // undefined
alert(window['sam']); // undefined
alert('sam' in window); // false
alert(sam); // ERROR
If sam is declared but not initialised, accessing window.sam still gets you undefined, but for a different reason: there is an entry in the window object for sam, but it points to the same undefined object as you get when you access a non-existant property.
var sam;
alert(window.sam); // undefined
alert(window['sam']); // undefined
alert('sam' in window); // ** true
alert(sam); // ** undefined
This is of course a confusing bloody mess; undefined is one of the worst mistakes in the design of the JavaScript language.
null on the other hand is fine and works pretty much the same as null/nil/void/None values in other languages. It doesn't come into any of the above.
<script type="text/javascript">
// variable with an unasigned value
var a;
if (a == undefined) {
alert('a is undefined');
}
if (a == null) {
alert('a is undefined');
}
// this will produce an error
if (b == undefined) {
alert('b is undefined');
}
// this is the right way to handle not defined variables
if (typeof(c) == 'undefined') {
alert('c is blabla');
}
</script>
For a variable to receive a null value it must be assigned. null is used to indicate an unknown or don't care value. undefined on the other hand is designed to indicate that the propery being accessed has never ben assigned a value. This differs from null.
With null one is deliberately saying "I don't know what value this should have yet" or "I don't care what value this is right now". OTH in undefined is really saying "Are you sure you should be using this value it hasn't been assigned".
The way I distinguish them is undefined being "I have not defined this value," and null being "I have defined this value, but I do not know or cannot figure out what the value should be."

Categories