1

I have a challenge to create a simple Notes manager in JS, I've written a function that takes one string, gives it and id and pushes it to an array of notes.

let nextId = 0;
const getId = () => nextId++;
let notes = [{id: getId(), value: 'Note'}];

const addNote = (input) => {
notes.push({id:getId(), value: input});
console.log('Note added');

I now struggle with a function that will take multiple strings as parameters

('own', 'snail', 'platypus')

create an object for each element with id/value(string) and push it to the main array.

The result should look like:

[{ id: 1, value: 'owl'},
 { id: 2, value: 'snail'}]

So far I have this, it assigns ID correctly, but the loop fails

const batchAddNotes = (values) => {
let obj = {};
for (i = 0; i < values.length; i++) {
    obj.id = (getId());
    obj.value = (values[i]);}
return obj;};
2
  • 2
    Have you tried using the functions arguments object? It's an array of all the arguments that are being passed to a function. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jul 5, 2018 at 14:12
  • just replace (values) => { with (...values) => { Commented Jul 5, 2018 at 14:20

6 Answers 6

1

To have your variables in a certain scope, I'd pack it all in a class (or a function). As you're using arrow functions, the class should be ok. To add multiple nodes the way you've shown; using var-args, you can create a method that expects those with (...input)

class Notes {
  constructor() {
    this.nextId = 0;
    this.nodes = [{
      id: this.getId(),
      value: 'Note'
    }];
  }

  addNote(input) {
    this.nodes.push({
      id: this.getId(),
      value: input
    })
  }

  getId() {
    return this.nextId++;
  }

  addNotes(...input) {
    input.forEach(e => this.addNote(e));
  }
}

const notes = new Notes();
notes.addNotes('own', 'snail', 'platypus');
console.log(notes.nodes);

Sign up to request clarification or add additional context in comments.

5 Comments

Why do you go for a OOP solution for a clearly "functional" example ? OOP is most of the time kinda Overengineering IMHO.
One reason is that your code will likely break should he come to the idea to use nextId anywhere else in his code again. @CristianS. I don't think that OOP is overengineering, but it's ok to have different opinions on that.
For sure! It depends a lot on what is he exactly trying to achieve. Normally variables like let are scoped in a module or something depending on which framework or tech-stack you use. But yeah... there is no white and black :D
My point was more meant to be in the same file as whole project @CristianS. You've definitely a point, for the task at hand it might be overkill to create a class for that, but I believe in a real world app, with a lot of code, the OOP style always wins. Again, only my opinion... :-)
@bambam See my answer, specially the more functional approach :D There's an alternative to OOP. OOP is good, but I'm not intoxicated anymore. OOP not always wins
0

Use the functions arguments object. It's an array of all the arguments that are being passed to a function. Then you can loop over them and run your functionality on them each time.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

Comments

0

You could use the arguments passed in your function as var args

const addNote = _ => {
     for(var i = 0; i < arguments.length; i++){
           notes.push({id:getId(), value: arguments[i]});
           console.log('Note added');
     }
}

Comments

0

use rest params :

const myFn = (...values) => {
  let tmpArr = [];
  for(let i = 0 ; i < values.length ; i++){
    tmpArr.push({
      id : i + 1,
      value : values[i]
    });
  }
  return tmpArr;
}

const result = myFn('own', 'snail', 'platypus');

console.log(result);

Comments

0

This is how it look like when using Rest Params and reusing your first function. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).

You can add so many notes as you want (addMultipleNotes can receive indefinite number of arguments )

let nextId = 0;
const getId = () => nextId++;
let notes = [{id: getId(), value: 'Note'}];

const addSingleNote = (input) => {
    notes.push({id:getId(), value: input});
    console.log('Note added');
};

const addMultipleNotes = (...args) => {
    for(let i = 0; i < args.length; i++){
        addSingleNote(args[i]);
    }
};

addMultipleNotes('one', 'two', 'three');
console.log(notes);

Comments

0

First of all, note how I've used an IIFE and a closure to create an id generator.

In the other hand, rest parameters, Array#map and parameter spread are your friends:

const incrId = (() => {
  let id = 0

  return () => ++id
})()

const valuesToNotes = (...values) => values.map(value => ({
  id: incrId(),
  value
}))

const notes = []

// Parameter spread (i.e. '...') gives each
// array item in the output of valuesToNotes
// as if you would use Function#apply
notes.push(...valuesToNotes('a', 'b', 'c'))

console.log(notes)

Yet another more functional approach which doesn't mutate the input notes and produces a new one with existing notes plus the ones transformed from values:

const concat = xs => ys => xs.concat(ys)
const map = f => xs => xs.map(f)
const pipe = xs => x => xs.reduce((r, f) => f(r), x)

const incrId = (() => {
  let id = 0

  return () => ++id
})()

const valueToNote = value => ({
  id: incrId(),
  value
})

const notes = []
const appendNotes = pipe([map(valueToNote), concat(notes)])
const moreNotes = appendNotes(['a', 'b', 'c'])

console.log(moreNotes)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.