0

I have arrays like this:

[ 'markdown', [ 'para', '\'example\'' ] ]

And I have a function that finds recursively the strings inside those arrays:

function traverse(tree, callback) {
  for (var i = 0; i < tree.length; ++i) {
    if (_.isArray(tree[i]) || _.isObject(tree[i])) {
      traverse(tree[i], callback)
    } else {
      callback(tree[i])
    }
  }
}

The problem is, when I perform tasks like replace what's being replaced isn't the actual array but just copies of its nodes. Example:

function replaceQuotes(tree, callback) {

  traverse(tree, function(node) {
    node = node.replace(/'/g, '"')
    console.log(node)
    // outputs: "example"
  })

  callback(null, tree)
}

function showResult(err, tree) {
   console.log(tree)
   // outputs [ 'markdown', [ 'para', '\'example\'' ] ]
}

How can I do it so I can I modify the actual arrays with the transverse function?

(By the way, I'm using the Async Node.js module.)

alexchenco
  • 53,565
  • 76
  • 241
  • 413

1 Answers1

2

Strings are passed by value - this is why your code behaves the way it does. A good solution is to make your callback return the new value and then modify your traverse slightly:

function tranverse(tree, callback) {
  for (var i = 0; i < tree.length; ++i) {
    if (_.isArray(tree[i]) || _.isObject(tree[i])) {
      tranverse(tree[i], callback)
    } else {
      tree[i] = callback(tree[i]) // changed part
    }
  }
}

You would then use it like this:

function replaceQuotes(tree, callback) {

  tranverse(tree, function(node) {
    return node.replace(/'/g, '"')
  })

  console.log(tree)
  // outputs [ 'markdown', [ 'para', '\'example\'' ] ]

  callback(null, tree)
}
fstanis
  • 5,234
  • 1
  • 23
  • 42
  • Hey, it worked. I think I tried something similar in the past but didn't work because I didn't add a `return`. Why does the `return` make all the difference? – alexchenco Mar 17 '15 at 13:43
  • It's not exactly the return itself, but rather the way you use your callback. In your original code, you modified the `node` parameter. Since strings are immutable, as already mentioned, any changes to `node` *will only exist inside the callback* and won't modify the value in the array itself. This is why you need to modify your traverse to make it do the actual change in the array, while you only use your callback as a way to "transform" the string. – fstanis Mar 17 '15 at 14:09