Checking if an object has a property and accessing it - javascript

I'm new to TypeScript (and js) and this is probably basic:
const myObj = {
"name": "Johnny",
"age": 29
}
const accessProperty = (key : string) => {
if(key in Object.keys(myObj)) {
// TODO: access myObj.key...
}
}
How do I access the property of myObj that is represented by key
Is this the right way to check if key is indeed a property of myObj?
Thanks.

How do I access the property of myObj that is represented by key
You can access the property via myObj[key]
Is this the right way to check if key is indeed a property of myObj?
Someone posted a link to the optional chaining operator. This is probably the best way to go. There are times when you want to iterate through the keys of an object (mostly when you're trying to figure out what it is) but in general it is hard to create meaningful code for keys that you're not expecting, so again using the optional chaining operator is probably the best way to go.

You use the dot syntax to access object fields, that don't contain restricted characters (like space or /). If your field is an arbitrary string or a variable, you can use the square brackets syntax:
return myObj[key]
You might also find optional chaining operator ?. useful, since it returns undefined instead of throwing an Error, when you are accessing an invalid object field:
const obj = {
field: "value",
}
console.log(obj.field2); // => Error
console.log(obj?.field2); // => undefined
You can also use it with square brackets:
obj?.['someField']

myObj[key] // may be undefined or raise an error
key in myObj operator in checks if the left-hand operand is a key of the right-hand operand. Calling Object.keys() will give you an array of keys, which is number-indexed and may result in a false positive if key is a number that is within array length.

Related

Why does JS allow property access with an array as key?

Suppose I have an object
obj = {
a : 1
}
I'm able to access property a via obj["a"] but I'm also able to access it via obj[["a"]]. How is that possible?
Object keys are always strings (or, rarely, symbols). When you do
obj[<expression>]
the interpreter will try to turn expression into a valid key, if it isn't one already. In this case, turning ["a"] into a string results in "a", so both obj["a"] and obj[["a"]] work.
(When an array is implicitly turned into a primitive, like here, it gets .joined by a comma, and ["a"].join(',') === "a")

Why are arrays / braces used in object literal definitions to allow dynamic computing of keys in Javascript / ES2015?

I came across this example in a MDN doc, for example:
class Search1 {
constructor(value) {
this.value = value;
}
[Symbol.search](string) {
return string.indexOf(this.value);
}
}
If I pull up node, and run just the line included as part of the object literal, it doesn't work:
> Symbol.search
Symbol(Symbol.search)
> [Symbol.search]
[ Symbol(Symbol.search) ]
> [Symbol.search]('somthing')
TypeError: [Symbol.search] is not a function
I think I've also seen this syntax in a few other places, like e.g. in the react docs:
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
Is this just a use of destructuring syntax? It doesn't seem like it.
brackets are used when you have variable as key and not a plain string.
const obj = {
"someId": 'abc',
};
const e = {
target: {
id: "someId"
}
};
console.log(obj[e.target.id]);
Apart from above mentioned, it is also used to access the numeric keys (Just like array) and when key is computed. See - https://javascript.info/object#square-brackets
Turns out, that's just part of the spec.
It looks a bit like array de-structuring, but it's not.
In the case of [event.target.id], you're assigning the value that event.target.id points to be a key in the object passed to setState(). If you tried to do this without the brackets ([]), it would not work, not how you expect anyway.
In the case of [Symbol.search](string), here you're using the Symbol.search symbol (see symbols) as a key which is dynamically evaluated immediately to its actual, unique value. The dynamic evaluation is allowed because this value becomes the key in an object literal definition. The value which the key points to is a function being defined here, which takes string as its first and only parameter, and operates on that. This is a hook for allowing an object to define how it behaves when used as a parameter, in this case to the .search() function. See here.
Thanks for #randomSoul's answer, for completing it I might say that braces also make you to have a string key with spaces like below:
const myOBJ = {
'my key': 'my assigned String Value'
}
Then you can call that key value pair with this braces syntax like:
console.log(myOBJ['my key'])
This is rarely used in JavaScript, but the main purpose of using braces for getting the value from object literal is for getting dynamically computed keys of object. Like that you have an object that each key is represented user id, and you based on that you want to decide to get the specific user id that you got from your url params or somewhere else then you would be able to get user data like below:
console.log(lastFiveUserData[myUserId].age)

Valid property names, property assignment and access in JavaScript

Updated Question
What, exactly, qualifies as a valid property name in Javascript? How do various methods of property assignment differ? And how does the property name affect property access?
Note
The answers to my original question (seen below) helped to clear some things up, but also opened a new can of worms. Now that I've had a chance to become a bit more familiar with JavaScript, I believe I've been able to figure a lot of it out.
Since I had a hard time finding this information consolidated into one explanation, I thought it might be helpful to expand my original question, and attempt to answer it.
Original Question
Originally, there was some confusion with the MDN JavaScript guide (object literals). Specifically, I wondered why they claimed that if a property name was not a valid JavaScript identifier, then it would have to be enclosed in quotes. Yet, they offered example code that showed that the number 7 could be used — without quotes — as a property name.
As it turns out, the guide simply left off one important part, and Pointy updated it (changes in bold):
If the property name would not be a valid JavaScript identifier or number, it must be enclosed in quotes.
I also wondered why property names were allowed to deviate away from the "may not start with a digit" rule, that applies to identifiers. That question actually reveals the complete misunderstanding that I had of property names, and is what lead me to do some more research.
Answer for 1st question:
Yes, the statement given in the MDN guide is not 100% accurate, but in your daily work it'd be better to follow it as rule. You really don't need to create properties names which are numbers.
Answer for 2nd question:
A property name may not start with a digit but a property name that is a number without any other characters in its name is fine.
This exception exists because the properties with number for name as the same as indexes.
Let's try this:
var obj = {7: "abc"};
obj[7]; // works fine
obj.7; // gives an error (SyntaxError)
Now try to call Array.push on the object and observe what happens:
Array.prototype.push.call(obj, "xyz");
console.log(obj);
console.log(obj[0]);
// Prints
Object {0: "xyz", 7: "abc", length: 1}
"xyz"
You can see that few new properties (one with name 0 and another with name length) have been added to the object. Moreover, you can use the object as an array:
var obj = { "0": "abc", "1": "xyz", length: 2 };
Array.prototype.pop.call(obj); // Returns: "xyz"
Array.prototype.pop.call(obj); // Returns: "abc"
You can use array's methods on objects and this is called Duck Typing.
Arrays are nothing more than objects with some predefined methods.
From MDN:
Array elements are object properties in the same way that length is a property, but trying to access an element of an array with dot notation throws a syntax error, because the property name is not valid. There is nothing special about JavaScript arrays and the properties that cause this. JavaScript properties that begin with a digit cannot be referenced with dot notation and must be accessed using bracket notation.
Now you can understand why a number for property name is valid. These are called just indexes and they are used in JavaScript arrays. And since JavaScript needs to be consistent with other languages, numbers are valid for indexes/properties names.
Hope this makes it clear.
Here are some interesting articles:
JavaScript identifiers (in ECMAScript 5)
JavaScript identifiers (in ECMAScript 6)
Short Answer
Object property names can be any valid identifier, numeric literal, or string literal (including the empty string).
With that said, there are some potentially confusing intricacies to keep in mind about JavaScript property names, as described below.
And unless you're working with valid (non-negative integer) array indexes, it's a good idea to explicitly assign all numerical property names as strings.
Negative Numbers
What might look like a negative number is actually an expression — something property names do not support.
// SyntaxError
const obj = { -12: 'nope' };
Fortunately, bracket notation handles expressions for us.
// Successful property assignment.
const obj = {};
obj[-12] = 'yup';
Typecasting
All property names are typecasted into strings before being stored.
const obj = {
12: '12'
};
console.log(typeof Object.keys(obj)[0]); // -> string
Parsing
But even before typecasting occurs, keys are parsed according to the syntax used, and transformed into a decimal literal.
const obj = {
// Valid string literal
'022': '022',
// Interpreted as decimal
6: '6',
// Interpreted as floating-point
.345: '0.345',
// Interpreted as floating-point
1.000: '1',
// Interpreted as floating-point
8.9890: '8.989',
// Interpreted as decimal
000888: '888',
// Interpreted as octal
0777: '511',
// Interpreted as hexadecimal
0x00111: '273',
// Interpreted as binary
0b0011: '3',
};
/* Quoted property name */
console.log(obj['022']); // "022"; as expected
console.log(obj[022]); // undefined; 022 is an octal literal that evaluates to 18 before our lookup ever occurs
/* Valid (non-negative integer) array index */
console.log(obj[6]); // "6"; as expected
console.log(obj['6']); // "6"; as expected
/* Non-valid array index */
console.log(obj[0x00111]); // "273"; we're accessing the property name as it was assigned (before it was parsed and typecasted)
console.log(obj['0x00111']); // undefined; after parsing and typecasting, our property name seems to have disappeared
console.log(obj['273']); // "273"; there it is, we found it using the evaluation of our original assignment

Can an Object object be coerced into an Array object?

Crockford writes in http://javascript.crockford.com/survey.html:
"There are two ways to make a new array:
var myArray = [];
var myArray = new Array();"
So I'm confused by these two lines in some AJAX code I am reading:
var obj={}; // obj is an Object object (i.e. a hash table)
obj[4] = 'x'; // now obj is suddenly an Array object via an integer key?
In JavaScript are an object and an array really just the same thing, but with a variant on the key type?
In other words, is this the same as in php where we can use either a name (string) or an integer for a hash key?
I've Googled for an answer on this but can't seem to nail down an article which discusses this issue.
One possibility that comes to mind is that perhaps the first line is syntactic lint because the 2nd line overwrites the previous definition of obj as it creates a new Array object.
it does not become an array, it is simply an Object with a '4' property, like this:
var obj = {
'4': 'x'
};
it is just converted to a string when used as a property like obj['4'] = 'x';
Everything but primitive datatypes is an object in JavaScript. Objects can have a properties and there are two ways to access object properties:
Dot notation, foo.bar, which you can use as long as the property name is a valid identifier.
Bracket notation, foo['bar'] which you have to use if the key is not a valid identifier [spec]. For example, if it is a number, or contains a space or you have a variable with the name.
Hence, bracket notation is not a characteristic of arrays and if you see it, it does not mean the value is an array. It is simple one of two ways of accessing properties.
The elements of an array are just properties with numeric keys. Arrays are built on top of objects and implement some additional methods which treat these numeric properties in a special way. For example the .length property is automatically updated when you add new elements. But ultimately they are just normal properties.
In your example you have a simple object. You have to access the property with obj[4] or obj['4'] because obj.4 is invalid since 4 is not a valid identifier (basically everything that you can use as variable name is a valid identifier. var 4 = 'foo'; is invalid).
And since arrays are just objects, if you could use numbers as identifiers, you were also able to access an element with arr.4.
As far as I know, no, an object can't be coerced into an array. But, it can look and act like an array, and that's what's happening here. Numbers, and anything else that can be coerced to a string, are perfectly valid property names for Javascript objects, so
obj[4] = 1;
obj['spam'] = 2;
are both valid ways of setting a property on the object. That doesn't make the object an array. An Array is a special class of object with specific methods (.slice(), .concat(), etc) and a length property that's kept up to date with the number of items in the array.
Yes
Javascript Array is very different from tradition array, you can think of it as object.
var array = [1,2,3] is equivalent to var object = {'0' : 1, '1' : 2, '2' : 3}
except array inherited from Array.prototype and object inherited from Object.prototype, where Array.prototype will contain method such as length.
Javascript is a loosely-typed, prototype-based language. Even primitive types like a boolean can be treated like an object (though you aren't going to get far). Almost everything in javascript is, at root, an object.
Understanding this, an array IS an object. You can arbitrarily add properties to any object:
var xml = new XMLHttpRequest();
xml[4] = 'x';
console.log(xml);
That object is still an instance of XMLHttpRequest. It now has a property labeled 4 with a value of x. You can treat anything like this -- even a function:
var test_func = function () {
alert('woah!');
}
test_func[4] = 'x';
console.log(test_func[4]);
The take-away here is that the obj[key] = value notation is NOT indicative of an "array" type, like it is in languages such as PHP. Rather, it is an alternate way to access properties of any object, and is equivalent to obj.key = value (you can't use obj.4 = 'x', though, that's invalid syntax). The other take-away is that any object in javascript can be modified or used in pretty much any way. You shouldn't misuse objects, but you can
Check it out here: http://jsfiddle.net/w2AqJ/
Documentation
Array on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array
Javascript "associative arrays" considered harmful by Andrew Dupont - http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/

What is the best way to check that multiple variables are set?

This is more of a general practices question.
The language I am working with is Javascript. I have a function that is getting an object with many variables (okay, just 10 variables). What is the best way to make sure this function is getting all the required variables and that they are all set?
I know, I know, why not just use a if statement. That's a big chunk of if statements! As I grow as a programmer, I know that may not be the best method for this. I'm looking for a shortcut actually. How would you check a large sum of variables for existence and non-blank values?
This is a pretty neat way of handling validation, I usually use this when checking for required fields in form inputs.
var theObj = { /* object loaded from server */ }
function checkTheObj(testObj)
{
var requiredKeys = ['key1', 'key2', 'key3'];
for(var keyPos = 0; keyPos < requiredKeys.length; keyPos++)
{
if(typeof(testObj[requiredKeys[keyPos]]) == 'undefined')
{
return false;
}
}
return true;
}
if(checkTheObj(theObj))
{
//do stuff
}
You can of course tweak this to return or throw an exception telling the first missing field (or use an internal array to return a list of all missing fields).
function objectHas(obj, properties) {
var len = properties.length
for (var i=0; i<len; i++) {
if (i in properties) {
if((!obj.hasOwnProperty(properties[i])) || (!obj.propertyIsEnumerable(properties[i]))) {
return false;
}
}
}
return true;
}
Usage:
if(objectHas(user, ["email", "password", "phone"])) {
console.log("awesome");
}
It's simple, but does the job.
Edit: On an ideal world you could extend the Object prototype for an even neater syntax such as if(object.has(["a", "b", "c"])), but apparently extending the Object prototype is the incarnation of evil so a function will have to do :)
First of all, you need to improve your understanding of these languages and learn the correct terminology.
There is no (single) language named "Javascript" at all. You are implicitly using several languages here (depending on the runtime environment), all of which are ECMAScript implementations, and one of which is Netscape/Mozilla JavaScript (in Mozilla-based software like Firefox).
An object does not have variables, it has properties (not: keys). Global code, function code, and eval code can have variables; that is a different (but similar) concept.
The function is not getting an object, it is being passed a reference to an object as argument.
As a programmer, you should already know that you can do repetitive tasks in a loop; the associated statements in ECMAScript implementations are for, for-in, while and do. So you do not have to write several if statements.
You can access the properties of an object in two ways, where property is the property name:
Dot notation: obj.property
Bracket notation: obj["property"]
The second one is equivalent to the first if the property name is an identifier, i.e. if it follows certain naming rules. If the property name is not an identifier or if it is variable, you have to use the second one. This also shows that all property names are string values. So you can store the name of a property as value of a variable or another property, and then access the variable or property in the property accessor. In the following, a property name (property) is stored in and used from a variable:
var propertyName = "property";
obj[propertyName]
Combining that with a loop allows you to iterate over certain properties of an object. Unfortunately, the solutions presented so far are flawed in two respects: A for-in statement iterates only over the enumerable properties of an object, and it does so in arbitrary order. In addition, it also iterates over the enumerable inherited properties (which is why one solution requires the hasOwnProperty() call).
A simple, sure and efficient way to iterate only over certain properties of an object in a defined order looks as follows:
var propertyNames = ['name1', 'name2', 'name3'];
for (var i = 0, len = propertyNames.length; i < len; ++i)
{
/* … */ myObject[propertyNames[i]] /* … */
}
This works because propertyNames refers to an Array instance, which encapsulates an array data structure. The elements of an array are the properties of the Array instance that have integer indexes from 0 to 65535 (232−1). Because indexes are not identifiers (they start with a decimal digit), you have to use the bracket property accessor syntax (some people misunderstand this and refer to all ECMAScript objects as "arrays", even call them "associative arrays" and […] the "Array operator"). Therefore, propertyNames[i] evaluates to the values of the elements of the array in each iteration as i is increased by 1 each time. As a result, myObject[propertyNames[i]] accesses the property with that name in each loop.
Now, to find out whether the property is set, you need to define what that means. Accessing a property that does not exist results in the undefined value (not in an error). However an existing property may also have the undefined value as its value.
If "not set" means that the object does not have the property (but may inherit it), then you should use hasOwnProperty() as used in Mahn's solution.
If "not set" means that the object does not have the property and does not inherit it, then you should use the in operator, provided that the object is not a host object (because the in operator is not specified for them):
if (propertyNames[i] in obj)
If "not set" means that the object either has or inherits the property, but the property has the undefined value, or the object neither has nor inherits the property, then you should use the typeof operator as used in Bob Davies' and aetaur's solutions (but the latter approach using Array.prototype.every() is less compatible as-is; that method was not specified before ECMAScript Edition 5, and is not available in IE/JScript < 9).
There is a third option with ECMAScript Edition 5.x, the Object.keys() method which (despite its name) returns a reference to an Array instance that holds the names of all not-inherited properties of the argument:
var propertyNames = Object.keys(obj);
/* continue as described above */
It is a good idea to emulate Object.keys() if it is not built-in, as this algorithm is frequently useful.
This expression returns true, if all variables from variableNameList (list of required variable names) set in object o:
variableNameList.every(function(varName){ return typeof o[varName] !== 'undefined'; });
You can use underscore _.all function instead of native every, and underscore _.isUndefined instead of typeof ....

Categories