Map having keys as objects - javascript

The documentation on Map on mdn says
A Map's keys can be any value (including functions, objects, or any primitive).
Let's say we have
let a = new Map();
a.set({a: 1, b:3}, "Hello");
a.set({a: 1, b:3}, "World");
This produces a map with 2 elements instead of one.
How can I make the lookup of keys to be in terms of their values and not their ids?
Or alternatively, how can I make a Map where the key is a pair of unordered values?

The following is a workaround that will store things in the way you intend. Albeit, it does not use the Map class and the assigning function is not a method of any class.
set=function(a,o,v){a[[o.a,o.b].sort().join(",")]=v};
const a = {};
set(a,{a: 1, b:3}, "Hello");
set(a,{a: 3, b:1}, "World");
set(a,{a: 2, b:2}, "something else");
console.log(a)

First of all you need to understand that two object initialized with same values will never be equal to each other. Try running the following snippet.
Hence map creates two different elements with it.
var x = {a: 1, b:3};
var y = {a: 1, b:3};
var z = x;
console.log(x === y); // => false
console.log(x === z); // => true
Therefore, if you wish to group based on object as keys you will probably have to pass the objects as references as shown below:
let a = new Map();
let key = {a: 1, b:3};
a.set(key, "Hello");
a.set(key, "World");
console.log(a.get(key));
Alternatively instead of keeping track to references for each key, you can just stringify the object like so:
let a = new Map();
let key = JSON.stringify({a: 1, b:3});
a.set(key, "Hello");
a.set(key, "World");
console.log(a.get(key));

Related

set new value for array's value using destructure

i got two noob questions about destructure an array:
1st question: when destructuring an object, I can define a new value or a new key or both. On array, can I add a new value without add a new key?
const obj = {a: undefined, b:2};
const {a = 3, b} = obj;
console.log(a); // 3
I want to know if there is a version of this but with array instead.
2nd question: is it possible to do not provide a default value for objects? Considering that I think that it is not possible to change default values using destructure.
const obj = [1, {a: 1, b:2}, 3, 4];
const [, object, three, four] = obj;
console.log(object); //{a: 1, b:2}
In this example, object returns {a: 1, b:2} but I wanted it change the value instead. Is that possible?
thanks, regards.
You are confusing default values with mutation of values, and assignment of values to variables with mutation of objects. Below is a demo of the default value feature of destructuring, with comments to explain the behavior.
You will see here that in general, destructuring is not designed for mutation of objects, but for extraction of variables and values. And hopefully also get a feel for why it would be undesirable for mutation to be mixed in to it, even if it were possible.
const obj = [1, {a: 1, b:2, 99:'z'}, ,3, 4, {mutateme: 1}];
const [, {a=3,b=4,c=5}, object={a:7,b:7},three, four, object2] = obj;
// a prop has value=1, b has value=2, c is not defined use default value 5
console.log(a,b,c,object);
//object is empty use default value={a:7,b:7}
// obj is unchanged
console.log(obj)
// mutate object2={mutateme:1} by reference (like a pointer)
object2.mutateme=7
// {mutateme: 1=>7}
console.log(obj)
// example of how you could (sort of) mutate inside a destructuring statement
// computed property, obj[1]=obj[3]=99 returns 99,
// so extract property 99 to variable z and mutate object obj at index [1] and [3] to =99
// y will 99 now.
const [y1, {[obj[1]=obj[3]=99]:z},, y2 ] = obj
console.log(y1, z, y2)
// if something similar were built into destructuring syntax,
// can you imagine how confusing it could get, and cause of all kinds of unexpected behavior?

How do I load the values from one array, into another array, without changing the memory address of the array receiving the new values?

