2015-03-17 5 views
0

У меня есть массивы, как это:JavaScript: функция не изменяя фактический массив

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

И у меня есть функция, которая находит рекурсивно строки внутри этих массивов:

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]) 
    } 
    } 
} 

Проблема в том, когда Я выполняю такие задачи, как replace, что заменяется не фактическим массивом, а только копиями его узлов. Пример:

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\'' ] ] 
} 

Как я могу это сделать, так что я могу изменить фактические массивы с функцией transverse?

(Кстати, я использую модуль Async Node.js.)

+3

Это потому, что в настоящее время вы работаете со строками в массиве и больше не сам массив, а строки передаются только по значению, а не копия ссылки значения и т. д. – adeneo

+0

[строки Javascript неизменяемы] (http://stackoverflow.com/questions/51185/are -javascript-strings-immutable-do-i-need-a-string-builder-in-javascript) –

+0

Я думаю, вы имеете в виду 'traverse' – Tom

ответ

2

Строки передаются по значению - вот почему ваш код ведет себя так, как это делает. Хорошим решением является, чтобы сделать ваш обратный вызов возвращает новое значение, а затем немного изменить свой траверс:

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 
    } 
    } 
} 

Вы бы затем использовать его как это:

function replaceQuotes(tree, callback) { 

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

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

    callback(null, tree) 
} 
+0

Эй, это сработало. Я думаю, что я пробовал что-то подобное в прошлом, но не работал, потому что я не добавлял 'return'. Почему «возврат» имеет значение? – alexchenco

+0

Это не совсем само возвращение, а способ использования обратного вызова. В исходном коде вы изменили параметр 'node'. Поскольку строки неизменяемы, как уже упоминалось, любые изменения в 'node' * будут существовать только внутри обратного вызова * и не будут изменять значение в самом массиве. Вот почему вам нужно изменить траверс, чтобы сделать фактическое изменение в массиве, в то время как вы используете свой обратный вызов только для того, чтобы «преобразовать» строку. – fstanis

+0

ОК, спасибо за объяснение! – alexchenco

Смежные вопросы