In Rails I can do this:
x = user.try(:name)
this method returns nil if user is nil else user.name. Here name is a method defined on the user object.
I know it can be done using if..then..else in Javascript but is there an equivalent compact method to do the same in Javascript?
Googling points to Javascript's try command which is not what I am looking for.
You can use optional chaining
Examples:
// Access Properties
user?.name; // user might be null/undefined
user.name?.firstName // user will be available however name is not guaranteed.
// Access array values
addresses?.[index]; // array addresses might be undefined
// May be function??
user.getGeolocation?.(); // If the function exists execute it.
Slightly unrelated but something around handling of null/undefined is another feature called Nullish coalescing operator ??
// Example:
function foo(input) // some Array as input {
//.. Some stuff
return [input??[]].concat(bar); //if input is empty ignore and concat bar on an empty array and return.
}
//----
const defaultVal = 'someVal';
...
const val = this.someObj.prop1??defaultVal;
Below is the outdated solution prior to Optional chaining became native to Javascript:
You can do this way, as there is no built in way of doing that:
var x = (user || {}).name;
If user is not defined/null you will get undefined
If user is defined you will get the name property (which may be set or undefined).
This won't break the script if user is not defined (null).
But user variable has to be declared some where in the scope, even though its value is not defined. Otherwise you will get the err saying user is not defined.
Similarly if is in global scope then you can explicitly check for this variable as a property of global scope, to avoid the error as mentioned above
ex:
var x = (window.user || {}).name; // or var x = (global.user || {}).name;
For safe execution of functions,
var noop = function(){}; //Just a no operation function
(windowOrSomeObj.exec || noop)(); //Even if there is no property with the name `exec` exists in the object, it will still not fail and you can avoid a check. However this is just a truthy check so you may want to use it only if you are sure the property if exists on the object will be a function.
Optional Chaining Operator
Is a new proposal for ECMAScript.
It is in an early stage but we can start using it with babel.
This is the problem:
const person = {name: 'santiago'}
let zip = person.address.zip // Cannot read property 'zip' of undefined
This is how it works:
const person = {name: 'santiago'}
let zip = person?.address?.zip // undefined
To start using it we need babel alpha 7:
npm install --save-dev babel-cli#7.0.0-alpha.19
npm install --save-dev babel-plugin-transform-optional-chaining#^7.0.0-alpha.13.1
And we need to add the plugin to our .babelrc
{
"plugins": ["transform-optional-chaining"]
}
Adam Bene Medium Post which explains how to use it and another use cases
You can use logical AND (&&) operator. It works differently than in most of the languages because its result is not a boolean. For example:
const x = user && user.name;
The table below shows all possible outcomes of using this operator:
+--------------+-----------------------+
| user | x = user && user.name |
+--------------+-----------------------+
| undefined | undefined |
| null | null |
| {} | undefined |
| {name:''} | '' |
| {name:'Jon'} | 'Jon' |
+--------------+-----------------------+
Isn't that the same as what this gives you in Javascript:
user['name']
user.name
This returns undefined instead of nil but that's equivalent in most cases. I think the reason Rails needs the try method is because you cannot access instance variables unless they are made accessible.
To add to #PSL's approach, I usually do something like:
var x = user || {},
y = x.name || {},
z = y.first_name;
In Rails4, try does this:
Invokes the public method whose name goes as first argument just like public_send does, except that if the receiver does not respond to it the call returns nil rather than raising an exception.
In Rails3, try is like try! in Rails4 and that's the same as try except that it complains if the object doesn't understand the method you're trying to call. The original intent of try was to hide a bunch of nil checks so that you could say:
o.try(:m)
instead of
o.nil?? nil : o.m
The Rails4 version also hides a check if the object understands the method you want to call.
There's no special syntax for this in JavaScript but you can sweep the ugliness into a function.
The Rails4 version of try would look like this function in JavaScript:
function rtry(obj, m) {
if(obj == null)
return null;
if(typeof obj[m] === 'function')
return obj[m].apply(obj, [].slice.call(arguments, 2));
return null;
}
and you'd say things like x = rtry(obj, 'method_name', arg1, arg2, ...) and x would be null if obj didn't understand method_name (including if obj is null or undefined).
Demo: http://jsfiddle.net/ambiguous/BjgjL/
A Rails3 version is simple, that's just a null check:
function rtry(obj, m) {
if(obj == null)
return null;
return obj[m].apply(obj, [].slice.call(arguments, 2));
}
and JavaScript itself will raise an exception of obj doesn't have an m method. This version is equivalent to the "is it a function" version of CoffeeScript's ? existential operator.
Demo: http://jsfiddle.net/ambiguous/FQCS2/
As usual, things might not work out so well if you're dealing with native methods rather than methods that you've written in JavaScript. typeof (6).toString might be 'function' in one JavaScript environment but I don't think it is guaranteed to always be 'function' everywhere. The primary use (i.e. hide null and undefined checks) should work everywhere though.
I don't think so. Why not roll your own? Not exactly equivalent but does the job.
function tryMe(obj) {
return obj === null || obj === undefined ? null : obj;
}
Related
I have the following function that performs a simple type assertion, checking that a variable is not undefined or null.
const isDefinedAndNotNull = <T>(val: T | null | undefined): val is NonNullable<T> =>
(val !== null) && (typeof val !== "undefined");
However, I have an issue when using this function to assert the presence of a nested object using optional chaining. The below code will cause Typescript to not compile:
type MaybeNullThing = {
myProp?: {
coolThing?: string
}
}
const thing: MaybeNullThing = getThing();
if (isDefinedAndNotNull(thing?.myProp?.coolThing)) {
console.log(thing.myProp.coolThing); // error: thing.myProp could be undefined
}
However, Typescript has no problem with the following:
if (thing?.myProp?.coolThing) {
console.log(thing.myProp.coolThing); // defined here
}
My question is essentially how to get the type assertion to assert that both the nested object and the target object are defined, if this is possible. Thanks!
Link to a TS Playground containing the above code
The type assertion only really covers the deepest level; the property you're passing to the assertion.
Your condition only confirms coolThing is defined and not null.
To cover myProp, you'd need to explicitly check that as well:
if (isDefinedAndNotNull(thing?.myProp) && isDefinedAndNotNull(thing?.myProp?.coolThing)) {
console.log(thing.myProp.coolThing);
}
TS is naïve like that, and I honestly don't know of a way around it.
In ES5 whenever I want to get some property I need to first check that it exists like this:
if (typeof floob.flib !== 'undefined') {
// do something
}
even worse is that for nested properties you have to manually check for the existence of every property down the dotted path.
Is there a better way to do this in ES2015?
If it is just a single depth property name - you don't need typeof, you may just compare the value with undefined.
Your solution is prone to false negatives: it may think there is no a property with a given name, while there is one. Example: var o = { foo: undefined };
If you need to check if the path exists in the nested objects - you still need to implement recursion/loop/or use any library that does either for you.
ES2015 did not bring anything new to solve this problem easier.
If you have lodash available, you can use _.get(obj, path, defaultValue) (https://lodash.com/docs#get)
By using typeof,
typeof floob.flib === 'undefined'
equals to,
floob.flib === undefined
I assume you want to check whether floob.flib has a value, and if it does, you want to perform an operation with it.
However, in JS, there's almost simpler way to achieve this.
E.g.
if (floob.flib) {
// 'floob.flib' is NOT 'null', 'empty string', '0', false or 'undefined'
}
This also works well if you want to assign variable with ternary ( ?: ) operators.
var str = floob.flib ? 'exists' : 'does not exist';
Or even using logical OR ( || )
var str = floob.flib || '<= either null, empty, false, 0 or undefined';
Note that unless floob.flib does not produce ReferenceError exception, the code above should work just fine.
I know if I do
angular.element(document.querySelector('<selector-name>')).scope()
I can get the scope. But that gives me everything ($$childTail, $$childHead, etc).
Is there a method that gives me just the $scope elements (variables and functions) that I created on my controller?
One option that, as far as I can tell, provides almost exactly these properties would be to take the difference of the scope that you retrieved (via angular.element(/*...*/).scope()), and that scope's prototype.
Here's a sample function that does that:
function getAssignedScopeProperties(targetScope){
var targetProto = Object.getPrototypeOf(targetScope);
var assignedProperties = {};
for (var prop in targetScope) {
if (targetScope.hasOwnProperty(prop) && typeof targetProto[prop] === "undefined") {
assignedProperties[prop] = targetScope[prop];
}
}
return assignedProperties;
}
And then using the function:
var targetElement = angular.element(document.querySelector('<selector-name>'));
var targetProps = getAssignedScopeProperties(targetElement.scope());
Unfortunately, in Angular 1.3.15 this seems to leave the $$watchersCount property. This does not happen in versions 1.3.14, nor 1.3.16, so it was likely a bug in AngularJS for version 1.3.15.
That said, keeping a guard against $$watchersCount (or a blacklist with it) to defend against versions of Angular with such bugs doesn't feel proper to me. Another option to ensure that this doesn't happen is to include a check for prop.charAt(0) !== "$" in the inner-if, but assuming the objective is to keep all values that are assigned in the controller, removing any that the controller defined starting with a $ would certainly be wrong (of course, the person who built the controller assigning to properties starting with $ is wrong, too, but that's neither here nor there).
Older question with unaccepted answer here.
The short answer is no, angular does not provide a method for getting only user created properties. Additionally it is a bit difficult to copy or even convert a $scope object to JSON.
The slightly longer answer is you can create a custom JSON.stringify function to parse the $scope object.
var cleanScope = function(scope, includeFunctions) {
// custom JSON.stringify function
// borrowed from: https://stackoverflow.com/questions/24806495/how-to-get-plain-object-from-scope-in-angularjs
function scopeStringify(key, value) {
// ignore any key start with '$',
// and also ignore 'this' key to avoid a circular reference issue.
if (typeof key === 'string' && (key.charAt(0) === '$' || key === 'this')) {
return undefined;
}
// by default, JSON.stringify will ignore keys with a function as a value
// pass true as the second param to get back 'function' instead of ignoring
return includeFunctions && typeof value === 'function' ? 'function' : value;
}
return angular.fromJson(JSON.stringify(scope, scopeStringify));
};
// call like so:
console.log('clean $scope: ', cleanScope($scope));
// or pass true as the second param to include functions
console.log('clean $scope: ', cleanScope($scope, true));
Given this function:
var test = function(param1, param2_maybe_not_set) {
var my_object = {};
// code here...
}
What's the best, in your opinion?
my_object.new_key = (param2_maybe_not_set === undefined) ? null : param2_maybe_not_set;
OR
my_object.new_key = (param2_maybe_not_set === void 0) ? null : param2_maybe_not_set;
OR
my_object.new_key = (typeof param2_maybe_not_set === 'undefined') ? null : param2_maybe_not_set;
Alternatively, would this shortened expression be correct?
my_object.new_key = param2_maybe_not_set || null;
All four methods work (in the NodeJS console at least). Also jsPerf doesn't show a big gap between any of these (http://jsperf.com/typeof-performance/8)
Which one should be used, as a good practice?
They are not strictly equivalent, but can often be used interchangeably. Here are the major differences between them:
x === undefined: this performs a strict-equality comparison between the value and undefined, meaning that only a actual value of undefined will be true, whereas similar values like null or 0 will be false.
In the case of a function call, this check does not differentiate between f(a) and f(a, undefined) (in fact, none of the examples will; to differentiate, you'll have to look at arguments).
x === void 0: this uses the void keyword, which evaluates any expression and returns undefined. This was mostly done in the olden days to prevent surprises from people redefining the global undefined variable, but is not so useful nowadays (ECMAScript 5 mandates that undefined be read-only)
typeof x === 'undefined': this uses the typeof keyword, which has a unique ability - namely, that the operand is unevaluated. This means that something like typeof foobarbaz returns 'undefined' even if no such variable foobarbaz exists at all. Contrast this with foobarbaz === undefined, which will throw a ReferenceError if the variable name has never been declared.
x || null: this is the simplest and probably most readable alternative. The || operator is often used to "set defaults" on arguments, and can be chained like x || y || z || null.
In most cases, this is the idiomatic technique used. However, note that || performs implicit conversions, which means that any "falsy" values will trigger the next value (meaning that it can't differentiate between undefined, false, null, 0, '', and NaN). So, if your function expects to receive falsy values as arguments, it may be more prudent to explicitly check for undefined.
The option chosen to be an idiom in Javascript development to force a value for an unspecified argument is actually the last:
my_object.new_key = param2_maybe_not_set || null;
So this one should be preferrable since a lot of Javascript developers will immediately get its purpose.
Best.
[Bounty Edit]
I'm looking for a good explanation when you should set/use null or undefined and where you need to check for it. Basically what are common practices for these two and is really possible to treat them separately in generic maintainable codee?
When can I safely check for === null, safely check for === undefined and when do I need to check for both with == null
When should you use the keyword undefined and when should one use the keyword null
I have various checks in the format of
if (someObj == null) or if (someObj != null) which check for both null and undefined. I would like to change all these to either === undefined or === null but I'm not sure how to guarantee that it will only ever be one of the two but not both.
Where should you use checks for null and where should you use checks for undefined
A concrete example:
var List = []; // ordered list contains data at odd indexes.
var getObject = function(id) {
for (var i = 0; i < List.length; i++) {
if (List[i] == null) continue;
if (id === List[i].getId()) {
return List[i];
}
}
return null;
}
var deleteObject = function(id) {
var index = getIndex(id) // pretty obvouis function
// List[index] = null; // should I set it to null?
delete List[index]; // should I set it to undefined?
}
This is just one example of where I can use both null or undefined and I don't know which is correct.
Are there any cases where you must check for both null and undefined because you have no choice?
Functions implicitly return undefined. Undefined keys in arrays are undefined. Undefined attributes in objects are undefined.
function foo () {
};
var bar = [];
var baz = {};
//foo() === undefined && bar[100] === undefined && baz.something === undefined
document.getElementById returns null if no elements are found.
var el = document.getElementById("foo");
// el === null || el instanceof HTMLElement
You should never have to check for undefined or null (unless you're aggregating data from both a source that may return null, and a source which may return undefined).
I recommend you avoid null; use undefined.
Some DOM methods return null. All properties of an object that have not been set return undefined when you attempt to access them, including properties of an Array. A function with no return statement implicitly returns undefined.
I would suggest making sure you know exactly what values are possible for the variable or property you're testing and testing for these values explicitly and with confidence. For testing null, use foo === null. For testing for undefined, I would recommend using typeof foo == "undefined" in most situations, because undefined (unlike null) is not a reserved word and is instead a simple property of the global object that may be altered, and also for other reasons I wrote about recently here: variable === undefined vs. typeof variable === "undefined"
The difference between null and undefined is that null is itself a value and has to be assigned. It's not the default. A brand new variable with no value assigned to it is undefined.
var x;
// value undefined - NOT null.
x = null;
// value null - NOT undefined.
I think it's interesting to note that, when Windows was first written, it didn't do a lot of checks for invalid/NULL pointers. Afterall, no programmer would be dumb enough to pass NULL where a valid string was needed. And testing for NULL just makes the code larger and slower.
The result was that many UAEs were due to errors in client programs, but all the heat went to Microsoft. Since then, Microsoft has changed Windows to pretty much check every argument for NULL.
I think the lesson is that, unless you are really sure an argument will always be valid, it's probably worth verifying that it is. Of course, Windows is used by a lot of programmers while your function may only be used by you. So that certainly factors in regarding how likely an invalid argument is.
In languages like C and C++, you can use ASSERTs and I use them ALL the time when using these languages. These are statements that verify certain conditions that you never expect to happen. During debugging, you can test that, in fact, they never do. Then when you do a release build these statements are not included in the compiled code. In some ways, this seems like the best of both worlds to me.
If you call a function with no explicit return then it implicitly returns undefined. So if I have a function that needs to say that it did its task and there is nothing result, e.g. a XMLHTTPRequest that returned nothing when you normally expect that there would be something (like a database call), then I would explicitly return null.
Undefined is different from null when using !== but not when using the weaker != because JavaScript does some implicit casting in this case.
The main difference between null and undefined is that undefined can also mean something which has not been assigned to.
undefined false
(SomeObject.foo) false false
(SomeObject.foo != null) false true
(SomeObject.foo !== null) true true
(SomeObject.foo != false) true false
(SomeObject.foo !== false) true false
This is taken from this weblog
The problem is that you claim to see the difference, but you don't. Take your example. It should really be:
var List = []; // ordered list contains data at odd indexes.
var getObject = function(id) {
for (var i = 1; i < List.length; i+=2) {
if (id === List[i].getId()) {
return List[i];
}
}
// returns undefined by default
}
Your algorithm is flawed because you check even indexes (even though you know there's nothing there), and you also misuse null as a return value.
These kind of functions should really return undefined because it means: there's no such data
And there you are in the heart of the problem. If you don't fully understand null and undefined and may use them wrongly sometimes, how can you be so sure that others will use it correctly? You can't.
Then there are Host objects with their nasty behavior, if you ask me, you better off checking for both. It doesn't hurt, in fact, it saves you some headaches dealing with third party code, or the aformentioned non-native objects.
Except for these two cases, in your own code, you can do what #bobince said:
Keep undefined as a special value for signalling when other languages might throw an exception instead.
When to set/use them...
Note that a method without a return statement returns undefined, you shouldn't force this as an expected response, if you use it in a method that should always return a value, then it should represent an error state internally.
Use null for an intentional or non-match response.
As for how/when to check...
undefined, null, 0, an empty string, NaN and false will be FALSE via coercion. These are known as "falsy" values... everything else is true.
Your best bet is coercion then testing for valid exception values...
var something; //undefined
something = !!something; //something coerced into a boolean
//true if false, null, NaN or undefined
function isFalsish(value) {
return (!value && value !== "" && value !== 0);
}
//get number or default
function getNumber(val, defaultVal) {
defaultVal = isFalsish(defaultVal) ? 0 : defaultVal;
return (isFalsish(val) || isNaN(val)) ? defaultVal : +val;
}
Numeric testing is the real bugger, since true, false and null can be coerced into a number, and 0 coerces to false.
I would treat them as 2 completely different values, and check for the one you know might occur.
If you're checking to see if something has been given a value yet, check against undefined.
If you're checking to see if the value is 'nothing,' check against 'null'
A slightly contrived example:
Say you have a series of ajax requests, and you're morally opposed to using callbacks so you have a timeout running that checks for their completion.
Your check would look something like this:
if (result !== undefined){
//The ajax requests have completed
doOnCompleteStuff();
if (result !== null){
//There is actually data to process
doSomething(result);
}
}
tldr; They are two different values, undefined means no value has been given, null means a value has been given, but the value is 'nothing'.