This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 2 years ago.
I started to learn JavaScript, and I can not catch one thing.
myDog.name = "Happy Camper";
myDog["name"] = "Happy Camper";
and also
var myDog = {
"name" : "Coder",
"legs" : 4,
"tails" : 1,
"friends" : ["everything!]"
};
here in everything - what is the difference with and without brackets?
Thank you.
In JavaScript, [] is used to determine an Array literal, but is also one of the ways to call Object keys, hence your confusion.
const myArray = []; // Returns an empty array
const someObjectValue = myObject["myKey"] // returns the value of an object's key
Please note you can also fetch an object value by using dot instead of brackets:
// They are the same thing.
const value = myObject["myKey"];
const sameValue = myObject.myKey;
They're basically two different ways of achieving the same thing.
There is one difference, thought. With brackets you can assign otherwise non-allowed keys to objects.
Example:
const myObject = {};
// Set
myObject.0 = "Hello!"; // throws error
myObject[0] = "Hello!"; // works!
myObject.some-key = "Hello!"; // throws error
myObject["some-key"] = "Hello!"; // works!
// Get
const value = myObject.0; // throws error
const value = myObject[0]; // works!
const value = myObject.some-key; // throws error
const value = myObject["some-key"]; // works!
In the first case you are accessing data inside an object passing the key inside the brackets, in the second one using the brackets you are declaring an Array in javascript which is a list of data.
Checkout this definition of array:
Arrays are list-like objects whose prototype has methods to perform
traversal and mutation operations. Neither the length of a JavaScript
array nor the types of its elements are fixed
You could add more items into your array like:
var myDog = {
"name" : "Coder",
"legs" : 4,
"tails" : 1,
"friends" : [
"everything!",
"a little more",
"one more thing",
1,
"the previous element was a number",
"the next will be an object",
{name: "test"}
]
};
You can also access array data passing the key value inside brackets like objects but array keys are ordered numbers called index, for example.
const myArray = ["a", "b", "c"]
console.log(myArray[0]) // a
console.log(myArray[1]) // b
console.log(myArray[2]) // c
Click here for more info about arrays
Related
Sorry for misleading title here, I wasn't able to frame any proper one.
I am confused in array when there is nothing inside them (prints by empty X n) but they have length.
e.g. I create array by const a = [,,,]. This creates an array whose length is 3 but nothing inside it. If i print it in browser console, it prints the following:
What does empty mean here? If I run map or forEach function and try to console something, I get nothing.
Have added some code.
const a = [,,,]
console.log("print a: ",a)
console.log("print a.length: ",a.length)
console.log("print typeof a[0]: ", typeof a[0])
console.log("a.forEach((data, index) => { console.log(data, index) }): ", a.forEach((data, index) => { console.log(data, index) }))
console.log("")
const b = [undefined, undefined, undefined]
console.log("print b: ", b)
console.log("print b.length: ", b.length)
console.log("print typeof b[0]: ", typeof b[0])
console.log("b.forEach((data, index) => { console.log(data, index) }): ", b.forEach((data, index) => { console.log(data, index) }))
console.log("")
console.log("compare a[0] and b[0]: ", a[0] === b[0])
The only thing which differs is when I print a and b (though stackoverflow console prints them same but browser console prints differently) and when I try to loop through the array. Also momentjs isEqual gives them equal (jsfiddle here)
My main doubts are:
What type of array is it?
What does empty mean here?
How is it different from array which has all undefined values or empty array? or is it not?
Do we use it or any sample use case for this one
I have read about null and undefined array values and have understood it. But for this one, I haven't find anything proper. Most of the search I found were related to const a = [] is an empty array or how to check if array is empty and so on.
So, if someone can explain or give any proper links to read, it will be very helpful.
Please let me know, if I should add anything else.
Intro to sparse arrays
First a clarification what you've created is called a sparse array. To put it simply, sparse arrays are similar to normal arrays but not all of their indexes have data. In some cases, like JavaScript, this leads to slightly more significant handling of them. Other languages simply have a normal array of fixed length with some values that are "zero" in some sense (depends on what value can signify "nothing" for a specific array - might be 0 or null or "", etc).
Empty slots
The empty slot in a sparse array is exactly what it sounds like - slot that is not filled with data. JavaScript arrays unlike most other implementations, are not fixed size and can even have some indexes simply missing. For example:
const arr = []; // empty array
arr[0] = "hello"; // index 0 filled
arr[2] = "world"; // index 2 filled
You will get an array with no index 1. It's not null, nor it's empty, it's not there. This is the same behaviour you get when you have an object without a property:
const person = {foo: "hello"};
You have an object with a property foo but it doesn't have, for example, a bar property. Exactly the same as how the array before doesn't have index 1.
The only way JavaScript represents a "value not found" is with undefined, however that conflates
"the property exists and the value assigned to it is undefined"
"the property does not exist at all"
Here as an example:
const person1 = { name: "Alice", age: undefined };
const person2 = { name: "Bob" };
console.log("person1.age", person1.age);
console.log("person2.age", person2.age);
console.log("person1.hasOwnProperty('age')", person1.hasOwnProperty('age'));
console.log("person2.hasOwnProperty('age')", person2.hasOwnProperty('age'));
You get undefined when trying to resolve age in either case, however the reasons are different.
Since arrays in JavaScript are objects, you get the same behaviour:
const arr = []; // empty array
arr[0] = "hello"; // index 0 filled
arr[2] = "world"; // index 2 filled
console.log("arr[1]", arr[1]);
console.log("arr.hasOwnProperty(1)", arr.hasOwnProperty(1));
Why it matters
Sparse arrays get a different treatment in JavaScript. Namely, array methods that iterate the collection of items will only go through the filled slots and would omit the empty slots. Here is an example:
const sparseArray = []; // empty array
sparseArray[0] = "hello"; // index 0 filled
sparseArray[2] = "world"; // index 2 filled
const arr1 = sparseArray.map(word => word.toUpperCase());
console.log(arr1); //["HELLO", empty, "WORLD"]
const denseArray = []; // empty array
denseArray[0] = "hello"; // index 0 filled
denseArray[1] = undefined; // index 1 filled
denseArray[2] = "world"; // index 2 filled
const arr2 = denseArray.map(word => word.toUpperCase()); //error
console.log(arr2);
As you can see, iterating a sparse array is fine, but if you have an explicit undefined, in the array, then word => word.toUpperCase() will fail because word is undefined.
Sparse arrays are useful if you have numerically indexed data that you want to run .filter, .find, .map, .forEach and so on. Let's illustrate again:
//some collection of records indexed by ID
const people = [];
people[17] = { id: 17, name: "Alice", job: "accountant" , hasPet: true };
people[67] = { id: 67, name: "Bob" , job: "bank teller", hasPet: false };
people[3] = { id: 3 , name: "Carol", job: "clerk" , hasPet: false };
people[31] = { id: 31, name: "Dave" , job: "developer" , hasPet: true };
/* some code that fetches records */
const userChoice = 31;
console.log(people[userChoice]);
/* some code that transforms records */
people
.map(person => `Hi, I am ${person.name} and I am a ${person.job}.`)
.forEach(introduction => console.log(introduction));
/* different code that works with records */
const petOwners = people
.filter(person => person.hasPet)
.map(person => person.name);
console.log("Current pet owners:", petOwners)
its just what it is empty its neither undefined or null
const a = [,,,,] is same as const a = new Array(4)
here a is an array with no elements populated and with only length property
do this, let arr1 = new array() and then console.log(arr1.length) you'll get 0 as output. and if you do console.log(arr1) you'll get [ <4 empty items> ]
if you change the length property of arr1 like this arr1.length = 4 you will have an empty array with it's length property = 4, but no items are populated so those slot will be empty and if you do console.log(typeof(arr1[0]) you get undefined only because there is no other possible types to show. And no methods of Array will be applied with an array with empty elements
so,
Empty array means an array with length property and with unpopulated slots
this is different from arrays with undefined because in JS undefined is a type and you can execute and have results by calling all array methods on it, whereas an array with empty elememts have no type and no array methods can be applied on it.
i have a Question. I was thinking long Time about it, but poorly i donĀ“t find a answer.
I know the every method.
My Question is about this code section:
var tr = order.every((i) => stock[i[0]] >= i[1]);
My Questions are:
stock is an Object. Why i must write as an array?
Why it is i[0] in stock and then i[1] ?
Why this code checks the nested Arrays in const order ?
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6
};
var tr = order.every((i) => stock[i[0]] >= i[1]); /// return true
console.log(`tr:`,tr)
So, the square brackets can be used to access element inside the array by passing it's index e.g:
const arr = ["first", "second"];
const secondElement = arr[1] // index 1 means seconds element
and also square brackets can be used to access element inside the object by passing it's key e.g:
const obj = { first: 1, second: 2 };
const secondElement = object.second // Normal way to access value in object
const secondElementWithAnotherSyntax = object['second'] // another syntax, same thing
the cool thing about the other syntax shown is that you can pass variable to it, e.g :
const objKey = 'second'
const secondElement = obj[objKey]
Now let's look at your example, i is one element of the array order, which carries arrays itself, so i is also one of the two small arrays, i[0] is the string word in the beginning of the small arrays, so:
i[0] // is either 'shirt' or 'shoes'
and since stocks is an object that has those keys, you can access for example the value 50 by saying stocks['shirt'] or as in your case, stock[i[0]] ;)
now your second question: why should it be >= i[1] ?
because the order second item , aka i[1] is the number of items required/ordered, so this should always be less that your stock, you can't by 5 shirts from a place that has only 3 in the stock :)
1. stock is an Object. Why i must write as an array?
You can access properties of objects using brackets [].
Why do we need this?
To be able to access properties of objects dynamically, e.g. when you are looping though keys and want to get the values
Object.keys(data).forEach(function(key) {
console.log('Key : ' + key + ', Value : ' + data[key])
})
Sometimes there is no other way to access the value:
const json = {
"id":"1",
"some key with spaces": "48593"
};
console.log(json.some key with spaces); // obviously throws error
console.log(json['some key with spaces']); // prints "48593"
2. Why it is i[0] in stock and then i[1] ?
3. Why this code checks the nested Arrays in const order ?
The code goes through the orders, each order is an array so i[0] is the type of the order and i[1] is the quantity. the code checks if there are enough items in stock. To check if there are enough shirts you would do:
console.log(stock["shirts"] >= 5
Thats what the code in your example does, it just passes the key ("shirts") and quantity (5) dynamically.
May I suggest to try to use more expressive naming of the variables ?
An object property can be accessed through bracket notation, as in stock[orderedProductName] when using a variable - Property accessors
A concise but imho more readable version can be written using destructuring assignment
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6,
};
// original version
let inStock = order.every((i) => stock[i[0]] >= i[1]); /// return true
// more verbose version
// check if every item in array order satisfies the condition
// let's cycle over the array calling the element we're working on
// orderItem
inStock = order.every( orderItem => {
const orderedProductName = orderItem[0];
const orderedProductQuantity = orderItem[1];
// to access an object property we can use bracket notation
const stockProductQuantity = stock[orderedProductName];
// the condition to check: do we have enough products in stock ?
return stockProductQuantity >= orderedProductQuantity;
});
// a concise variation could make use of destructuring assignment.
// Here, when we take the order item array, we immediately assign
// each of its elements to the appropriate variable
//
// orderItem[0] or first array element -> productName
// orderItem[1] or second array element -> orderedQuantity
inStock = order.every(([productName, orderedQuantity]) =>
stock[productName] >= orderedQuantity
);
if(inStock) {
console.log('pack and ship');
}
else {
console.log('need to restock');
}
The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. If you want to read more Array.prototype.every()
In your code snippet you are checking that every item in order array has quantity less than the quantity available in stock.
To access the properties of a object you can use square notation also like arrays. To read more Bracket Notation
If you assigned more meaningful variables to the code you'd probably understand how this works better.
In one order (an array) we have two nested arrays. The first describes shirt/value, the other shoes/value. every is going to see if there is enough stock for both shirt and shoes by checking that the stockValue >= the items in the order.
When you every over the order array the callback for each iteration is one orderItem (['shirt', 5] first, then ['shoes', 2] for the second). We can assign the first element of each array to a variable called itemType, and the second to a variable called itemQty.
So when you see stock[i][0] we can translate that in the new code as stock[orderType] which is using bracket notation to locate the property value associated by that key in the stock object. We then check to see if that value >= than the itemQty.
const order=[["shirt",5],["shoes",2]],stock={shirt:50,height:172,mass:120,shoes:6};
const result = order.every(orderItem => {
const itemType = orderItem[0];
const itemQty = orderItem[1];
return stock[itemType] >= itemQty;
});
console.log(result);
I am following a tutorial on Youtube about importing data into existing todo list component in React.
If you look at the code below, at the const data object, there are two keys namely lists and listIds. There are two parts which I don't understand.
Why is the key "list-1" a string while the value {id: "list-1",title: "Todo",cards,}
is a normal object? I could not figure out this syntax. If it's JSON format, both key-value should be a in quotation marks.
Is the listIds: ["list-1"] just a normal key-value pair which has an array as its value? If so, why does it has the same name as the one from the initial lists keys? Is this a Destructuring method from ES6?. I just cannot understand the syntax.
const cards = [
{
id: "card-1",
title: "Learning how to cook",
},
{
id: "card-2",
title: "Making sandwich",
},
{
id: "card-3",
title: "Taking the trash out",
},
];
const data = {
lists: {
"list-1": {
id: "list-1",
title: "Todo",
cards,
},
},
listIds: ["list-1"],
};
export default data;
Because "list-1" contains a minus sign and that would be an error for an identifier name. It would be like trying to subtract 1 from "list" and use the expression as a key.
listIds : ["list-1"] is a normal JS key-value expression with a key to the left of : and an array with a single string value to the right.
Object data.lists looks like it contains various sub-objects, each having an ID and listIds is just an array containing all the keys in lists. In your example there is one sub-object and correspondingly, one key in listIds.
One more thing: In a JSON string, keys to the left of : must be in double quotes, however this is a Javascript object, and Javascript objects can have keys without double quotes as long as each key is formatted as a regular Javascript variable, as well as values to the right of : that many times cannot be represented in a JSON string, such as functions for example.
I just thought I'd add a little summary here about declaring key/value pairs in an object declaration. When you declare an object property as in:
let obj = {prop: value};
the left hand side of the property declaration is the property name. There are three possible syntaxes allowed for that:
Plain String - No Quotes
// no quotes - this is allowed when the property name
// doesn't contain any reserved characters
let obj = {prop: value};
Quoted String
// quotes - this is always allowed, but is required when the property name
// does contain reserved characters like a "-" such as your example of "list-1"
let obj = {"prop": value};
Brackets around a variable name
// computed property name. This is used when the property name you want to use
// is in a variable
let someVar = "prop";
let obj = {[someVar]: value};
All three of these options above create the exact same key/value pair in that object.
The right hand side of the prop: value pair can be any Javascript expression like these:
let obj = {prop: 3}; // a number
let obj = {prop: "foo"}; // a string
let obj = {prop: value}; // value from some variable
let obj = {prop: [1,2,3]}; // an array
let obj = {prop: resultFromCallingFunc()}; // the result from calling some function
let obj = {prop: {greeting: "hello"}}; // another object
let obj = {prop: 3 + 4}; // any expression
I have a huge object that contains the entire ESV Bible. I am trying to get a random book of the Bible whenever I press a button. Here is a small sample of the object.
var esvObject = {
"Genesis": {
"1": {}
"2": {}
"3": {}
},
"Exodus": {
"1": {}
"2": {}
"3": {}
}
}
Here is the code that I am using to get a random book.
var randNum = Math.floor(Math.random() * 66);
var randBook = esvObject[randNum];
var output = randBook;
I would expect this to work, but the output I always get is "undefined," where as I would like the output to be "Genesis" or "Exodus" etc. Getting the random number works, but if
randNum = 1
then
randBook = esvObject[1]
the output returns as "undefined" and I don't know why.
Well the reason you get undefined is that your object is of the structure:
let esvObject = {
bookName: {
1 : {}
}
}
Using bracket [] notation on a javascript object finds the matching key for the name and returns it's value. In your top level object (the one with bookNames for keys), you have to use a valid book name like Genesis. To do so, leverage the Object.keys function of javascript to get an array of all the keys in your object.
You can then use [] notation, which has a different semantic on arrays.
let books = Object.keys(esvObject); // ["Genesis", "Exodus", ...]
let randomKey = books[randNum] // this is an array, so index access works
let book = esvObject[randomKey] // matches on the bookname
And to tie it all together, esvObject["Genesis"][1] would have been valid because the object stored as "Genesis" has a property 1
You are generating random number. And then trying to pick property using that number.
But you object has properties Genesis and Exodus not 1 or 20 etc.
What you need to do is Object.getOwnPropertyNames(esvObject)
that will give you array of the property names. In this case ['Genesis', 'Exodus'] and then you need to pick random element from that array
It would not work because it does not know that the first book is named "Genesis".
To be able to use numbers from the random function you will need to use array from the keys of the object
var keys = esvObject.keys( obj );
randBookKey = keys[randNum]
randBook = esvObject[randBookKey]
esvObject (as you show it) does not have any integer keys. So you need to select a random (existing) key instead:
esvObject[Object.keys(esvObjects)[Math.floor(Math.random() * 66)]]
You're confusing accessing an array with accessing an object.
An array:
arr = ["genesis", "exodus"]
is accessed like this:
arr[0] // genesis
An object:
obj = { "genesis" : "foo", "exodus" : "bar"}
is accessed like this:
obj["genesis"] // foo
To achieve what you want to do, see Access non-numeric Object properties by index?
I have a function which reads Files from the file system and stores them into an array. Afterwards I want to add a key/value pair to that element. However, the forEach loop is not executed, because apparently there is no element in there.
readFilesFromDirectory(folder, elements, 'json', function(){
log(Object.keys(elements).length,0);
log(elements.length,0);
elements.forEach(function(elem){
elem["newKey"] = 1;
});
});
My log contains the following lines:
1
0
The first length method is working, the second is not.
I would like to know what I am doing wrong for the second function and how I can fix it.
Actually, my main objective is to add the new key. However, I do not know how to use some Object.keyValues(elements).forEach(function(elem){...} in my code. If you have a hint for that, this would also be nice.
I would really appreciate some insight here! :-)
The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
Object.keys returns an array whose elements are strings corresponding to the enumerable properties found directly upon object. The ordering of the properties is the same as that given by looping over the properties of the object manually.
var arr = ["a", "b", "c"];
alert(Object.keys(arr)); // will alert "0,1,2"
// array like object
var obj = { 0 : "a", 1 : "b", 2 : "c"};
alert(Object.keys(obj)); // will alert "0,1,2"
// array like object with random key ordering
var an_obj = { 100: "a", 2: "b", 7: "c"};
alert(Object.keys(an_obj)); // will alert "2, 7, 100"
// getFoo is property which isn't enumerable
var my_obj = Object.create({}, { getFoo : { value : function () { return this.foo } }});
my_obj.foo = 1;
alert(Object.keys(my_obj)); // will alert only foo