const arr = ["a","b","c"]
arr.map(obj => {obj.id: obj})
I expect arr can become [{id:"a"},{id:"b"},{id:"c"}] but I got error at obj.id within my map, what's my mistake?
You could use parenthesis for the return object and just the variable id, which resolves to an object with the key id.
let arr = ["a", "b", "c"],
result = arr.map(id => ({ id }));
console.log(result);
From MDN Returning object literals:
Returning object literals
Keep in mind that returning object literals using the concise syntax params => {object:literal} will not work as expected.
var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
This is because the code inside braces ({}) is parsed as a sequence of statements (i.e. foo is treated like a label, not a key in an object literal).
Remember to wrap the object literal in parentheses.
var func = () => ({foo: 1});
you should use extra parenthesis when returning object. so your code will be
const arr = ["a", "b", "c"]
const a = arr.map((obj, i) => ({
[i]: obj
}))
console.log(a)
Related
I found here a script. It works fine. But now, I want to use a Variable instead of single values.
Here the original script:
const customData = {
"func":"bri",
"oid":"ID",
"onVal":1,
"offVal":0,
"...":"..."
}
const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const Light.bri = getSubset(customData, "oid", "onVal", "offVal");
Result (OK):
bri: {
offVal: 0,
oid: "objekt-ID",
onVal: 1
},
Now I want to do define the keys in a variable, ideally as a object. But this do not work.
const params = {bri: "oid, onVal, offVal"};
const Light.bri = getSubset(customData, params.bri);
Result (NOK):
bri: {
oid, onVal, offVal: undefined
},
description: "Deckenspots"
}
what changes do I have to make?
Define the bri property as an array of strings. That way you can use the spread syntax (...) to pass the strings as individual arguments.
const params = {bri: ["oid", "onVal", "offVal"]}; // bri is now an array.
const Light.bri = getSubset(customData, ...params.bri); // Notice the ... before params.bri
I am trying to find the best way to check whether an object key is present inside multiple objects present in an array which will provide a boolean as output
[{alert:hi},{alert:bye},{}]
From the above example basically what I am trying to achieve is if any one object is missing the alert object key the output should be as false or anything
You can iterate your array with every(). Something like this:
const objects = [{alert:'hi'},{alert:'bye'},{}];
const every = objects.every(obj => obj.hasOwnProperty('alert'));
console.log(every);
You can use the Array#some method and check if at least one element is undefined
const isAlertMissing = (array) => array.some(elem => elem.alert === undefined)
const objs1 = [{alert: "foo"},{alert: "foo"},{}]
const objs2 = [{alert: "foo"},{alert: "foo"}]
console.log(isAlertMissing(objs1))
console.log(isAlertMissing(objs2))
You can use every to check all items and some with Object.keys for finding a key in the inner objects.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => Object.keys(item).some(key => key === "alert"));
console.log(result) //false
EDIT
some with Object.keys is kind of roundabout, so we can use hasOwnProperty instead.
const data = [{alert:"hi"},{alert:"bye"},{}]
const result = data.every(item => item.hasOwnProperty("alert"));
console.log(result) //false
Array#some will succeed as soon a match is found, making it more efficient than Array#every.
const test = (data, propName) =>
!(data.some((el) => !el.hasOwnProperty(propName)))
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true
Or:
const test = (data, propName) => {
for(let el of data) {
if(!el.hasOwnProperty(propName))
return false
}
return true
}
const data1 = [ {alert:'hi'}, {alert:'bye'}, {}]
const data2 = [ {alert:'hi'}, {alert:'bye'}]
console.log(test(data1, 'alert')) // false
console.log(test(data2, 'alert')) // true
I have the following:
const a = (...args) =>{ return {...args}}
const abc = a('lol', 'rofl', 'lmao');
console.log('abc', abc);
However, this prints out
Object {0: "lol", 1: "rofl", 2: "lmao"}
But I expected
Object {lol: "lol", rofl: "rofl", lmao: "lmao"}
since
{lol, rofl, lmao}
produces the line above.
Is there a way to spread the arguments so that I can get this result?
I don't think that there is any build in method to do that, the spread syntax will not work as you expected. Anyway, you can use Array#reduce method.
const a = (...args) => args.reduce((obj, v) => (obj[v] = v, obj), {})
const abc = a('lol', 'rofl', 'lmao');
console.log('abc', abc);
You could use Object.assign and computed properties.
const a = (...args) => args.reduce((obj, v) => Object.assign(obj, { [v]: v }), {});
const abc = a('lol', 'rofl', 'lmao');
console.log('abc', abc);
You may do as follows;
function F(...args){
args.forEach(a => this[a] = a, this);
}
var abc = new F('lol', 'rofl', 'lmao');
console.log('abc', abc);
In javascript programming in the functional way is a great benefit. I'm trying to modify a property of an object contained in an array of objects in the functional way that means that the item that is the object passed in the map function cannot be modified. If I do something like this:
const modObjects = objects.map((item) => {
item.foo = "foo" + 3;
return item;
});
this is not functional because item is modified inside the function. do you know any other approach to this problem?
A new (ES6) way that is really immutable and in the spirit of functional programming:
// A. Map function that sets obj[prop] to a fixed value
const propSet = prop => value => obj => ({...obj, [prop]: value})
// B. Map function that modifies obj.foo2 only if it exists
const foo2Modify = obj =>
obj.hasOwnProperty('foo2') ? {...obj, foo2: 'foo ' + obj.foo2} : obj
// Usage examples of A and B
const initialData = [{'foo': 'one'}, {'foo2': 'two'}, {'foo3': 'three'}]
const newData1 = initialData.map(propSet('foo2')('bar')) // Set value
const newData2 = initialData.map(foo2Modify) // Use a modify function
console.log(initialData) // Initial data should not change
console.log(newData1) // Each object should contain the new fixed foo2
console.log(newData2) // Modify foo2 only if it exists in initial data
You could use Object.assign to create a copy of the item obj and return that from the map callback.
Object.assign()
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Here is an example
let data = [
{"foo": "one"},
{"foo": "two"},
{"foo": "three"}
]
let newData = data.map( item => {
let itemCopy = Object.assign({}, item);
itemCopy.foo = "foo " + item.foo;
return itemCopy;
})
console.log(data)
console.log(newData)
You can also do it like this:
const modObjects = objects.map((item) => {
return { ...objects, foo: "foo" + 3; };
});
The reason that this: objects.map((item) => { ...destSchema, foo: "foo" + 3; }); doesn't work is that they made it this way to make the JS interpreter understand whether it is a scope or an object. You MUST use return
In modern JavaScript you can use spread operator on object inside of an object literal for this:
const modObjects = objects.map(
item => ({...item, foo: item.foo + 3})
)
Notice parentheses () around object literal. They are needed to disambiguate object literal {} from code block {} in lambdas. Another way is to use code block with return:
const modObjects = objects.map(
item => { return {...item, foo: item.foo + 3} }
)
I have extended #Dimitrios Tsalkakis answer to change property with a callback function.
Example: https://repl.it/#robie2011/ts-set-property-functional
Typescript:
function mapProperty<T>(prop: string){
return (cb: (propValue: any) => any) => (obj: any) => ({...obj, [prop]: cb(obj[prop])}) as (T)
}
For example, can I do this?:
{
a: b: c: d: 1,
e: 2,
geh: function() { alert("Hi!") }
}
EDIT:
Is there some way I can avoid doing this?:
{
a: 1,
b: 1,
c: 1,
d: 1,
e: 2,
geh: function() { alert("Hi!") }
}
An update to this (in terms of the latest JavaScript abilities) avoiding unwanted defined vars:
{
let v;
var obj = {
"a": (v = 'some value'),
"b": v,
"c": v
};
}
This will mean v won't be defined outside the block, but obj will be.
Original answer
Another way of doing the same thing is:
var v;
var obj = {
"a": (v = 'some value'),
"b": v,
"c": v
};
You could set a line of equality between various properties:
var foo = {};
foo.a = foo.b = foo.c = "Hello";
Or you could just create a method that does the mass-assignment for you:
var foo = {
setValue: function( props, value ) {
while ( props.length ) this[ props.pop() ] = value;
}
}
foo.setValue( [ "a", "b", "c" ] , "Foo" );
You could try this. It's not the syntactic sugar you're looking for (eg. {a,b,c:1, d:2}) but it's another way to do it, although all of these answers are pretty much fine.
(object,fields,value)=>Object.assign(object||{}, ...fields.map(f=>({[f]:value}) ))
Explanation:
(object,fields,value)=>
Takes an object (or falsey value if you want a new object, feel free to rearrange the argument order)
Object.assign(object||{},
Will return an object based on object and it will mutate the object. To disable this, simply add a first argument object literal like this Object.assign({}, object || {}, ...
...fields.map(f=>({[f]:value}) )
Will spread the array of fields mapped to objects as a list of extra arguments to Object.assign. ['a','b'].map(f=>({[f]:value}) ) will give [{a:value}, {b:value}] and f(...[{a:1},{b:1}]) is like f({a:1},{b:1}). Object.assign does the rest :)
There's yet another approach: using a mapping function...
// This will be standard!
if (!Object.fromEntries)
Object.fromEntries = entries => entries.reduce ((o, [key, value]) => ({
...o,
[key]: value
}), {})
const setSameValue = (source, props, value) => ({
...source,
...Object.fromEntries (
props.map (prop => [prop, value])
)
})
// The important part: do what you want with ease!
const output = setSameValue ({}, ['1', '01'], 'string 1')
const obj = { x: 1, y: 'hello' }
const output2 = setSameValue (obj, ['1', '01'], 'string1')
console.log ('output1:', output)
console.log ('output2:', output2)
You could wrap in a closure too, if you didn't want multiple local vars. This syntax seems to be popular (but ugly):
var obj = (function() { var v='some value'; return { a:v, b:v, c:v }; })();
Use for of loop instead.
for (let [key, value] of Object.entries(object_name)) {
object_name[key] = 0; // the value that you want to assign
}
Or yet another way:
{...['a', 'b', 'c', 'd'].reduce((obj,prop)=>({...obj, [prop]: 1}), {}) }
It can be wrapped up pretty neatly by extending the Array prototype:
Array.prototype.ditto = function(v) { return this.reduce((o,p)=>({...o, [p]: v}), {}) }
So now it can be used like this:
{
...['a', 'b', 'c', 'd'].ditto(1),
...['e', 'f'].ditto(2)
geh: function() { alert("Hi!") }
}
Explanation: the .reduce starts off with an empty object {} and for each element prop return an object which is whatever was in the object already ...obj plus a new property with our value 1: [prop]: 1. Then expand these properties into the outer object with the ... at the start.
If you had tons of properties reduce wouldn't be the most efficient, but you could change it to:
Array.prototype.ditto = function(v) { let o = {}; this.forEach(p => o[p] = v); return o; }
More readable and more efficient but less cool??