Pull to refresh

Comments 18

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

Это динамическая типизация.
Javascript имеет динамическую неявную слабую типизацию. Нетипизированный язык это, например, ассемблер.
Бу-э:
<li :class="todo.completed ? 'completed' : ''"></li>

Ведь в соседнем листинге у вас:
<li :class="{ completed: todo.completed }"></li>

Поправьте пжлст.
Это называется флэшбек из Реакта ;)
А вот эти вот все
JSON.parse(JSON.stringify(...))

это клон обьектов? А почем не
Object.assign

?
Этот способ не обеспечивает глубокого клонирования
Сейчас же можно юзать spread-оператор:
const source = { name: 'Vasya', age: 25, hobbies: { books: ['fantasy', 'novels'], music: ['rock', 'classic']}}
const target = { ...source }
Можно, но он тоже не обеспечивает глубокого копирования. Добавьте этот код и увидите:
target.hobbies.books.push("sci-fi")
console.log(source.hobbies.books)


Самое красивое решение будет использование сторонней библиотеки, например lodash:

const target = _.cloneDeep(source)

А какой смысл пушить строку в новый объект, а выводить в консоль старый?
Или я как-то не так понимаю, что вы имеете ввиду под глубоким копированием
А все понял. Сам дурак называется. Сорри

Ни разу не специалист в vue, но всё же: для чего вообще глубокое клонирование каждого элемента контейнера (массива или объекта), если вы меняете только один из них (например, todos[index])? Насколько я понимаю идею реактивных фреймворков, клонировать нужно только сам мутируемый элемент/свойство и его родительский контейнер, сохраняя неизменными ссылки на немутировавшие элементы, иначе у вас произойдёт полная инвалидация состояния, и всё выродится в тупой digest-цикл, разве не так?

По логике вещей так и должно быть, но реактивность во Vue устроена таким образом, что при замене одного массива новым отслеживаются совпадающие элементы, поэтому даже рекомендуется так делать. Подробнее тут

Там написано, что "замена одного массива другим, в случае совпадения части элементов этих массивов, будет очень эффективной операцией", но что подразумеватся под "совпадением" элементов? В реактивных фреймворках это обычно ссылочная эквивалентность (oldArray[i] === newArray[i]), потому что структурную эквивалентность и равенство по значению проверять дорого. В случае JSON.parse(JSON.stringify()) ссылочная эквивалентность полностью теряется.


Насколько я понимаю, эффективнее было бы делать примерно так:


const onUpdateTodo = (text: string, index: number) => {
  // клонируем контейнер, сохраняя старые элементы
  const todos = [ ...store.state.currentNote.todos ]; 
  // клонируем строго один элемент, модифицируя свойство `text`
  todos[index] = { ...todos[index], text };
  store.commit("updateTodos", todos);
}
Насколько я понимаю, имеется в виду структурная эквивалентность, поскольку методы массива, которые приводятся возвращают новый массив.
Я не вижу в чем ваш способ эффективнее, все еще используется клонирование, только с помощью spread оператора. В общем-то клонирование нужно только потому, что Vuex запрещает действия над своими состоянием вне мутаций в 'strict' режиме. Можно полностью избежать клонирования, если перенести изменение массива в мутацию. Мне пришло в голову такое решение:
      const onUpdateTodo = (text: string, index: number) => {
        store.commit("updateTodo", {
          index: index,
          todo: {
            text: text,
            completed: note.value.todos[index].completed
          }
        })
      }


Ну и соответственно мутация в хранилище:
    updateTodo(state, payload: { index: number, todo: ToDo }) {
      state.currentNote.todos[payload.index] = payload.todo
    },


Мутации в vuex могут принимать только один аргумент, поэтому нужна такая сложная структура для payload, чтобы передать индекс.

Я понимаю, что обилие `JSON.parse(JSON.stringify())` режет глаза. Попробую переписать код, и избавиться от этого, где возможно.
Насколько я понимаю, имеется в виду структурная эквивалентность

Что-то сомнительно.


поскольку методы массива, которые приводятся, возвращают новый массив.

Массив может быть новым, но при этом хранить ссылки на старые элементы, а не на их клоны.


В общем-то клонирование нужно только потому, что Vuex запрещает действия над своими состоянием вне мутаций в 'strict' режиме.

В моём примере нет действий над состоянием, исходное состояние остаётся нетронутым. Просто новое состояние максимально переиспользует неизменённые объекты из старого, чтобы не переаллоцировать объекты постоянно.


Я не вижу в чем ваш способ эффективнее

  • Нет сериализации/десериализации.
  • При клонировании массива через spread op копируются только ссылки на элементы массива, сами элементы не клонируются. Копировать ссылки намного дешевле. Из всех элементов массива клонируется только один-единственный изменённый элемент (причём в нём тоже копируются только ссылки везде, где данные не поменялись).
  • Меньше аллокаций, меньше нагрузка на сборщик мусора
  • Эффективнее поиск изменений: если 2 ссылки одинаковы, то структуру этих объектов и значения их полей можно не сравнивать, так как это один и тот же объект.
Разобрался в вашем способе. Действительно отличное решение
Sign up to leave a comment.

Articles