Javascript - any way to access child properties only if they exist? - javascript

I'm thinking it would be useful to have something like:
let data = { item : { subItem: { text: 'Nested thing' } } }
if(data.?item.?subItem.?text){
//do something
}
Which would be shorthand for
if( data && data.item && data.item.subItem && data.item.subItem.text )
Can this be done? What would this be called?

At the moment the way you are doing it is the best one (performance speaking, code clarity and debuggability), usually objects doesn't get that nested deeper.
A (worse) option would be to simply access the member and use a try/catch construct to otherwise continue.
However for the future there is a feature called optional chaining planned, which will directly offer the functionality you where talking about. As userqwert stated with babel-plugin-transform-optional-chaining (currently in alpha) one can use that feature now/in the short future.

Here's the function I use
getValue(element,path) {
"use strict";
if (!Array.isArray(path)) {
throw new Error("The first parameter must be an array");
}
for (var i = 0; i < path.length; i++) {
if (typeof element == "object" && typeof element[path[i]] != "undefined") {
element = element[path[i]];
} else {
return undefined;
}
}
return element;
}
For your example, should be called like so
getValue(data,['item','subItem','text']);
This has some draw back though... But does the job.
If you wanted you could use this and work out a way to make it work directly on the Object prototype.

Related

JavaScript loop through all existing objects to find an object key

I am trying to debug a system that was built by someone else. I have a minified library that makes an ajax (xhr) call to an external data source and writes the received data to an object or a variable. The call is made immediately after page load so I can't catch it by appending a function to register all XHR call requests. So I am trying to run a loop through all variables and objects that the browser window has. I am trying this:
var foundVar = false;
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (var name in obj) {
if (obj[name] && {}.toString.call(obj[name]) === '[object Function]') { //making sure that the object is not a function
} else {
if (name == 'searchedKey') { //found the object with key = searchedKey
console.log(obj[name]);
foundVar = true;
} else {
setTimeout(loopThroughObject.bind(null, obj[name]), 10); //do more recursion of inner objects
}
}
}
} catch (error) {}
}
}
The problem is that the setTimeout(loopThroughObject.bind(null, obj[name]), 0); part stacks up and a memory issue occurs. I tried the simple loopThroughObject(obj[name]), but I am facing the "Too much recursion" error after 25000 loops. It also seems that I am missing something and it causes the loop go through some object types that I don't need. Does anyone know a more efficient way to do that loop?
P.S. I tried a very simple HTML page and the code works fine:
<html>
<head>
<script>
var test = JSON.parse("{\"searchedKey\":\"12\"}");
</script>
</head>
<body>
</body>
</html>
The problem is almost certainly the fact that window has several properties that point back to itself, so your code is going into an infinite loop. There may well be other circular references.
You can remember what objects you've already looked in using a Set, like this (I've also added a few other tweaks; for instance, you can check for a function with typeof x === "function"):
let foundVar = false;
let seen = new Set();
loopThroughObject(this);
function loopThroughObject(obj) {
if (!foundVar) {
try {
for (const name in obj) {
const value = obj[name];
if (typeof value !== "function") {
if (name == "searchedKey") { // found the object with key = searchedKey
console.log(value);
foundVar = true;
break;
} else if (value && typeof value === "object" && !seen.has(value)) {
seen.add(value);
loopThroughObject(value); // No need for setTimeout
}
}
}
} catch (error) {}
}
}

string prototype custom method to make use of encodeURIComponent()

