Problem pushing a value inside an array located in an object key - javascript

Suppose I have the following function:
const createMenu = () => {
const obj = {
consumption: [],
};
return obj;
};
This is a function that, when called, returns the object
{ consumption: [] }
What I am trying to do is create a key inside that object that is a function that, when called with a string parameter, it pushes the string into the array inside the key 'consumption';
Here's my attempt:
const createMenu = () => {
const obj = {
consumption: [],
};
let order = (item) => {obj.consumption.push(item); };
obj.order = order;
return obj;
};
The expected result is that, when calling that function inside the object with a string parameter,like this:
createMenu().order('pizza');
when I run:
console.log(createMenu().consumption);
my result is:
['pizza']
but it is not working. I would appreciate if anyone could help me with this.
const createMenu = () => {
const obj = {
consumption: [],
};
let order = (item) => {
obj.consumption.push(item);
};
obj.order = order;
return obj;
};
createMenu().order('pizza');
console.log(createMenu().consumption);

You creating two instance of createMenu,
Your likely wanting to create 1
const menu = createMenu()
Also if you want to chain the functions, you will want to return the obj again inside order.
Below is an example..
const createMenu = () => {
const obj = {
consumption: [],
};
let order = (item) => {
obj.consumption.push(item);
return obj;
};
obj.order = order;
return obj;
};
const menu = createMenu().order('pizza');
console.log(menu.consumption);

You have to store the object created by createMenu() to a variable then perform operations to that variable. The update below should work.
In your code, you've created a new object when called the createMenu() function at the console.log. Which is not what you are wanting.
const createMenu = () => {
const obj = {
consumption: [],
};
let order = (item) => {
obj.consumption.push(item);
};
obj.order = order;
return obj;
};
const menu = createMenu();
menu.order('pizza');
menu.order('burger');
console.log(menu.consumption); // ["pizza", "burger"]
.as-console-wrapper{min-height: 100% !important; top: 0}

You may want to consider a class for this. Set up the array in the constructor, add a method to update the array when a new menu item is introduced, and have a final method that returns your desired object.
class CreateMenu {
constructor() {
this.consumption = [];
};
orderItem(item) {
this.consumption.push(item);
return this;
}
getList() {
return { consumption: this.consumption };
}
};
const menu = new CreateMenu();
const order = menu
.orderItem('pizza')
.orderItem('cheese sticks')
.getList();
console.log(order);

Related

