I am trying to access a certain member in a JavaScript object. In order to do this, I need to try out a couple of key values.
For example, Object['text/html'] which will give me an export link for a HTML document. However, not every object of this type will have a text/html key pair value.
In Python I would solve this problem using a Try-Catch block, with the KeyError exception. If I can do something similar in javascript, as in use an exception in a Try-Catch block, that would be great.
However, if alternatives exists instead of try catch blocks, that do achieve the same end goal, I would like to know about them as well.
EDIT:
I would prefer to use an exception over using functions. I do this because the text/html key might not be there, but it should be there. An exception seems more appropriate for this scenario
Javascript doesn't generate an exception when reading or writing a property that doesn't exist. When reading it, it just returns undefined. When writing it, it just creates the property.
You could create your own function that tests to see if the property exists and throws an exception if it does not (but you'd have to call that function whenever), but JS doesn't make an exception out of that on it's own like you are asking for.
If you want to test if a key exists on an object in javascript, you can use this construct with the in operator:
var obj = {};
var key = "test";
if (key in obj) {
// key exists
} else {
// key doesn't exist
}
If you try to read a key that doesn't exist, you will get undefined as the value.
var obj = {};
var value = obj.test;
alert(value === undefined);
The in operator does a better job of telling you whether the key exists that testing for undefined because undefined is a legal value for a key that exists.
In many cases, where you control the values that the keys have and a key that is present will never have a falsey value, you can also just check if the key has a truthy value:
var obj = {};
var obj.test = "hello";
if (obj.test) {
// key exists and has a truthy value
}
If you want to make sure that the object itself has the property and not any prototype that it is inheriting from, then you can do this:
var obj = {};
var obj.test = "hello";
if (obj.hasOwnProperty(test)) {
// key exists on the object itself (not only on the prototype)
}
Read this!
The accepted answer is correct however omits some points.
1) Accessing nested object
Like someone pointed out in the comment, Javascript returns undefined when the key doesn't exists in the object.
However, if you need to access an object inside an object (or an Array, or a function), well this break.
let a = {};
let userName = 'js'
let data = a.response[userName];
Cuz you will received actually a TypeError, basically because we are trying to read a property of undefined, which doesn't have any.
VM187:2 Uncaught TypeError: Cannot read properties of undefined (reading 'js')
at <anonymous>:2:22
2 Answering the question
The Python principle "Ask forgiveness not permission" - explain is actually for the most part working well in Javascript (and PHP, you didn't ask but well..). There are for sure some difference, or some situation where the difference is important, but for most use cases is the same
So this is how you would do it:
try {
let data = a.key1.key2['whatever'].nested.damn.object;
console.log(data)
} catch (error) {
let data = "noope";
console.log(data);
}
As you can see, in Javascript you don't really care about the error type, (for the most part, sure other situation you should case). Is almost like anything is in a Python's
try:
a = "hello" + 1 + {} + [] # crazy stuff here
except BaseException as bleh:
print(str(bleh))
Documentatin
MDN Working with objects
How do I check if an object has a key in JavaScript? [duplicate]
Related
I'm using JavaScript/jQuery to fetch data as json via an ajax call. The json is then parsed to a JavaScript object. Let's call the object var.
Now I want to assign a value from the object to a variable:
let publicationDay = val["work-summary"][0]["publication-date"]["day"]["value"]
This works, as long this value exists. However, for some results, the object contains null not for ["value"] but for ["day"] (as shown below)
val["work-summary"][0]["publication-date"]["day"] // is null
In this case, let publicationDay = val["work-summary"][0]["publication-date"]["day"]["value"] will throw the following error:
Uncaught TypeError: val['work-summary'][0]['publication-date'].day is null
and the code execution is stopped. Sure, I can check whether val["work-summary"][0]["publication-date"]["day"] === null, but what would be the most elegant way to handle this case? Maybe, in the future even
val['work-summary'][0]['publication-date'] // is null
may occur and my check for null does not work.
I would recommend trying optional chaining.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
Assuming that any of those values could be null:
let publicationDay = val?.["work-summary"]?.[0]?.["publication-date"]?.["day"]?.["value"]
It will set the variable to either day.value or undefined
Depends heavily on your context but here’s some examples.
const publicationDate = val['work-summary'][0]['publication-date'];
// usage
console.log(publicationDate && publicationDate.day && publicationDate.day.value); // very basic
console.log(publicationDate?.day?.value); // optional chaining, better if supported by your environment (should be)
console.log(get(publicationDate, “day.value”)); // lodash get()
although it is a very simple code, I would like to get a full understanding of what is happening in my condition:
let getFreqOn = function(string){
//set a variable for object
let object = {}
for (let key = 0; key < string.length; key++){
// if (object.hasOwnProperty(string[key])) {
// if (object[string[key]]) {
// if (object[string[key]] !== undefined) {
if (string[key] in object) {
object[string[key]]++
}
else{
object[string[key]] = 1
}
}
return object
}
My main concern would be the first condition, I understand what it is they do but I cant put in to plain English how it is working. For example if (string[key] in object) is basically telling my that if a specific property is in the empty object I defined, then I will set then it will be set as the property and incremented. But what I'm trying to wrap my head around is that the object is empty, so how can the property be in the object?
Hoping someone can enlighten me on the conditions that I commented out as well. Sorry for the noob question.
First, the in operator returns a boolean result. It checks whether the string on the left is present as a property name in the object on the right.
Thus
if (string[key] in object)
asks whether that single character of the string is in use as a property name in the object. As you observed, the very first time through the loop that cannot possibly be true, because the object starts off empty.
Thus the if test is false, so the else part runs. There, the code still refers to object[string[key]], but it's a simple assignment. An assignment to an object property works whether or not the property name is already there; when it isn't, a new object property is implicitly created.
The key difference is right there in the two different statements from the two parts of the if - else:
object[string[key]]++; // only works when property exists
object[string[key]] = 1; // works always
I want to create status object. Which can have values like pending, session, rejected, cancelled...
I want to access it like status.isSession();, status.isPending()... etc`
but i want to assign it like this status.toPending(); , status.toSession();
This way there is no room for spelling errors.
I think this is dynamic programming.
You can achieve this in JavaScript, but it will work only with double equals.
You can create an object with constructor like this :
function Status(value){
this.session = true;
this.value = value;
}
Now if you create an instance of this object :
const status = new Status('session');
Sure enough status.session will return true and status.value will return 'session.'
Now you can override toString() method of this object so it returns status.value
Status.prototype.toString = function(){
return this.value;
}
The reason for this is that, when you try to compare an Object vs Primitive, the Engine will try to put them in 'value context' and coerce your object to String by calling .toString() operation.
Sure enough this will produce :
const status = new Status('session');
console.log(status == 'session');
A true in your console.
But this is highly discouraged because is a hack and you might get weird bugs, so I suggest to stay away.
I'm a bit of a newbie in Javascript. I was looking through a bit of Coffeescript code for an Atom package, and I stumbled upon this piece of code:
loadProperties: ->
#properties = {}
fs.readFile path.resolve(__dirname, '..', 'completions.json'), (error, content) =>
{#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error?
return
I was a bit confused by the last line {#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error? because it seems like it assigns multiple values from the parsed JSON content. In my confusion, I decided to convert this back to Javascript using js2Coffee, and I ended up with the following:
function() {
this.properties = {}; // make list of properties (global to provider)
return fs.readFile(path.resolve(__dirname, '..', 'completions.json'), (function(_this) { //load completions.json (using path module)
return function(error, content) { // edit: nvm, js2coffee's fault. not sure why they wrapped the call back in another anonymous function, but this is a node stream callback
var ref;
if (error == null) { // if there are no errors
ref = JSON.parse(content), _this.pseudoSelectors = ref.pseudoSelectors, _this.properties = ref.properties, _this.tags = ref.tags;
}
};
})(this));
This code is a bit more understandable than the above. I can see that ref is assigned the object parsed from the content stream, and is then used to assign the other variables with their designated data. My question is, how does this type of assignment work? In Coffeescript, how does the preprocessor know where to assign the values, and in what order to assign them in?
By inspecting completions.json, the data is not in the order in which the assignments occur.
This is known as Destructuring Assignment.
To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left.
CoffeeScript interprets an object or array on the left side of an = as a pattern, matching the names used...
#pseudoSelectors
#properties
#tags
...to properties or indices within the value being assigned:
JSON.parse(content).pseudoSelectors
JSON.parse(content).properties
JSON.parse(content).tags
(Defining the additional ref to avoid reevaluating JSON.parse(content) for each.)
As for order, CoffeeScript will generally use the order they're mentioned within the assignment. Moving #pseudoSelectors to the 3rd property in the pattern will be echoed in the generated JavaScript.
{#properties, #tags, #pseudoSelectors} = JSON.parse(content) unless error?
var ref;
if (typeof error === "undefined" || error === null) {
ref = JSON.parse(content),
this.properties = ref.properties,
this.tags = ref.tags,
this.pseudoSelectors = ref.pseudoSelectors; // now last
}
Though, JavaScript Objects, like the result of JSON.parse(content), aren't enforced as sorted data structures. If you need to ensure the order of the values, you'll have to instead use an Array.
I'm working with XULRunner and came across the following pattern in a code sample:
var StrangeSample = {
backingStore : "",
get foo() { return this.backingStore + " "; },
set foo(val) { this.backingStore = val; },
func: function(someParam) { return this.foo + someParam; }
};
StrangeSample.foo = "rabbit";
alert(StrangeSample.func("bear"));
This results in "rabbit bear" being alerted.
I've never seen this get/set pattern used in Javascript before. It works, but I can't find any documentation/reference for it. Is this something peculiar to XUL, a recent language feature, or just something I missed? I'm puzzled because I was specifically looking for something like this a few months ago and couldn't find anything.
For reference, removing "get" or "set" results in a syntax error. Renaming them to anything else is a syntax error. They really do seem to be keywords.
Can anyone shed some light on this for me, or point me towards a reference?
As suggested by Martinho, here are some links explaining the getter/setters in JS 1.5:
http://ejohn.org/blog/javascript-getters-and-setters/
http://ajaxian.com/archives/getters-and-setters-in-javascript
Be aware though, they don't seem to be supported in IE, and some developers have (legitimate) concerns about the idea of variable assignment having side-effects.
get/set are not reserved keywords as Daniel points out. I had no problem creating a top-level functions called "get" and "set" and using the alongside the code-sample posted above. So I assume that the parser is smart enough to allow this. In fact, even the following seems to be legitimate (if confusing):
var Sample = {
bs : "",
get get() { return this.bs; },
set get(val) { this.bs = val; }
}
According to Mozilla, they are not in ECMAScript.
JavaScript Setters And Getters:
Usually the setter and getter methods follow the following syntax in JavaScript objects. An object is created with multiple properties. The setter method has one argument, while the getter method has no arguments. Both are functions.
For a given property that is already created within the object, the set method is typically an if/else statement that validates the input for any time that property is directly accessed and assigned later on via code, a.k.a. "set". This is often done by using an if (typeof [arg] === 'certain type of value, such as: number, string, or boolean') statement, then the code block usually assigns the this.(specific)property-name to the argument. (Occasionally with a message logging to the console.) But it doesn't need to return anything; it simply is setting the this.specific-property to evaluate to the argument. The else statement, however, almost always has a (error) message log to the console that prompts the user to enter a different value for the property's key-value that meets the if condition.
The getter method is the opposite, basically. It sets up a function, without any arguments, to "get", i.e. return a(nother) value/property when you call the specific-property that you just set. It "gets" you something different than what you would normally get in response to calling that object property.
The value of setters and getters can be easily seen for property key-values that you don't want to be able to be directly modified, unless certain conditions are met. For properties of this type, use the underscore to proceed the property name, and use a getter to allow you to be able to call the property without the underscore. Then use a setter to define the conditions by which the property's key-value can be accessed and assigned, a.k.a. "set". For example, I will include two basic setters and getters for this object's properties. Note: I use a constant variable because objects remain mutable (after creation).
const person = {
_name: 'Sean';
_age: 27;
set age(ageIn) {
if (typeof ageIn === 'number') {
this._age = ageIn;
}
else {
console.log(`${ageIn} is invalid for the age's key-value. Change ${ageIn} to/into a Number.`);
return 'Invalid Input.';
}
},
get age() {
return this._age;
},
set name(nameIn) {
if (typeof nameIn === 'string') {
this._name = nameIn;
} else {
console.log(`Change ${nameIn} to/into a(ny) String for the name's
key-value.`);
return 'Invalid Input.';
}
},
get name() {
return this._name;
}
};
Where it gets interesting is when you try to set/assign a new key-value for the _age property, because it has to meet the if conditional in order to be successfully assigned, meaning not all assignments are valid, etc.
person.age = 'twenty-eight'; /* output: twenty-eight is invalid for the
age's key-value. Change twenty-eight to/into a Number. */
console.log(person.age); // output: 27 (twenty-eight was never assigned)
person.age = 28; // output: none
console.log(person.age); // output: 28
Note how I was able to access the person._age property via the person.age property thanks to the getter method. Also, similar to how input for age was restricted to numbers, input for the name property is now restricted/set to strings only.
Hope this helps clear things up!
Additionally, some links for more:
https://johnresig.com/blog/javascript-getters-and-setters/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
https://www.infragistics.com/community/blogs/infragistics/archive/2017/09/19/easy-javascript-part-8-what-are-getters-and-setters.aspx