I am writing this method encodedURIComponentValue() for Javascript string:
the idea is to allow me to call : "some string".encodedURIComponentValue()
The code is as:
if (typeof String.prototype.encodedURIComponentValue != 'function') {
String.prototype.encodedURIComponentValue = function (str) {
if (str && str.length > 0)
return encodeURIComponent(str);
else
return "";
};
}
but in some case it does not work:
var encodedVal = $("body").find("option:selected").first().text().encodedURIComponentValue() // text() = "Option1"
console.log(encodedVal); // I only see "" (empty)
Any idea ?
You may find the following answer helpful as it explains prototype, constructor function and the value of this.
In this case I would not advice doing it like you do. You don't own String and modifying it breaks encapsulation. The only "valid" situation would be if you need to implement an existing method to support older browsers (like Object.create). More info on that here.
You could do what you're doing with:
encodeURIComponent(
$("body").find("option:selected").first().text()
);
So other then liking the other syntax there really isn't any reason for it.
OK, it is my stupid mistake - the str is the parameter which was never supplied.
So I changed to this and it works:
if (typeof String.prototype.encodedURIComponentValue != 'function') {
String.prototype.encodedURIComponentValue = function () {
if (this && this.length > 0)
return encodeURIComponent(this);
else
return "";
};
}
Hope I will understand more about this keyword in Js

Read value or return

Often writing function's code I need to make sure certain values are defined or I want immediately return false value. But writing whole if block feels too much typing. Is it possible to write instead of:
function getSomethingByModel(model) {
var id = model.id;
if (! id) {
return;
}
// rest of the code
}
Something like this:
function getSomethingByModel(model) {
var id = model.id || return;
// rest of the code
}
This is pure aesthetics question, not functional one.
To some extent, you can use the && operator to accomplish this and avoid cumbersome if statements:
function getSomethingByModel(model) {
var id = model && model.id,
thing = id && getThingById(id),
otherThing = thing && getOtherThingFromThing(thing);
return otherThing || null; // or alternatively, just return otherThing;
}
If any stage of the process produces a falsey value, the logic will just quickly fall through to the end and return null (or the first falsey value encountered if you use the alternative return statement above).
You could define all your properties at the top of the function (or wherever, because hoisting), then use the side-effects of assignment to cause a return. For example:
function getSomethingByModel(model) {
var id;
if(!(id = model.id)) return false;
// rest of the code
}

How do I easily get the value of a nested field in Javascript without null reference exceptions?

I've seen a lot of posts on using the in operator in Javascript to check if a field exists on an object or up the object's prototype chain, but I've seen none for going down the other way.
Let's say I have an object:
var obj = {
myField
}
And myField is set to another object, with various fields on it:
obj.myField = {
mySetting: true
}
If I want to reference mySetting, let's say in an if statement, I have to do something like this:
if (obj.myField && obj.myField.mySetting && obj.myField.mySetting === true)
If I use in, it is still clumsy:
if ("myField" in obj && "mySetting" in obj.myField && obj.myField.mySetting === true)
The following returns false:
if ("mySetting" in obj)
Is there some syntax I'm not aware of that can allow me to write a decent if statement here, returning false if it doesn't exist, or barring that, at least not throw an exception. I use jQuery, so a solution with that would be fine as well.
var a = { b: { c: { d: 10 } } };
var res = [ 'b', 'c', 'd' ].reduce(function(p, c) {
return p ? p[c] : p;
}, a);
You could improve that with some syntactic sugar, I suppose:
function nested_get(obj, path) {
return path.split('.').reduce(function(p,c){return p?p[c]:p;}, obj);
}
var obj = { some: { weird: { nested: 'thing' } } };
alert(nested_get(obj, 'some.weird.nested'));
You are checking for myfield instead of myField that is why you are getting it as false. Remember that JavaScript is case sensitive.
alert(("myField" in obj && "mySetting" in obj.myField && obj.myField.mySetting === true));
Working demo - http://jsfiddle.net/Yfuvu/
I'm not sure there's a nice way to describe a nested property, which you would of course need to do in order to directly check whether it exists or not. As an alternative, you might consider using an intermediate variable to stand in for the field you want to test:
var myField = obj.myField;
if (myField.mySetting && myField.mySetting === true) { /* do stuff */ }
Finally, it's worth at least mentioning the Object.hasOwnProperty method that you might use to check for the existence of a field. Rewriting the example above:
var myField = obj.myField;
if (myField.hasOwnProperty('mySetting') && myField.mySetting === true) {
/* do stuff */
}

What's the simplest approach to check existence of deeply-nested object property in JavaScript? [duplicate]

