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")
Related
I am new to the typescript, and trying to learn the language
Below I have 2 objects I want to understand what is difference between them, they are definitely different as nothing is printed on console.
Code
let some = {'flag' : {copy : 'true'}};
let other = {'flag' : {"copy" : 'true'}};
if(some === other)
console.log("Same")
(Other variable have copy in quotes)
Also if I hover on to the "copy" attribute, IDE is showing string property in both cases.
let some = {'flag' : {copy : 'true'}};
let other = {'flag' : {"copy" : 'true'}};
Your two objects, some and other are basically the same, but object comparison in JS will always return false. This is because the variables are not storing the objects, it's storing a reference to the object. This means that even if the objects have the same structure and the same values for every key, any equality comparison with both == and === will be false. The exception is when you're comparing the same object to itself, ie some === some is true(as it should be).
You can read more about it here
As for your question about quotes around keys, that is the proper syntax for JSON objects. By that I mean, if you're writing something that will be parsed as JSON, then you should use double quotes around all your keys. If it's in JS, you can omit the quotes, in fact, prettier will usually remove the quotes even if you type them. In JS, both the objects above are functionally exactly the same.
One place you will need to use quotes is when your object keys have symbols like -, +, spaces, etc.
const obj = {
"key with spaces": "value",
"Jan-Dec": "123"
}
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.
This question sparked when I was setting the base case of the following code:
function withoutReverse(str, arrayFor = []){
arrayFor.unshift(str[0]);
if (str.length === 1)
return arrayFor.join("");
else return withoutReverse(str.slice(1), arrayFor) }
let hola = "hello";
withoutReverse(hola);//-->olleh
I thought that the base should be str.length === 0, cause I assumed that unshift literally took each element from the source object to put it into arrayFor. Then, I realized that that was what I was using slice for.
I didn't found a conclusive information in mdn. Am I right? unshift() doesn't really take those values (when stored in an object)? if so, how is that handled in memory?
Thank you
When you get to the 5th call:
console.log(str) // "o"
arrayFor.unshift(str[0]); // str[0] === "o"
console.log(str.length) // "1" because accessing the property here does not change it.
Therefore your exit condition is now true.
For functions in JS:
numbers/strings/booleans are passed as values
arrays/objects are passed as references
Extra info about strings:
Unlike some programming languages (such as C), JavaScript strings are immutable. This means that once a string is created, it is not possible to modify it.
Source MDN
return 'cat'[1] // returns "a"
When using bracket notation for character access, attempting to delete or assign a value to these properties will not succeed. The properties involved are neither
writable nor configurable. (See Object.defineProperty() for more information.)
Source MDN
If I declare the following in my Chrome console:
var object = {0:0, 1:1}
I can call object[0] and object[1] and get their values. I can also call object["0"] and object["1"]. Next, if I declare:
var object = {"0":0, "1":1}
I can also make all four of the above calls. But if I declare:
var object = {a:0, 1:1}
I get a ReferenceError of "a is not defined" when I call object[a], but object["a"] returns 0, even though the property name in the declaration is not a string. I guess JavaScript thinks I'm calling a variable that doesn't exist in the first example. But why do calling object[0] and object["0"] both work? It seems that JavaScript is doing some kind of automatic conversion for numbers (presumably since they can't be variable names), but what are the rules for this? And is this behavior universal to other places it might come up or just to the bracket notation for objects?
When you use brackets, the expression inside the brackets is evaluated. What's the value of the expression
a
?? Well, if "a" isn't a declared variable, it's nonsense. When you use . notation, the identifier (and it must be an identifier) following the operator is treated as a string. It's just the way the language works.
The reason you're getting a ReferenceError for object[a] is because a literal a is a variable in javascript. "a" is a string containing the letter a.
You can use the dot notation object.a or the bracket notation with object["a"]
object.a; //=> 0
object["a"]; //=> 0
object[1]; //=> 1
object["1"]; //=> 1
Or you can use a variable for access
var x = "a";
object[x]; //=> 0
var y = 1;
object[y]; //=> 1
You are correct.
a there is a token which the engine assumes is a variable.
If you type "a" JS knows it's a string-primitive.
If you type 0, JS knows it's a number-primitive.
So on top of obj.a, obj["a"], obj[0], obj["0"], you can also say:
var a = 0;
obj[a]; // 0
Your app is exploding, because a hasn't been defined yet, and now you want to use it.
And yes, this is the expected behaviour.
What's inside of the brackets isn't seen as a "part" of the object -- it's a way of saying "give me the value of the object which is referenced by this key", where the key might be a number or string (or something that can be coerced into a string or number).
In the future, with maps and weakmaps, you would actually be able to use other objects/functions as keys as well.
var obj = new Map(),
func = function () { },
el = document.getElementById("myId");
obj[func] = 1;
obj[el] = 2;
Right now, these things technically work... ...but only because they're converted to their string values... ...so if you had two functions which were written the same (but technically two different objects), you would overwrite values, currently.
Inside of a map, they'd be treated as separate objects.
Using DOM elements is even worse, right now, as it might be useful to store hundreds of those and bind references to them, so that you don't have to keep looking for them... ...but for now, you need to make a unique ID number/key for each one, and store that, and remember the keys, and then create a child object to hold the data you want...
Whereas in the future, with maps, you could say:
var my_els = document.querySelector(".lots-of-els");
for (let el of my_els /* also the future */) {
console.log( my_map_of_data[el].info );
}
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/