2015-04-12 2 views
5

Я пытаюсь написать довольно простую функцию Javascript и испытываю поведение, которое я не понимаю, когда я повторяю функцию.проблема с вызовом функции javascript дважды

Я переделал проблему до следующей ситуации. Я хочу написать функцию, которая будет принимать в качестве входных данных массив, состоящий из массивов массивов, например. A = [[[1]]]. Я не знаю стандартную терминологию для этого, поэтому я буду ссылаться на главный массив как «уровень 0», который имеет элементы, которые являются массивами «уровня 1». Я скажу, что массивы уровня 1 состоят из массивов «уровня 2». Массивы уровня 2 состоят из целых чисел.

Функция выполняет следующие действия на входе A (уровень 0 массива):

  1. создать пустой массив L;
  2. для каждого уровня 1 массив M в A
    • добавить один к каждой записи целого числа в каждом массиве уровня 2 в M;
    • добавить две копии M в L
  3. возвращение L.

Вот мой код:

function myFunc(A){ 
    var L = []; 
    for(var a=0; a<A.length; a++){ 
    var M = A[a].slice(0); 
    for(var i=0; i<M.length; i++){ 
     for(var j=0; j<M[i].length; j++){ 
     M[i][j]++; 
     } 
    } 
    for(var s=0; s<2; s++){ 
     var N = M.slice(0); 
     L.push(N); 
    } 
    } 
    return(L); 
} 

Теперь я проверить это:

var A = [[[1]]]; 

A = myFunc(A) 

После этого, я получаю A = [[[2]],[[2]]], чего я ожидал. Однако предположим, что я перебирать его:

var A = [[[1]]]; 

A = myFunc(A); 

A = myFunc(A); 

Тогда я ожидаю получить A = [[[3]],[[3]],[[3]],[[3]]], но вместо этого у меня есть A = [[[4]],[[4]],[[4]],[[4]]].

С другой стороны, если я заведу myFunc([[[2]],[[2]]]), я получаю ожидаемое [[[3]],[[3]],[[3]],[[3]]].

Я не понимаю, откуда это несоответствие.

+1

Это не проблема. Функция, вызываемая дважды, не имеет одинаковых результатов, снова прочитайте его вопрос. Я расследую, и у меня есть лидерство. Думаю, –

+1

Его вероятно ссылочное значение и скопированное. Попробуйте A = JSON.parse (JSON.stringify (A)) между вашими вызовами A = myFunct (A). Я не могу проверить, что я нахожусь на своем iPhone –

+1

@FlavienVolken да, который решает эту проблему, но я не понимаю, почему она здесь не работает. : o –

ответ

5

Проблема заключается линия:

M[i][j]++; 

узел хранит это в качестве ссылки на срез вашего, и вы видите это ясно, когда вы делаете это:

x = [[[1]]]; 
myFunc(x); 
myFunc(x); 
console.log(x); // ---> [[[3]]] 

Для мелкой копии вы 'd придется использовать трюк JSON.parse(JSON.stringify()) и доказать, что M является проблемой; добавив эту строку сразу после того, как M = A[a].slice(0); решает проблему.

M = JSON.parse(JSON.stringify(M)) 

документации Mozilla, о Array.prototype.slice():

Для ссылок на объекты (а не сам объект), ломтик копирует объект ссылки в новый массив.И исходный, и новый массив ссылаются на на тот же объект. Если объект, на который делается ссылка, изменяется на , видимый как для нового, так и для оригинального массива.

Source

Вот почему, потому что когда вы делаете M[i][j] массив уровень глубже по-прежнему ссылаются снаружи.

0

С Tristan Foureur уже указал, что вызвало несоответствие, я просто хотел бы добавить в почему

var A = [[[1]]]; 

A = myFunc(A); 
A = myFunc(A); 

дает различный результат в сравнении с

myFunc([[[2]],[[2]]]) 

При выполнении myFunc([[[2]],[[2]]]), что вы в основном делает myFunc(new Array(new Array(new Array(2))),(new Array(new Array(2))))).

Таким образом, когда двигатель V8 поднимает эту линию

var M = A[a].slice(0); 

было бы интерпретировать A[a].slice(0), как

new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0) 

и, следовательно, вы получаете 2 (из нового массива) каждый раз, когда он вызывается.

Это можно увидеть, если вы исследуете функцию с бревнами:

function myFunc(A){ 
    var L = []; 
    console.log("A is"+ JSON.stringify(A)); 
    for(var a=0; a<A.length; a++){ 
    var M = A[a].slice(0); 
    console.log("M is"+ JSON.stringify(M) + " while A is" +JSON.stringify(A),a); 
    for(var i=0; i<M.length; i++){ 
     for(var j=0; j<M[i].length; j++){ 
     M[i][j]++; 
     } 
    } 
    for(var s=0; s<2; s++){ 
     var N = M.slice(0); 
     L.push(N); 
     console.log("L.push:"+ JSON.stringify(N)); 
    } 
    } 
    console.log("the end" + JSON.stringify(L), JSON.stringify(A)); 
    return(L); 
} 

var A = [[[1]]]; 
A = myFunc(A); 
A = myFunc(A); 
var t = myFunc([[[2]],[[2]]]); 

Если заменить var M = A[a].slice(0); с

var M = new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0) 

и запустить через функцию без А, вы увидите [[[3]],[[3]],[[3]],[[3]]].

1

Как уже упоминалось, проблема заключается в том, что вызов M.slice сделал только мелкую копию. Они также дали хорошие решения о том, как сделать глубокую копию. Я бы предположил, что вам действительно не нужно делать копию вообще:

var L = []; 
for (var iLevel1 = 0; iLevel1 < A.length; iLevel1++) 
{ 
    for (var iLevel2 = 0; iLevel2 < A[iLevel1].length; iLevel2++) 
    { 
     for (var iLevel3 = 0; iLevel3 < a[iLevel1][iLevel2].length; iLevel3++) 
      L.push(a[iLevel1][iLevel2][iLevel3] + 1); 
    } 
} 

return L.concat(L); 
Смежные вопросы