This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Closed 8 years ago.
I have to check deeply-nested object property such as YAHOO.Foo.Bar.xyz.
The code I'm currently using is
if (YAHOO && YAHOO.Foo && YAHOO.Foo.Bar && YAHOO.Foo.Bar.xyz) {
// operate on YAHOO.Foo.Bar.xyz
}
This works, but looks clumsy.
Is there any better way to check such deeply nested property?
If you expect YAHOO.Foo.Bar to be a valid object, but want to make your code bulletproof just in case it isn't, then it can be cleanest to just put a try catch around it and let one error handler catch any missing segment. Then, you can just use one if condition instead of four that will detect if the terminal property exists and a catch handler to catch things if the intermediate objects don't exist:
try {
if (YAHOO.Foo.Bar.xyz) {
// operate on YAHOO.Foo.Bar.xyz
} catch(e) {
// handle error here
}
or, depending upon how your code works, it might even just be this:
try {
// operate on YAHOO.Foo.Bar.xyz
} catch(e) {
// do whatever you want to do when YAHOO.Foo.Bar.xyz doesn't exist
}
I particularly use these when dealing with foreign input that is supposed to be of a particular format, but invalid input is a possibility that I want to catch and handle myself rather than just letting an exception propagate upwards.
In general, some javascript developers under-use try/catch. I find that I can sometimes replace 5-10 if statements checking input with a single try/catch around a larger function block and make the code a lot simpler and more readable at the same time. Obviously, when this is appropriate depends upon the particular code, but it's definitely worth considering.
FYI, if the usual operation is to not throw an exception with the try/catch, it can be a lot faster than a bunch of if statements too.
If you don't want to use the exception handler, you can create a function to test any arbitrary path for you:
function checkPath(base, path) {
var current = base;
var components = path.split(".");
for (var i = 0; i < components.length; i++) {
if ((typeof current !== "object") || (!current.hasOwnProperty(components[i]))) {
return false;
}
current = current[components[i]];
}
return true;
}
Example usage:
var a = {b: {c: {d: 5}}};
if (checkPath(a, "b.c.d")) {
// a.b.c.d exists and can be safely accessed
}
var _ = {};
var x = ((YAHOO.Foo || _).Bar || _).xyz;
Consider this utility function:
function defined(ref, strNames) {
var name;
var arrNames = strNames.split('.');
while (name = arrNames.shift()) {
if (!ref.hasOwnProperty(name)) return false;
ref = ref[name];
}
return true;
}
Usage:
if (defined(YAHOO, 'Foo.Bar.xyz')) {
// operate on YAHOO.Foo.Bar.xyz
}
Live demo: http://jsfiddle.net/DWefK/5/
If you need to check the correctness of the path, rather than the existance of the "xyz" member on the "YAHOO.Foo.Bar" object, it will probably be easiest to wrap the call in a try catch:
var xyz;
try {
xyz = YAHOO.Foo.Bar.xyz;
} catch (e) {
// fail;
};
Alternately, you can do some string-kong-fu-magicTM:
function checkExists (key, obj) {
obj = obj || window;
key = key.split(".");
if (typeof obj !== "object") {
return false;
}
while (key.length && (obj = obj[key.shift()]) && typeof obj == "object" && obj !== null) ;
return (!key.length && typeof obj !== "undefined");
}
The use as follows:
if (checkExists("YAHOO.Foo.Bar.xyz")) {
// Woo!
};
This problem is solved quite beautifully by coffeescript (which compiles down to javascript):
if YAHOO.Foo?.Bar?.xyz
// operate on YAHOO.Foo.Bar.xyz
use a try catch.
a={
b:{}
};
//a.b.c.d?true:false; Errors and stops the program.
try{
a.b.c.d;
}
catch(e){
console.log(e);//Log the error
console.log(a.b);//This will run
}
I actually voted to close the question as duplicate of javascript convert dotnotation string into objects.
However, I guess it's a different topic, but the answer there might still be helpful if you don't want to try-catch all the time.

Categories

Resources