Say I have some object
> var a = {'a': 1, 'b': 2}
undefined
> a.c
undefined
I would like it if this "undefined" attribute c were to instead raise some sort of custom error.
Is there some way to over-ride my object's default behavior, or perhaps invoke it in some way as to provide a callback in case the lookup returns undefined?
I found this question from a couple of years ago that appears related.
I ask because I feel generic TypeError: cannot call method 'foo' of undefined errors might be better replaced with more meaningful feedback.
You'll be testing for an error one way or another. Overriding it doesn't make a lot of sense, especially since you'll just make your code base more complicated and undefined actually makes sense here. The property c is literally undefined and so this is quite readable (especially to new people working with your code):
if (a.c) { //or could be a.c !== undefined,
//but if(a.c) will catch other falsey values
a.c.something();
}
You can use try, throw and catch() for this is exact situation.
Here's an example:
var a = {'a': 1,'b': 2};
try {
if (a.c === undefined) throw "Sorry you need to create the property 'a.c first";
} catch (err) {
console.log(err);
}
In JS Fiddle
Whatever you put as the string after throw becomes the argument passed to catch(err). So, instead of it saying undefined it says Sorry you need to create the property 'a.c first
If you want to get a more meaningful feedback, you can use Firefox.
At least on its version 26, I get
TypeError: a.c is undefined
when doing
var a = {};
a.c.foo(); // TypeError: a.c is undefined
There's a js library called underscore.js with methods like _.isUndefined(), _.isNull(), _.isEmpty() or _.isNan() that may be useful for you in some case.
But the way javascript capture exceptions is like Deryck said. Anyway I'd prefer have more control throw if validations with the underscore methods when I need it.
Related
So I've been looking for an answer given to me in a nodeJS test.
Why use _.get(err, ['data', 'error', 'code']) if you could simply do err.data.error.code?
And can you think of a better name for err here?
after 3 days of searching i can't figure out an answer ,I may need some help
Code:
if (_.includes(errorCodesOnWhichToRemoveSynchronization,
_.get(err, ['data', 'error', 'code']))) {
// ...
}
Update
A preferred way to do this without any external library is to leverage optional chaining.
err?.data?.error?.code
Lodash's _.get is failsafe. If any of the intermediate property doesn't exist, it simply returns undefined, instead of throwing an error.
See the demo below:
var obj = {
data: {
}
};
try {
console.log(obj.data.error.code);
} catch(e) {
console.log('regular method throws error');
}
console.log('lodash returns', _.get(obj, ['data', 'error', 'code']));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
By the way, in your case, ['data', 'error', 'code'] can simply be data.error.code.
Imagine err.data is undefined or an empty object. In that case, you would get an exception that js cannot read error from undefined. Using underscore/lodash's get function is a "safer" way to access it. It does not throw that exception and just returns undefined.
Optional Chaining (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)
err?.data?.error?.code
Lodash has few methods to access properties that are quite handy and _.get is one of them where the main idea is for you to not have to worry if the path is not valid due to a falsy value along the way. Not only that but it has a defaultValue 3rd parameter (different in lodash/fp) where you could set a default value if the path asked for is invalid:
_.get(object, 'a.b.c', 'foo'); // if a.b.c is falsy you would get 'foo'
_.has is another one which would return a boolean if the requested path exists or not.
_.result is super handy when it comes to getting a value from a path which goes trough functions. Think about knockout and observables for example where to get from a to b you would usually need to do a().b().c().myValue ... so with _.result you would do:
_.result(obj, 'a.b.c.myValue')
In order to prevent using an object's value that doesn't exist (which would throw an error), I usually do something like this:
if(apple.details){
// do something with apple.details
}
and it normally works fine. But if it's about a "object's object's value", like apple.details.price, that doesn't work, because if not even .details exists, the if() would throw an error.
What can I do or is there generally a better way to do this?
You can do chain:
if (apple && apple.details && apple.details.price) { ... }
But it's not convenient if the chain is long. Instead you can use lodash.get method
With lodash:
if (get(apple, 'details.price')) { ... }
Since 2020:
The best way to solve this is using the Optional Chaining Operator
if(apple?.details) // Undefined if apple does not exist
Suggestion of lodash is no longer required when using runtime compatible with ES2020 i.e. Most browsers today & node>14.5
You may try solution of #Sphinx
I would also suggest _.get(apple, 'details.price') of lodash, but surely it is not worth to include whole library for simple project or few tasks.
_.get() function also prevents from throwing error, when even apple variable is not defined (undefined)
You would have to check each parent object prior to checking the nested child object, i.e., if (a && a.b && a.b.c) {}
If you're using LoDash, you can use the _.get function with an optional default:
let obj = {'a': {'b': {'c': 42} } };
let result = _.get(obj, 'a.b.c'); // 42
let result2 = _.get(obj, 'a.b.d'); // undefined
let result3 = _.get(obj, 'a.c.d', null); // null
If you're not using LoDash, you can implement a simplified version of _.get as shown in this answer.
Is the undefined message in the pop up or console log (e.g. when calling a variable that doesn't exist) an ERROR message or just a NOTICE message?
In PHP there is a difference, so, looking for your explanation on this subject.
Neither, it is a value (or a stringification of a value in the case of an alert)
Whether or not you can ignore the fact that a variable/property/whatever is undefined depends on the needs of the program you are writing. If a message displays "undefined" when it should display "sweet cuppin' cakes", then that would be a logic error; conversely, if a message displays undefined when it is merely intended to reflect an internal state that can legitimately be undefined, it would not be an error.
It sounds to me like an incomplete error message; like when a developer prints "This should never appear!11" Undefined is nothing more than a value, so seeing it on its own does not assign any meaning or importance to the message.
'undefined' means exactly what it says - you have referenced a variable name that is not defined.
Some languages, like Python, are stricter about this kind of thing, and will throw an error if you try to do this.
Javascript assumes you know what you are doing, and so doesn't complain.
Undefined is, what its name says, a sign for something beeing not defined, like
var a=new Array(10);
It is an array: Array.isArray(a)is true, a.length is 10; but all it contains are undefined values: e.g. a[5] is undefined. So it is no error.
ERROR message or just a NOTICE message?
Neither nor.
undefined is a special data type. For example, a common case is a missing parameter in a function call:
var foobar = function(val)
{
alert(typeof val); // alerts 'undefined'
alert(foobar.length); // throws an error
}
foobar();
The author of this example function should have checked for the type of val before trying to access the length property.
In the book Javascript the good parts, on the opening page of Ch3 on objects, it states:
An object is a container of properties, where a property has a name and a value. A property name can be any string, including the empty string. A property value can be any Javascript value except for undefined.
Note: undefined is highlighted in the book to denote that is is a literal.
In practice, however, I am able to do it.
var a = { "name": undefined };
What is wrong with my understanding ?
I believe the answer is that he's wrong.
As you observe, you can set var a = { "name": undefined };.
a.name === undefined
a.name === a.someFakeProperty
Here's where they're different, though:
'someFakeProperty' in a === false
'name' in a === true
Or, to do it a different way,
a.hasOwnProperty('someFakeProperty') === false
a.hasOwnProperty('name') === true
Using the somewhat infamous for..in loop,
for (var i in a) {
alert(i);
}
... will give you name.
So, by value you may not be able to distinguish undefined and undefined, but they are quite different internally.
Addition: he's wrong about the property names, too - a[window] = 43; a[window] == 43; is just fine. Sure, you can't then do a.window, but a.___ is just syntactic sugar for a['___']. As noted in the comments, property names are cast to string so I was wrong about this bit.
I don't like the terminology that Crockford uses, he seem to mix the concept of undefined and undeclared.
The statement:
A property value can be any Javascript value except for undefined.
Is completely wrong IMO, because undefined is a primitive value of the language.
See also:
Difference between undefined and not being defined in Javascript
I think what he's trying to say is that a property's value cannot be undefined because undefined is exactly how JavaScript denotes properties that don't exist. In other words, if you have the following object
var a = { "name": undefined };
Then a.name is undefined, but so is a.someFakeProperty. However, as Ben Lee points out in his comment, name will still show up when you iterate the properties of a using a for loop, while someFakeProperty will not. Therefore, it seems that Crockford was a bit imprecise in conveying the idea in question here.
Perhaps this:
var a = {"name": x}; //x is undefined, so it will cause an error.
Just my understanding.
I am wondering if this is possible in JavaScript, I want to have an Object which could contain dynamic properties.
Give an example:
function MyObject()
{
}
var myobj = new MyObject();
myobj.property1 = "something";
alert(myobj.property1); // something
alert(myobj.property2); // this should never report error, instead the property should be evaluated to null, as it has never been set.
Is there any way to intercept property calls in JavaScript so I can proactively set a no-value property as null?
Thanks.
This is about as close as you can get to achieving your goal.
Code:
var obj = {};
alert("prop: " + obj.prop);
obj.prop = "something";
alert("prop: " + obj.prop);
delete obj.prop;
alert("prop: " + obj.prop);
Behavior:
Alert: "prop: undefined"
Alert: "prop: something"
Alert: "prop: undefined"
'Proxy' can do that
var myobj = new Object();
var handler = {
get:function (obj, name, proxyed){
if(obj[name] !== undefined) // if obj[name] exist
return obj[name]; // then return obj[name]
return null; // if obj[name] is not exist then return null;
}
};
var obj = new Proxy(myobj, handler);
obj.property1 = "something";
alert(myobj.property1); // something
alert(myobj.property2); // undefined
alert(obj.property1); // something
alert(obj.property2); // null
Yes, but only in version 2.0 and higher. The exact syntax is still TBD but it's looking like it'll be get * () {...} for object literals at least.
Nope. JavaScript is not Smalltalk.
There is no way to intercept direct property accesses in JavaScript. When a property is retrieved that hasn't been set than the result will be undefined. Although null and undefined are usually considered to be the same thing they are in fact different entities.
In JavaScript undefined means no value and null means a value of null. In some cases you can mix undefined and null. For example, when using the == operator they are equivalent ((null == undefined) === true). Using the non-coercing operator, ===, they are different ((null === undefined) === false).
You can use this to your advantage. While most people will claim that you should use the non-coercing equality operator (===) it's mostly safe to put null and undefined in the same bucket, in less of course you actually care about the difference between the two. Where it gets tricky is that undefined is a property of the global object and can therefore be assigned a new value.
If someone were to say undefined = 'donkey' then null == undefined would start to return false. In practice this is almost never a problem since most people aren't foolish enough to reassign the value of undefined.
So, in a roundabout sort of way, you don't need to trap property accesses to return null for properties that have not been set so long as you compare the result against null using ==.
No unless you are manipulating an object controlled by an NPAPI plugin in which case you could implement the intended behavior.
In other words, through an NPAPI plugin, you could implement the behavior you are looking for.
Check out javascript prototypes. I think that will give you at least some of what you are looking for. Just google up "javascript prototype".
In your example the second alert will not generate an error. It will just alert undefined. Accessing properties of properties will generate an error:
myobj.property2.property3