Rafael Rafael - 19 days ago 5
React JSX Question

JS (and maybe React): Is this "find" method actually returning a reference to the array value?

I'm currently reading this somewhat outdated but fine React tutorial, and I spent hours looking at this little piece of trouble, which might be more Javascript-related than React-related. At a certain point, the author starts building a small notepad app, and then there's this code:

var onChangeNote = function (id, value) {
var note = _.find(notepad.notes, function (note) {
return note.id === id;
});
if (note) {
note.content = value;
}
onChange();
};


In the app, which can be viewed in full at the forementioned article or on the respective fiddle, we have a list of notes (which by itself is an array assigned to the
notes
property on a
notepad
object defined at the top of the script), and the selected one may be changed by the user, all while using React.

What really gets me is that this is the function responsible for changing the content of the note, in the
note.content = value;
line, but
note
is a variable that got its value from
_.find()
(it's the lodash variant, but I already tried replacing it with the vanilla JS array.find() and nothing changed), and yet, changing it appears to be updating the actual array, I found nowhere in the code any other instance of the selected note being changed, and the onChange() function just updates the view layer (therefore it doesn't do anything to the notepad itself), so this has to be it. So is the variable note referencing the actual respective item on the notepad.notes array it got its value from even though Javascript doesn't usually do that?

Maybe I'm missing something really obvious, but I cannot put my finger on it.

Answer

Basing from the source we can check that _.find doesn't create a deep copy of the object, it returns the object from the array.

Taken from: https://github.com/lodash/lodash/blob/4.6.0-npm-packages/lodash.find/index.js

function createFind(findIndexFunc) {
  return function(collection, predicate, fromIndex) {
    var iterable = Object(collection);
    if (!isArrayLike(collection)) {
      var iteratee = baseIteratee(predicate, 3);
      collection = keys(collection);
      predicate = function(key) { return iteratee(iterable[key], key, iterable); };
    }
    var index = findIndexFunc(collection, predicate, fromIndex);
    return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
  };
}

So yes, it returns the object "reference", and not a clone, so changing a property in it, changes the one in the array.

============

Here's an example regarding your question if javascript is pass by value or reference. Javascript is always pass by value except if the value passed is an object or array. Changing the value of a property to the object will also affect the original one. But changing the whole object will not affect the original one.

var arr = [{a: 1}, {a: 2}];
var x = arr.find(v => v.a === 1);
x.a = 5;
console.log(arr); // you'll see a is 5 here
x = 100; // we changed variable directly (note that x is the object that we extracted from the find function)
console.log(arr); // it's not changed, 5 is still the value
x = arr.find(v => v.a === 5); // let's get that object again
x = {a: 10}; // we replaced it with another object with same property but another value
console.log(arr); // still not changed
Comments