DRY combine two functions in one [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I am trying to refactor my code and have noticed I am repeating myself. Was wondering if there is a way to combine these two functions in one?
export const fn1 = article => article.categoryValueDtoSet.reduce((res, item) => {
const result = { ...res };
if (item.language) {
const language = item.language.languageValue;
const category = item.categoryValue;
result[language] = category;
}
return result;
}, { it: undefined, de: undefined, en: undefined );
export const fn2 = article => article.titleDtoSet.reduce((res, item) => {
const result = { ...res };
if (item.language) {
const language = item.language.languageValue;
const category = item.titleValue;
result[language] = title;
}
return result;
}, { it: undefined, de: undefined, en: undefined );
First you would need function which you will pass to the reduce function as a callback. For this you can use a higher-order function which is basically a function that returns a function. We can call this function dry
const dry = (fieldName) => (res, item) => {
const result = { ...res };
if (item.language) {
const language = item.language.languageValue;
result[language] = item[fieldName];
}
return result;
}
then we can extract the initial object that is being passed to the reduce callback:
const intialValueObject = { it: undefined, de: undefined, en: undefined };
and then pass the dry function to the reduce function as an argument:
export const fn1 = article => article.categoryValueDtoSet.reduce(dry('categoryValue'), { ...initialValueObject });
export const fn2 = article => article.titleDtoSet.reduce(dry('titleValue'), { ...intialValueObject });
There is pretty much always a way. Could you be more specific with your constraints?
If nothing else, you can share the reduce logic
let reducer = (res, item) => {
const result = { ...res };
if (item.language) {
const language = item.language.languageValue;
const category = item.categoryValue;
result[language] = category;
}
return result;
}
export const fn1 = article => article.categoryValueDtoSet.reduce(reducer, { it: undefined, de: undefined, en: undefined });
export const fn2 = article => article.titleDtoSet.reduce(reducer, { it: undefined, de: undefined, en: undefined });
Most straightforward and simple, albeit with bad naming because I don't know what all this represents:
function reduceIt(it) {
return it.reduce((res, item) => {
const result = { ...res };
if (item.language) {
const language = item.language.languageValue;
const category = item.categoryValue;
result[language] = category;
}
return result;
}, { it: undefined, de: undefined, en: undefined });
}
export const fn1 = article => reduceIt(article.categoryValueDtoSet);
export const fn2 = article => reduceIt(article.titleDtoSet);

How to mock localStorage that works with Object.keys(localStorage)?

I am able to mock the basic localStorage in jest test like this:
// localStorage.js
export default new class {
store = {};
setItem = (key, val) => (this.store[key] = val);
getItem = key => this.store[key];
removeItem = key => { delete this.store[key]; };
clear = () => (this.store = {});
}();
// xxx.test.js
import localStorage from './localStorage';
window.localStorage = localStorage;
However, it won't work for mocking something like Object.keys(localStorage), which is supposed to return the keys in the localStorage in an array. Please help.
Thank you.
You can use JavaScript Proxy object to achieve Object.keys() ability.
E.g.
index.js:
class FakeLocalStorage {
store = {};
setItem = (key, val) => (this.store[key] = val);
getItem = (key) => this.store[key];
removeItem = (key) => {
delete this.store[key];
};
clear = () => (this.store = {});
}
let fakeLocalStorage = new FakeLocalStorage();
fakeLocalStorage = new Proxy(fakeLocalStorage, {
ownKeys: (target) => {
return Object.keys(target.store);
},
getOwnPropertyDescriptor(k) {
return {
enumerable: true,
configurable: true,
};
},
});
(async function test() {
fakeLocalStorage.setItem('name', 'TS');
fakeLocalStorage.setItem('age', 23);
const keys = Object.keys(fakeLocalStorage);
console.log('keys:', keys);
})();
The execution results:
keys: [ 'name', 'age' ]
When you have Object.keys(localStorage) to iterate through all available keys you can use spying instead of mocking using the following approach. Make sure you call mockRestore afterwards (not mockReset), or other tests that use local storage may fail.
The tested code:
const someFunction = () => {
const localStorageKeys = Object.keys(localStorage)
console.log('localStorageKeys', localStorageKeys)
localStorage.removeItem('whatever')
}
The test:
describe('someFunction', () => {
it('should remove some item from the local storage', () => {
const _localStorage = {
foo: 'bar', fizz: 'buzz'
}
Object.setPrototypeOf(_localStorage, {
removeItem: jest.fn()
})
const mock = jest.spyOn(global, 'localStorage', 'get')
try {
mock.mockReturnValue(_localStorage)
someFunction()
expect(_localStorage.removeItem).toHaveBeenCalledTimes(1)
expect(_localStorage.removeItem).toHaveBeenCalledWith('whatever')
} finally {
mock.mockRestore()
}
})
})

How to call a function from a nested object?

I have an object called obj that has a nested object comments and a function startMatch that returns an object like this:
var obj = {};
obj.comments = {
startMatch: function(matchStrings, isCaseSensitive) {
return {
subscribe: function(delegate) {
delegate('test')
const unsubscribe = () => {
console.log("unsubscribed");
};
}
};
}
};
var subscription = obj.comments.startMatch([], false).subscribe(function(result) {
console.log(result)
});
I would like to make this in such a way that I could call the unsubscribe function like this:
subscription.unsubscribe();
But I can't figure out how to do it without getting the unsubscribe undefined error.
Choose the simplest way:
var obj = {};
obj.comments = {
startMatch: function(matchStrings, isCaseSensitive) {
return {
subscribe: function(delegate) {
delegate('test');
return { unsubscribe: () => console.log("unsubscribed") }
}
};
}
};
var subscription = obj.comments.startMatch([], false).subscribe(function(result) {
console.log(result)
});
subscription.unsubscribe();

Dynamically set multiple object properties using variable

I wanna set multiple object property with the same value.
const SHOW_PAYMENT_DIALOG = 'SHOW_PAYMENT_DIALOG';
const SHOW_BUSINESS_DIALOG = 'SHOW_BUSINESS_DIALOG';
const handler = (state, payload) => {
return {
...state,
data: payload
};
};
const object = {
[SHOW_BUSINESS_DIALOG]: handler,
[SHOW_PAYMENT_DIALOG]: handler,
};
As above example, I have to manually assign handler for 2 property SHOW_BUSINESS_DIALOG & SHOW_PAYMENT_DIALOG
Is there anyway to set it quickly on the fly by js api but no need to introduce a new function to handle that like
const object = {
[SHOW_BUSINESS_DIALOG, SHOW_PAYMENT_DIALOG]: handler,
};
You could use Object.fromEntries() with .map() if you're okay with having the same reference to handler for each value... (the snippet console output shows how the handler method is the same reference for each value, that's why it looks a little strange):
const SHOW_PAYMENT_DIALOG = 'SHOW_PAYMENT_DIALOG';
const SHOW_BUSINESS_DIALOG = 'SHOW_BUSINESS_DIALOG';
const handler = (state, payload) => {
return {
...state,
data: payload
};
};
const keys = [SHOW_PAYMENT_DIALOG, SHOW_BUSINESS_DIALOG];
const object = Object.fromEntries(keys.map(k => [k, handler]));
console.log(object);
Please note that .fromEntries() is currently in draft mode, however, I think a generic if statement accompanied with a Set (using .has()) would be better for this case than using an object:
const SHOW_PAYMENT_DIALOG = 'SHOW_PAYMENT_DIALOG';
const SHOW_BUSINESS_DIALOG = 'SHOW_BUSINESS_DIALOG';
const handler = (state, payload) => {
return {
...state,
data: payload
};
};
const get_handler = key => {
const keys = new Set([SHOW_PAYMENT_DIALOG, SHOW_BUSINESS_DIALOG]);
if(keys.has(key))
return handler;
}
console.log(get_handler(SHOW_BUSINESS_DIALOG)); // hanlder
console.log(get_handler("foo")); // undefined
You can create a generic function and pass an array of key and loop through keyArr and place value for each key
const SHOW_PAYMENT_DIALOG = 'SHOW_PAYMENT_DIALOG';
const SHOW_BUSINESS_DIALOG = 'SHOW_BUSINESS_DIALOG';
let value = "some value"
const object = { someKey: 'value'};
let dynamicSetValues = (keyArr, value) => {
keyArr.forEach(key => {
object[key] = value
})
}
dynamicSetValues(['SHOW_PAYMENT_DIALOG','SHOW_BUSINESS_DIALOG'], value)
console.log(object)
Note:- this mutates original object, if you want immutability you can make a copy of object and place value on desired keys and return a new object every time from function

How to make Object.assign work?

Background
I am trying to extend the functionality of an old object via Object.assign, by passing in a new object with an additional feature.
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
const test = () => {
printLog(); //fails here!
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();
Problem
My mix object fails execution, even though it has bot printLog and test methods:
Object {printLog: function, test: function}
Question
How can I fix my code so that the test function will work as expected?
In order to access printLog, you have to access it through this. However, your function test cannot be an arrow function because arrow functions use the this context of the context they're defined in, so to get the result you want, change printLog() into this.printLog() and switch test from an arrow function to a regular function:
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
const test = function() {
this.printLog(); //fails here!
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();
edit: Change your code to this:
const oldObj = () => {
const printLog = () => console.log("hello");
return {printLog};
};
const newObj = () => {
function test() {
this.printLog();
console.log("world");
};
return {test};
};
const mix = Object.assign(oldObj(), newObj());
mix.printLog();
mix.test();

Categories