If I do this:
a = []
b = [1, 2, 3]
a = b
a will then refer to b
I want to copy all of the values in b into a without changing any memory address/references.
You could push the values without changing the reference from a or b.
var a = [],
b = [1, 2, 3];
a.push(...b);
If you want to populate a in-place, without ever discarding the initial array, then you can simply loop over b and add all the items in a:
var a = []
var b = [1, 2, 3]
var firstA = a; //get a initial element
b.forEach(function(item) {
this.push(item)
}, a);// <-- pass `a` as the `this` context
console.log("`a` is unchanged", a === firstA);
console.log("`a` is not `b`", a !== b);
console.log(a);
let a = b.map(x => x);
The .map() function will create a new array with values generated from the source elements via the passed-in callback function.
As noted in a comment
let a = b.slice();
is pretty much exactly the same.
Basically this saves you the step of
let a = [];
since one brand-new empty array is as good as another. However, if you really have your heart set on using the empty array explicitly initialized, you could use
b.forEach(x, i) { a[i] = x; });
A= b.slice(). It will create a shadow copy of element without changing original one. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

Javascript array referencing an array position (not an element)

UPDATE:
Many asked why not using [arr[0], arr[1]]. The problem is I have to pass this array to a method, which I don't have access Angular Material Table. And I don't want to call the method over and over again.
I already processed the arr array and I don't want to process pointer array to reflect the new data, which I already know where it is.
The Nina Scholz answer seems to solve the problem.
Is there a way to use "pointers" like C in Javascript?
What I want to do is:
I have an array with objects
const arr = [
{prop: 3},
{prop: 4},
];
And I want to have an array to point to the positions of this array
const pointer = [arr[0], arr[1]]; // I want pointer to point to be an array containing the first and second elements of arr
This will get a reference to the {prop: 3} and {prop: 4} objects, which is not what I want, because, if I do:
arr.splice(0, 0, {prop: 1}); // arr => [{prop:1},{prop:3},{prop:4}]
console.log(pointer); // [{prop: 3},{prop: 4}]
As you can see, pointer holds a reference to the objects {prop:3} and {prop:4}.
How can I achieve pointer to hold reference to the position 0 of the array, instead of the object stored in it? So, on this example, pointer => [{prop:1},{prop:3}]?
I can't call pointer = [arr[0], arr[1]] all the time because arr will change constantly and asynchronously.
Is there a "reactive" way to handle arrays?
If your pointers are always to the same array, you can simply store the indexes.
const pointer = [0, 1];
Then you would use:
console.log(pointer.map(ptr => arr[ptr]));
If your pointers can point to different arrays, you can make the elements of pointer be objects that contain references to the array along with their indexes.
const pointer = [{a: arr, i: 0}, {a: arr1, i: 1}];
console.log(pointer.map(({a, i}) => a[i]));
Interesting aside: several decades ago I used a C implementation for Symbolics Lisp Machines. This is basically how it represented C pointers.
You could use a getter function and return the element of the actual object.
const arr = [{ prop: 3 }, { prop: 4 }];
const pointer = [];
Object.defineProperty(pointer, 0, { get() { return arr[0]; } });
Object.defineProperty(pointer, 1, { get() { return arr[1]; } });
arr.splice(0, 0, { prop: 1 });
console.log(pointer);
You can use a Proxy (not supported by IE) with a get trap:
const arr = [{ prop: 3 }, { prop: 4 }];
const pointer = new Proxy([], {
get(target, prop, receiver) {
// if the prop is a string that can be converted to a number
// return the corresponding value from the arr
if(typeof prop === 'string' && !isNaN(Number(prop))) return arr[target[prop]];
return Reflect.get(target, prop, receiver);
}
});
pointer.push(0, 1);
console.log(pointer);
arr.splice(0, 0, { prop: 1 });
console.log(pointer);

Array destructuring in JavaScript

