Когда мутация становится побочным эффектом? - PullRequest
2 голосов
/ 22 апреля 2019

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

Основной ответ мутировал массив для раннего выхода из итератора, но массив можно было легко восстановить в исходное состояние, отодвинув сплайсированные элементы, несколько сомнительное решение и, возможно,не совсем функциональный.

Однако многие алгоритмы получают значительное преимущество, если элементы могут быть изменены на месте (мутированы)

В отношении Javascript (однопоточный (без рабочих) и без прокси)это считается мутацией, если модификация существует только временно?Или Является ли мутация только побочным эффектом после возврата функции.

Является ли следующая функция мутатором?

function mutateAndRepair(arr) {  // arr is an array of numbers
    arr[0]++;
    arr[0]--;
}
  • Массив содержит 1 или более элементов.
  • Первый элемент массива (индекс 0) - это число в максимальном безопасном целочисленном диапазоне.
  • Массив не является общим буфером
  • Массив не отслеживается прокси

Я считаю, что это не является мутацией, поскольку мутация существует только во время выполнения функции и когда JS блокирует, никакой другой код никогда не сможет увидеть мутацию, следовательно, никаких побочных эффектов нет.

Учитывая ограничения, соответствует ли это общей функциональной парадигме, используемой JavaScript-кодерами?

1 Ответ

5 голосов
/ 22 апреля 2019

Операторы ++ и -- изменяются, и они точно не меняют друг друга. Цитирование стандарта 2017 :

12.4.4.1 Семантика раннего времени: оценка
UpdateExpression : LeftHandSideExpression ++

  1. Пусть lhs будет результатом оценки LeftHandSideExpression.
  2. Пусть oldValue будет ? ToNumber(? GetValue(lhs)).
  3. Пусть newValue будет результатом добавления значения 1 к oldValue, используя те же правила, что и для оператора + (см. 12.8.5).
  4. Выполнить ? PutValue(lhs, newValue).
  5. Возврат oldValue.

Это второй шаг, который важен, поскольку он преобразует значение в примитив number, но между ним и объектом Number есть небольшая разница, возвращаемая конструктором Number.

var arr = [new Number(1234)];

function mutateAndRepair(arr) {
  console.log(`the value before is ${arr[0]}`);
  arr[0]++;
  arr[0]--;
  console.log(`the value after is ${arr[0]}`);
}

arr[0].foo = 'bar';
console.log(`foo before is ${arr[0].foo}`);
mutateAndRepair(arr)
console.log(`foo after is ${arr[0].foo}`);

Теперь я немного нахальный, потому что я свободно интерпретирую ваше требование, что первый элемент arr - это "число". И, конечно, вы можете добавить еще одно условие, что значения arr должны быть «числовыми примитивами», чтобы исключить эту точную форму мутации.

Как насчет другого, более тонкого вопроса. -0 и 0 обрабатываются как одно и то же значение практически всеми способами, кроме Object.is:

var arr = [-0];

function mutateAndRepair(arr) {
  console.log(`the value before is ${arr[0]}`);
  arr[0]++;
  arr[0]--;
  console.log(`the value after is ${arr[0]}`);
}

console.log(`is zero before ${Object.is(0, arr[0])}`);
mutateAndRepair(arr)
console.log(`is zero after ${Object.is(0, arr[0])}`);

Хорошо, вы можете добавить требование, чтобы первый элемент arr не был -0. Но все это не попадает в точку . Вы можете утверждать, что практически любой метод не является мутирующим, если вы просто объявите, что будете игнорировать любой случай, в котором будет наблюдаться мутация.

Учитывая ограничения, соответствует ли это общей функциональной парадигме, используемой кодировщиками JavaScript?

Я бы не считал бы, что этот код следует принципам функционального кодирования, и, возможно, даже отклонил бы его в обзоре кода, если бы это было целью проекта. Дело даже не в мельчайших подробностях того, как и обеспечивается ли неизменность всеми путями кода, а в том, что он зависит от внутренней мутации , что делает этот код нефункциональным, на мой взгляд. Я видел множество ошибок в псевдо-функциональном коде, где между шагами mutate и repair возникает исключение, которое, конечно, приводит к явным и неожиданным побочным эффектам, и даже если у вас есть catch / finally блок, чтобы попытаться восстановить состояние, также может возникнуть исключение. Возможно, это только мое мнение, но я думаю об неизменности как о части большого функционального стиля , а не просто как о технической особенности данной функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...