2017-11-22 128 views
9

Drodzy przepełnienie stosu Wspólnoty,
Mam pytanie dotyczące wymiany własności obiektu (można przeskoczyć na dół, aby przeczytać pytanie). Pracuję nad aplikacją, która pobiera obiekt nauczyciela z Back-end. Back-end używa hibernacji java do zapytania bazy danych i serializuje obiekt, który ma być wysłany na front end (ja). Dostaję ten obiekt nauczyciela, ale w obiekcie znajdują się okrągłe odniesienia. Które java obsługuje, dodając identyfikator referencyjny zamiast obiektu. Dostaję obiekt nauczyciela, a wewnątrz obiektu znajdują się referencyjne identyfikatory, które muszę zastąpić rzeczywistym obiektem, a problem polega na tym, że są to obiekty zagnieżdżone. To, co obecnie robię, to tworzenie stosu i przemierzanie obiektów w celu znalezienia tych identyfikatorów i identyfikatorów. Kiedy znajdę identyfikator, umieszczę go na stosie. Nie jest to problemem, ale kiedy znajdę identyfikator referencyjny, muszę go odwiesić z tym, który znalazłem na stosie. Ponownie jest to trudne, ponieważ robię to za pomocą funkcji rekursywnej, więc nie mam fizycznego obiektu.JS - wymiana własności

Moje pytanie brzmi, w jaki sposób można zastąpić zagnieżdżonych właściwości obiektów

JS BIN

var stack = {}; 
var add = function(prop, data) { 
    if (prop == '@id') { 
    stack[data[prop]] = data; 
    } 
    if (prop == '@ref') { 
    // console.log(stack[data[prop]]) 
    // How do i replace the value with the stack object 
    // test.PROPERTY = stack[data[prop]] is what im looking for 
    } 
} 
var traverse = function(object) { 
    for (var property in object) { 
    if (object.hasOwnProperty(property)) { 
     add(property, object); 
     if (object[property] && typeof object[property] === 'object') { 
     traverse(object[property]); 
     } 
    } 
    } 
} 
var test = { 
    'teacher': { 
    'course': { 
     "@id": "1", 
     'students': [{ 
     "@id": "2", 
     'name': "John", 
     'course': { 
      "@ref": "1", 
     } 
     }, { 
     "@id": "2", 
     'name': "Next", 
     'course': { 
      "@ref": "1", 
     } 
     }] 
    } 
    } 
}; 
setTimeout(() => { 
    console.log(stack); 
    // console.log(test); 
}, 500); 
traverse(test); 
+0

obok hałasu, co masz i co chcesz? proszę dodać dane przed i po zmianie. –

+0

@NinaScholz Obecnie nie robię nic z danymi, ponieważ nie jestem pewien, w jaki sposób mogę odwołać się do danych obiektu z mojej funkcji. Ma sens ? – John

+1

'@ ref' jest tam z jakiegoś powodu. jeśli spróbujesz zastąpić 'id's rzeczywistymi obiektami, możesz trafić w kołowe odwołania, które spowodują wycieki pamięci (które doprowadzą do maksymalnego błędu wielkości stosu wywołań). –

Odpowiedz

3

Rozważ iteracji nad strukturą danych dwukrotnie:

  1. rekurencyjne przechodzenie do wypełniania id -to-object map (gdzie klucze to id i wartości są rzeczywistymi obiektami). Możesz zainicjować mapę w pierwszym wywołaniu rekurencyjnym, a następnie przekazać ją do następnych poziomów rekursji.

  2. Rekurencyjne przejście dla zastąpienia odniesień rzeczywistymi obiektami. Ponieważ masz teraz mapę, można ją zastąpić na miejscu.

Code

+0

Pomyślałem o tym, ale wciąż napotykam problem, w którym nie wiem, co jest własnością. Jeśli to rozwiąże problem, opublikuj przykład, ponieważ nie rozumiem, jak to zrobić. – John

+0

Tak, że rozumiem - właściwość "kurs" studentów "Jan" i "Dalej" powinna zawierać kurs o id "1", zamiast obiektu "{ref:" 1 "}"? –

+0

Masz rację. Potrzebuję go zamienionego na obiekt kursu @id: 1. Rzeczą, która mnie blokuje, są właściwości obiektów. Nie rozumiem, w jaki sposób mogę znaleźć ścieżkę do właściwego obiektu, przynajmniej z moim kodem. Przykładem tego, co sugerujesz, byłoby WIELKIE, to coś mnie zaskoczyło. – John

3

Najpierw należy przechodzić przez obiekt i zbierać: słownik

  1. Object - mapa ID obiektu do obiektu
  2. lista elementów, gdzie:
    • Pierwszym elementem jest obiekt zawierający właściwość do zamiany
    • nazwa własności zastąpić

Mając taka lista jest kluczem do rozwiązania. Umożliwia to zarówno uniknięcie drugiego przebiegu rekursywnego obiektu test, jak i przechowywanie informacji wystarczających do zastąpienia całego obiektu {"@ref":"..."}, a nie tylko jego zawartości.

Następnie powinieneś przetestować listę i zastąpić wszystkie obiekty {"@ref":"..."} odwołaniami do rzeczywistych obiektów ze słownika.