I have this code in my vue-js app:
methods: {
onSubmit() {
ApiService.post('auth/sign_in', {
email: this.email,
password: this.password,
})
.then((res) => {
saveHeaderToCookie(res.headers);
this.$router.push({ name: 'about' });
})
.catch((res) => {
this.message = res.response.data.errors[0];
this.msgStatus = true;
this.msgType = 'error';
});
},
}
While running Eslint I got an error saying "Use array destructuring" (prefer-destructuring) at this line:
this.message = res.response.data.errors[0];
What is array destructuring and how to do this? Please provide me a concept on this. I've researched it but could not figure it out.
Destucturing is using structure-like syntax on the left-hand-side of an assignment to assign elements of a structure on the right-hand-side to individual variables. For exampple,
let array = [1, 2, 3, 4];
let [first, _, third] = array;
destructures the array [1, 2, 3] and assigns individual elements to first and third (_ being a placeholder, making it skip the second element). Because LHS is shorter than RHS, 4 is also being ignored. It is equivalent to:
let first = array[0];
let third = array[2];
There is also an object destructuring assignment:
let object = {first: 1, second: 2, third: 3, some: 4};
let {first, third, fourth: some} = object;
which is equivalent to
let first = object.first;
let third = object.third;
let fourth = object.some;
Spread operator is also permitted:
let [first, ...rest] = [1, 2, 3];
would assign 1 to first, and [2, 3] to rest.
In your code, it says you could do this instead:
[this.message] = res.response.data.errors;
The documentation on prefer-destructuring lays out what it considers to be "correct".
U can rewrite that line as [this.message] = res.response.data.errors; and that es-lint error will go off. See this example for better understanding
var x = {
y: {
z: {
w: [3, 4]
}
}
};
function foo() {
[this.a] = x.y.z.w
console.log(this.a);
}
foo() // prints 3
For more information about array destructuring please see here
Always look things up on MDN if you want to find out about javascript things. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Array_destructuring
Here's a simple example of destructuring:
const [a, b] = ['a', 'b'];
Its a shorthand available since es6 that allows doing variable assignment in a more shorthand way.
The original way would be like:
const arr = ['a', 'b'];
const a = arr[0];
const b = arr[1];
And the es6 way would be like:
const arr = ['a', 'b'];
const [a, b] = arr;
Now in regards to the eslint error, I actually disagree with that one. Your code by itself should be fine. So you should file an issue on the Eslint github repo to ask about why that line is triggering the "prefer-destructuring" warning.
Beside of the given destructuring assignments, you could take an object destructuring for an array if you like to take certain elements, like the 11th and 15th element of an array.
In this case, you need to use the object property assignment pattern [YDKJS: ES6 & Beyond] with a new variable name, because you can not have variables as numbers.
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
{ 11: a, 15: b } = array;
console.log(a, b);
Destructuring is a method of extracting multiple values from data stored in (possibly nested) objects and Arrays. It can be used in locations that receive data or as the value of objects. We will go through some examples of how to use destructuring:
Array Destructuring
Array destructuring works for all iterable values
const iterable = ['a', 'b'];
const [x, y] = iterable;
// x = 'a'; y = 'b'
Destructuring helps with processing return values
const [all, year, month, day] =
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.exec('2999-12-31');
Object Destructuring
const obj = { first: 'Jane', last: 'Doe' };
const {first: f, last: l} = obj;
// f = 'Jane'; l = 'Doe'
// {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Jane'; last = 'Doe'
Examples of where to use Destructuring
// Variable declarations:
const [x] = ['a'];
let [x] = ['a'];
var [x] = ['a'];
// Assignments:
[x] = ['a'];
// Parameter definitions:
function f([x]) { ··· }
f(['a']);
// OR USE IT IN A FOR-OF loop
const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
console.log(index, element);
}
// Output:
// 0 a
// 1 b
Patterns for Destructuring
There are two parties involved in any destructuring
Destructuring Source: The data to be destructured for example the right side of a destructuring assignment.
Destructuring Target: The pattern used for destructuring. For example the left side of a destructuring assignment.
The destructuring target is either one of three patterns:
Assignment target: Usually an assignment target is a variable. But in destructuring assignment you have more options. (e.g. x)
Object pattern: The parts of an object pattern are properties, the property values are again patterns (recursively) (e.g. { first: «pattern», last: «pattern» } )
Array pattern: The parts of an Array pattern are elements, the elements are again patterns (e.g. [ «pattern», «pattern» ])
This means you can nest patterns, arbitrarily deeply:
const obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
const { a: [{foo: f}] } = obj; // f = 123
**How do patterns access the innards of values? **
Object patterns coerce destructuring sources to objects before accessing properties. That means that it works with primitive values. The coercion to object is performed using ToObject() which converts primitive values to wrapper objects and leaves objects untouched. Undefined or Null will throw a type error when encountered. Can use empty object pattern to check whether a value is coercible to an object as seen here:
({} = [true, false]); // OK, Arrays are coercible to objects
({} = 'abc'); // OK, strings are coercible to objects
({} = undefined); // TypeError
({} = null); // TypeError
Array destructuring uses an iterator to get to the elements of a source. Therefore, you can Array-destructure any value that is iterable.
Examples:
// Strings are iterable:
const [x,...y] = 'abc'; // x='a'; y=['b', 'c']
// set value indices
const [x,y] = new Set(['a', 'b']); // x='a'; y='b’;
A value is iterable if it has a method whose key is symbol.iterator that returns an object. Array-destructuring throws a TypeError if the value to be destructured isn't iterable
Example:
let x;
[x] = [true, false]; // OK, Arrays are iterable
[x] = 'abc'; // OK, strings are iterable
[x] = { * [Symbol.iterator]() { yield 1 } }; // OK, iterable
[x] = {}; // TypeError, empty objects are not iterable
[x] = undefined; // TypeError, not iterable
[x] = null; // TypeError, not iterable
// TypeError is thrown even before accessing elements of the iterable which means you can use empty Array pattern [] to check if value is iterable
[] = {}; // TypeError, empty objects are not iterable
[] = undefined; // TypeError, not iterable
[] = null; // TypeError, not iterable
Default values can be set
Default values can be set as a fallback
Example:
const [x=3, y] = []; // x = 3; y = undefined
Undefined triggers default values

