This question already has answers here:
How to avoid 'cannot read property of undefined' errors?
(18 answers)
Closed 2 years ago.
I am creating a personal script that in some instances gets the error:
Cannot read property '0' of undefined
I have something like this
item["OfferSummary"][0]["LowestUsedPrice"][0]["FormattedPrice"]
Is it possible to completely ignore/override this error so that it just prints n/a or -- in that scenario?
You can use try and catch to perform error handling.
You can use a boilerplate function to do so:
function get(obj, property) {
if (Array.isArray(property)) {
var current = obj;
for (var i = 0, l = property.length; i < l; ++i) {
if (Object(current) === current) current = current[property[i]];
else {
current = undefined;
break;
}
}
return current;
}
if (Object(obj) === obj) return obj[property];
}
Pass either a string or an array to get to find the property -- if not found, undefined will be returned.
Example:
get(window, ['location', 'href']); // "http://stackoverflow.com..."
get(Number, 'MAX_VALUE'); // 1.7976931348623157e+308
Even if you can use try and catch I wouldn't do that, I prefer avoid errors at all, so you'd just need to check the object you're reading:
if(item && item["OfferSummary"].length && item["OfferSummary"][0]["LowestUsedPrice"].length) {
//then do whatever
}
if you know that item is always defined you can avoid to check it in the if.
Similar to Qantas' answer, but using an in test. Always expects the property list to be an array, I can't see the point of using this to get a single property so no concession for that case:
function get2(obj, prop) {
for (var i=0, iLen=prop.length - 1; i<iLen; i++) {
if (typeof obj[prop[i]] == 'object') {
obj = obj[prop[i]];
} else {
// Property not found, return undefined (or other suitable value)
return;
}
}
return obj[prop[i]];
}
var foo = {foo:{bar:{meh:'meh!'}}};
var fum = {meh:'meh!'};
console.log(get2(foo,['foo','bar','meh'])); // meh!
console.log(get2(fum,['meh'])); // meh!
console.log(get2(Number,['MAX_VALUE'])); // 1.7976931348623157e+308
console.log(get2(Object,['prototype','toString'])); // function toString() { ... }
Edit
Per Qantas' comment, the test has been updated.
Related
I'm writing some code to generate JSX based on items in an array, however I'm getting the error 'Cannot read property 'length' of undefined' despite having checks in place to see whether the variable is actually undefined. The code is really long so I've summarised the problem here:
render() {
var metadata = this.props.data["metadata"]
if(typeof metadata !== undefined && metadata.length !== undefined) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}
The render method is inside a component, which is placed inside another, by doing
<Marksheet data={this.state.data} />
I've checked to make sure that data is actually defined and being supplied as a prop, but even if it was undefined, I don't understand why it's saying cannot read property length of undefined.
You could also use the Array.isArray method:
render() {
var metadata = this.props.data["metadata"];
if(Array.isArray(metadata)) {
metadata.forEach(val => console.log(val));
}
}
The string "undefined" is not the same as undefined.
Try changing your code to the following:
render() {
var metadata = this.props.data["metadata"]
if(metadata !== undefined && metadata.length !== undefined) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}
That basically checks to ensure both metadata and metadata.length are not equal to undefined before running that for loop.
Or just simply. You might also check for metadata.length >0 (instead of just length)
render() {
var metadata = this.props.data["metadata"]
if(metadata && metadata.length) {
for(var i=0; i<metadata.length; i++) {
console.log(metadata[i]);
}
}
}
This question already has answers here:
JS checking deep object property existence [duplicate]
(2 answers)
Closed 6 years ago.
After spending many hours today searching for a specific condition functionality and testing my modified finds. I thought I share my coding snippets and knowledge here. I'm not too good at answering other questions so I thought it would do to post my finds and hope it would benefit others. Since this site has been really helpful with my projects.
Anyway. At some point when you get to a stage scripting more complicated scripts. You'll most likely bump into a problem were you'll need to check deep in objects if a certain property exists. This has occurred mostly with JSON API from my experience.
Example Issue
if (someObject && someObject.nextObject && someObject.nextObject.andAnother) {
// do something if all of this exists
}
Trying to check the deepest property, when one property in the middle doesn't exist, will throw a reference error.
ReferenceError: something is not defined
At some point these can get really long and messy to work with. Which is pretty much silly.
Trying to Tidy Like That Makes JSLint Complain & Can Be Harder for Another Scripter to Read
JSLint doesn't like when code ends up like this when scripters try to reduce the amount of characters on one line. Even I find it more difficult to read with other nested conditions together:
if (someObject
&& someObject.nextObject
&& someObject.nextObject.andAnother) {
// do something if all of this exists
}
There's multiple ways of making this less clutter. Below is an example of some different versions of snippet functions for this object.
var object = {
nextObject: {
anArray: [{
value: true
}]
}
};
Boolean Function with String Perimeter
var hasDeepProperty = function (obj, pathString) {
var i, properties = pathString.split("."), l = properties.length;
for (i = 0; i < l; i++) {
if (obj.hasOwnProperty(properties[i])) {
obj = obj[properties[i]];
} else {
return false;
}
}
return true;
};
console.log(hasDeepProperty(object, "nextObject.0.value")); // returns true
console.log(hasDeepProperty(object, "nextObject.doesNotExist.value")); // returns false
Boolean Function with Array Perimeter
var hasDeepProperty = function (obj, pathArray) {
var i, properties = pathArray, l = properties.length;
for (i = 0; i < l; i++) {
if (obj.hasOwnProperty(properties[i])) {
obj = obj[properties[i]];
} else {
return false;
}
}
return true;
};
console.log(hasDeepProperty(object, ["nextObject", 0, "value"])); // returns true
console.log(hasDeepProperty(object, ["nextObject", "doesNotExist", "value"])); // returns false
Prototype Boolean Function with String Perimeter
Object.prototype.hasDeepProperty = function (pathString) {
var i, properties = new String(pathString).split("."), l = properties.length, obj = new Object(this);
for (i = 0; i < l; i++) {
if (obj.hasOwnProperty(properties[i])) {
obj = obj[properties[i]];
} else {
return false;
}
}
return true;
};
console.log(object.hasDeepProperty("nextObject.0.value")); // returns true
console.log(object.hasDeepProperty("nextObject.doesNotExist.value")); // returns false
Prototype Boolean Function with Array Perimeter
Object.prototype.hasDeepProperty = function (pathArray) {
var i, properties = pathArray, l = properties.length, obj = new Object(this);
for (i = 0; i < l; i++) {
if (obj.hasOwnProperty(properties[i])) {
obj = obj[properties[i]];
} else {
return false;
}
}
return true;
};
console.log(object.hasDeepProperty(["nextObject", 0, "value"])); // returns true
console.log(object.hasDeepProperty(["nextObject", "doesNotExist", "value"])); // returns false
I'm aware that declaring with the new keyword that isn't a function simulated as a class is discouraged. But for some reason Prototype causes slice method not to exist for string and same for hasOwnProperty for the object.
I hope others find this useful and there be something like this to be added on the next version of JavaScript.
This my first: post my own QnA. And Happy New Year everyone.
I've written a couple of functions that effectively replicate JSON.stringify(), converting a range of values into stringified versions. When I port my code over to JSBin and run it on some sample values, it functions just fine. But I'm getting this error in a spec runner designed to test this.
My code:
// five lines of comments
var stringify = function(obj) {
if (typeof obj === 'function') { return undefined;} // return undefined for function
if (typeof obj === 'undefined') { return undefined;} // return undefined for undefined
if (typeof obj === 'number') { return obj;} // number unchanged
if (obj === 'null') { return null;} // null unchanged
if (typeof obj === 'boolean') { return obj;} // boolean unchanged
if (typeof obj === 'string') { return '\"' + obj + '\"';} // string gets escaped end-quotes
if (Array.isArray(obj)) {
return obj.map(function (e) { // uses map() to create new array with stringified elements
return stringify(e);
});
} else {
var keys = Object.keys(obj); // convert object's keys into an array
var container = keys.map(function (k) { // uses map() to create an array of key:(stringified)value pairs
return k + ': ' + stringify(obj[k]);
});
return '{' + container.join(', ') + '}'; // returns assembled object with curly brackets
}
};
var stringifyJSON = function(obj) {
if (typeof stringify(obj) != 'undefined') {
return "" + stringify(obj) + "";
}
};
The error message I'm getting from the tester is:
TypeError: Cannot convert undefined or null to object
at Function.keys (native)
at stringify (stringifyJSON.js:18:22)
at stringifyJSON (stringifyJSON.js:27:13)
at stringifyJSONSpec.js:7:20
at Array.forEach (native)
at Context.<anonymous> (stringifyJSONSpec.js:5:26)
at Test.Runnable.run (mocha.js:4039:32)
at Runner.runTest (mocha.js:4404:10)
at mocha.js:4450:12
at next (mocha.js:4330:14)
It seems to fail with:
stringifyJSON(null) for example
Generic answer
This error is caused when you call a function that expects an Object as its argument, but pass undefined or null instead, like for example
Object.keys(null)
Object.assign(window.UndefinedVariable, {})
As that is usually by mistake, the solution is to check your code and fix the null/undefined condition so that the function either gets a proper Object, or does not get called at all.
Object.keys({'key': 'value'})
if (window.UndefinedVariable) {
Object.assign(window.UndefinedVariable, {})
}
Answer specific to the code in question
The line if (obj === 'null') { return null;} // null unchanged will not
evaluate when given null, only if given the string "null". So if you pass the actual null value to your script, it will be parsed in the Object part of the code. And Object.keys(null) throws the TypeError mentioned. To fix it, use if(obj === null) {return null} - without the qoutes around null.
Make sure that object is not empty (null or undefined ).
Error:
let obj
Object.keys(obj)
Solution:
Object.keys(obj || {})
Make sure that destination object is not empty ( null or undefined ).
You can initialize destination object with empty object like below:
var destinationObj = {};
Object.assign(destinationObj, sourceObj);
This is very useful to avoid errors when accessing properties of null or undefined objects.
null to undefined object
const obj = null;
const newObj = obj || undefined;
// newObj = undefined
undefined to empty object
const obj;
const newObj = obj || {};
// newObj = {}
// newObj.prop = undefined, but no error here
null to empty object
const obj = null;
const newObj = obj || {};
// newObj = {}
// newObj.prop = undefined, but no error here
Adding Object && works before putting the object on to map.
objexts && Object.keys(objexts)?.map((objext, idx) =>
In my case, I added Lucid extension to Chrome and didn't notice the problem at that moment. After about a day of working on the problem and turning the program upside down, in a post someone had mentioned Lucid. I remembered what I had done and removed the extension from Chrome and ran the program again. The problem was gone. I am working with React. I thought this might help.
I solved the same problem in a React Native project. I solved it using this.
let data = snapshot.val();
if(data){
let items = Object.values(data);
}
else{
//return null
}
Replace
if (typeof obj === 'undefined') { return undefined;} // return undefined for undefined
if (obj === 'null') { return null;} // null unchanged
with
if (obj === undefined) { return undefined;} // return undefined for undefined
if (obj === null) { return null;} // null unchanged
If you're using Laravel, my problem was in the name of my Route.
Instead:
Route::put('/reason/update', 'REASONController#update');
I wrote:
Route::put('/reason/update', 'RESONController#update');
and when I fixed the controller name, the code worked!
In my case I had an extra pair of parenthesis ()
Instead of
export default connect(
someVariable
)(otherVariable)()
It had to be
export default connect(
someVariable
)(otherVariable)
Below snippet is sufficient to understand how I encountered the same issue but in a different scenario and how I solved it using the guidance in the accepted answer. In my case I was trying to log the keys of object present in the 0th index of the 'defaultViewData' array using Object.keys() method.
defaultViewData = [{"name": "DEFAULT_VIEW_PLP","value": {"MSH25": "LIST"}}]
console.log('DEFAULT_VIEW', Object.keys(this.props.defaultViewData[0]));
The console.log was not getting printed and I was getting the same error as posted in this question. To prevent that error I added below condition
if(this.props.defaultViewData[0]) {
console.log('DEFAULT_VIEW', Object.keys(this.props.defaultViewData[0]));
}
Adding this check ensured that I didn't get this error. I hope this helps for someone.
Note: This is React.js code. (although to understand the problem it doesn't matter).
reactTraverser.js:6 Uncaught TypeError: Cannot convert undefined or null to object at Function.keys () at reactTraverser.js:6
If you are getting this error on typeScript Try using it without Live Server this error will not be displayed
I have the same problem with a element in a webform. So what I did to fix it was validate.
if(Object === 'null')
do something
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.
Here is the line which is causing null or not an object error
if(frm.elements["hdn_retain"+indexval].value==""){
....
} else {
....
}
frm.elements["hdn_retain"+indexval] may be a null object. So, it will have error when getting the value. You can check the frm.elements["hdn_retain"+indexval] if it is null first.
if(frm.elements["hdn_retain"+indexval] != null && frm.elements["hdn_retain"+indexval].value=="")
Either frm or frm.elements["hdn_retain"+indexval] isn't a valid object (doesn't exist in the dom) and therefore you can't access it's property.
you could try something like:
if(frm.elements["hdn_retain"+indexval] && frm.elements["hdn_retain"+indexval].value==""){
Following is the result of alert statement:
alert("frm:::"+frm);
alert("frm elements::::"+frm.elements);
alert("frm hdn_retain :: "+frm.elements["hdn_retain"+indexval]);
frm:::[object]
frm elements::::[object]
frm hdn_retain :: undefined
you can use this utility method getProperty i always use to make sure i get a nested namespace back without worrying about whether or not something is defined:
function getProperty(ns, obj) {
var nsArray = ns.split('.'),
i = 0,
nsLen = nsArray.length;
while (nsLen > 0) {
var newNs = nsArray.shift();
if (obj[newNs]) {
obj = obj[newNs];
} else {
return false;
}
nsLen = nsArray.length;
}
return obj;
};
var index = "hdn_retain" + indexval;
// the following `value` will come back as a valid object/value or a false
value = getProperty('elements.' + index + '.value', frm);
if (value) {
// do whatever
} else {
// do not whatever
}
this can be applied not only to this situation but to any other situation you need to make sure a certain namespace is available before usage.