var test = { 
 
    'teacher': { 
 
     'course': { 
 
      "@id": "1", 
 
      'students': [{ 
 
       "@id": "2", 
 
       'name': "John", 
 
       'course': { 
 
        "@ref": "1", 
 
       } 
 
      }, { 
 
       "@id": "2", 
 
       'name': "Next", 
 
       'course': { 
 
        "@ref": "1", 
 
       } 
 
      }] 
 
     } 
 
    } 
 
}; 
 

 
function collectRefs(obj, dic, list) { 
 
    obj.hasOwnProperty('@id') && (dic[obj['@id']] = obj); // populate dictionary 
 
    Object.keys(obj).forEach(function(key) { 
 
     if(obj[key] && typeof obj[key] === 'object') { 
 
      if(obj[key].hasOwnProperty('@ref')) { 
 
       list.push([obj, key]) // populate list 
 
      } else { 
 
       collectRefs(obj[key], dic, list) // traverse recursively 
 
      } 
 
     } 
 
    }); 
 
    return obj; 
 
} 
 

 
function recover(obj) { 
 
    var dic = {}, list = []; 
 
    collectRefs(obj, dic, list); 
 
    list.forEach(function(item) { 
 
     item[0][item[1]] = dic[item[0][item[1]]['@ref']]; // make replacements 
 
    }); 
 
    return obj; 
 
} 
 

 
console.log(recover(test).teacher.course.students[0].course['@id']); // 1

Na koniec wszystkie {"@ref": "1"} zostaną zastąpione w odniesieniu do obiektu {"@id": "1", ...}

P.S.

Nawiasem mówiąc, jest lepszym rozwiązaniem serializacji/Cofnięcie JSON odniesieniami tarczowe (cycle.js) świadczonych przez wynalazcę formatu JSON Douglas Crockford. Wykorzystuje ona wartości JSONPath jako wartości obiektów @ref i dlatego nie wymaga posiadania @id na polecanych obiektach. Nie ma również potrzeby posiadania dodatkowych struktur danych (takich jak słownik i lista z powyższego przykładu) do rekonstrukcji oryginalnego obiektu z odwołaniami cyklicznymi. Tak więc, jeśli możesz zmienić sposób serializacji obiektów Back-end, polecam zajrzeć do tego.

+0

Wygląda dobrze!Ale ostatni nawias kwadratowy tutaj 'item [0] [item [1]] = dic [item [0] [item [1]] ['@ ref']]];' jest nadmiarowy, dlatego fragment kodu doesn ' t działa –

1

Nie wiem, czy to, co chcesz

var test = { 
 
    'teacher': { 
 
     'course': { 
 
      "@id": "1", 
 
      'students': [{ 
 
       "@id": "2", 
 
       'name': "John", 
 
       'course': { 
 
        "@ref": "1", 
 
       } 
 
      }, { 
 
       "@id": "2", 
 
       'name': "Next", 
 
       'course': { 
 
        "@ref": "1", 
 
       } 
 
      }] 
 
     } 
 
    } 
 
}; 
 

 
let tmpObj = {}; 
 
let noRef = {}; 
 

 
function traverse(obj){ 
 
    Object.keys(obj).forEach(function(v){ 
 
    if(v !== '@ref' && typeof obj[v] === 'object'){ 
 
     var newObj = obj[v]; 
 
     if(obj[v]['@id']){ 
 
     \t if(!tmpObj[v]){ 
 
     \t \t tmpObj[v] = {}; 
 
     \t } 
 
     tmpObj[v][obj[v]['@id']] = obj; 
 
     } 
 
     if(obj[v]['@ref']){ 
 
     if(tmpObj[v] && tmpObj[v][obj[v]['@ref']]){ 
 
      obj[v]['@ref'] = tmpObj[v][obj[v]['@ref']][v]; 
 
     }else{ 
 
      if(!noRef[v]){ 
 
      \t noRef[v] = []; 
 
      } 
 
      noRef[v].push(newObj) 
 
     } 
 
     } 
 
     traverse(newObj); 
 
    } 
 
\t }) 
 
} 
 

 
traverse(test); 
 
Object.keys(noRef).forEach(function(v){ 
 
\t v.forEach(function(vv){ 
 
\t \t vv['@ref'] = tmpObj[v][vv['@ref']][v]; 
 
\t }) 
 
}); 
 

 
console.log(test);

obiektu noRef to w przypadku, gdy przedmiot ref nie został jeszcze znaleziony, więc umieścić w nim obiektu nadrzędnego bieżącego ref, a po przejściu zakończyłem pętlę, aby nie skojarzyć asocjacji z ref.

1

Jeśli bezpośrednio ustawisz wartość. w następnych iteracjach obiekt będzie miał odniesienie kołowe, a skończysz w nieskończonej pętli. Tak więc wciśnij operację przypisania do kolejki zdarzeń (prosty sposób to wywołanie setTimeout przechodzącej 0 sekund). Mam nadzieję, że to Ci pomoże.

var stack = {}; 
 
    var add = function(prop, data) { 
 
     if (prop == '@id') { 
 
     stack[data[prop]] = data; 
 
     } 
 
     if (prop == '@ref') { 
 
     // console.log(stack[data[prop]]) 
 
     // How do i replace the value with the stack object 
 
     setTimeout(function(){ 
 
      data[prop] = stack 
 
     },0); 
 
     } 
 
    } 
 
    var traverse = function(object) { 
 
     for (var property in object) { 
 
     if (object.hasOwnProperty(property)) { 
 
      add(property, object); 
 
      if (object[property] && typeof object[property] === 'object') { 
 
      traverse(object[property]); 
 
      } 
 
     } 
 
     } 
 
    } 
 
    var test = { 
 
     'teacher': { 
 
     'course': { 
 
      "@id": "1", 
 
      'students': [{ 
 
      "@id": "2", 
 
      'name': "John", 
 
      'course': { 
 
       "@ref": "1", 
 
      } 
 
      }, { 
 
      "@id": "2", 
 
      'name': "Next", 
 
      'course': { 
 
       "@ref": "1", 
 
      } 
 
      }] 
 
     } 
 
     } 
 
    }; 
 
    setTimeout(() => { 
 
     console.log(stack); 
 
     // console.log(test); 
 
    }, 500); 
 
    traverse(test);