Javascript: Using a pre-existent object values as keys os a new one

I created this object:
var keys = {A: 'a', B: 'b' };
Later I tried create this other object:
var values = {keys.A: 1, keys.B: 2};
However I got this in Firefox console:
SyntaxError: missing : after property id
Even when I tried:
var vals = {keys['A']: 1, keys['B']: 2}
I got the same error.
The only way to get a success is if I type this:
var vals= {};
vals[keys.A] = 1;
vals[keys.B] = 2;
So, my question is if there is a more elegant way (similar to the first try) to create an anonymous object using as keys the values from a pre-existent object.
Thanks,
Rafael Afonso
Yes, the more elegant way is to use ES6 syntax:
var values = {[keys.A]: 1, [keys.B]: 2};
The thing in brackets can be any expression, so run wild:
var values = { [createPropName() + "_prop"]: 42 }
This is called "computed (dynamic) property names". See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names.
try this
var keys = {A: 'a', B: 'b' },
foo = {};
for (key in keys) { foo[key] = keys[key] }
In an Object Initialiser, the property name must be one of:
IdentifierName
StringLiteral
NumericLiteral
You can do what you want in ES5 using an Object literal for the keys and an Array literal for the values:
var keys = {A: 'a', B: 'b' };
var values = [1, 2];
var obj = {};
Object.keys(keys).forEach(function(v, i) {
obj[v] = values[i];
});
console.log(JSON.stringify(obj)) // {"A":1,"B":2}
However, that isn't reliable because the object properties may not be returned in the order you expect, so you might get:
{"B":1,"A":2};
To do what you want in ES5 and guarantee the order, an array of keys and an array of values is required, so something like:
var keys = ['a', 'b', 'c'];
var values = [1, 2, 3];
var obj = {};
keys.forEach(function(v, i) {obj[v] = values[i]});
console.log(JSON.stringify(obj)) // {"a":1, "b":2, "c":3}

Categories