Merging two arrays of objects with different keys/properties
When you merge two arrays, where the one array contains a key value, you can save a lot of time by indexing the keys. Consider an index on the array2 name column.

It is really easy to index the data using an Object with named properties:

var indexed = {};

_.each(array2, function(data) {
  indexed[data["name"]] = data;
});


Now, we have a fast way to find any data record in array2 for a given name.

Using that structure becomes easy again, by looping for each of the array1 values, and updating them based on the value that was indexed, if any. Loop for each record, search in the index, use the default if the index value was not found.

To make the code a bit more flexible, and because the "column" names change from id to new_id, it helps to have a structure containing this column mapping:

var mapCols = {
  key1: "key1",
  key2: "key2",
  key3: "key3",
  id: "new_id"
}


The mapCol indicates that key1 should become key1, and so on, but id should become new_id.

This allows us to then make the "simple" nested loops:

_.each(array1, function(person){
  var use = indexed[person["id"]] || defaultOptions;
  _.each(mapCols, function(key) {
    person[mapCols[key]] = use[key];
  });
});


You can see this running here in your forked code.

In theory, this will turn your code from an \$O(n \times m)\$ operation to become an \$O(n + m)\$ one, where \$n\$ and \$m\$ are the sizes of the two arrays.