Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Хотел как лучше, а получилось сложно. Лучший splice. (https://javascript.ru/forum/misc/73458-khotel-kak-luchshe-poluchilos-slozhno-luchshijj-splice.html)

Yesasha 17.04.2018 16:39

Хотел как лучше, а получилось сложно. Улучшаю splice.
 
Изначальной задачей было сделать так, чтобы функция splice могла принимать отрицательный второй аргумент и удалять значения в обратном направлении.
Допустим есть массив:
var arr = [0,1,2,3,4,5];
splice(3,1);
>[0,1,2,4,5]
splice(3,-1);
>[0,1,3,4,5]

Но потом всё пошло не так. По стандарту, первые 2 аргумента обязательны, но по факту движки допускают вызов только с первым аргументом, удаляя остаток массива. Дальше приключения продолжаются! Отсутствием второго аргумента считается только вызов функции с 1 аргументом splice(0), если же вызвать метод как splice(0,undefined), то второй аргумент будет принят за ноль! Более того, нулями становятся null и даже NaN! В общем-то так ведут себя и другие методы. Решил я сделать всё аргументы не обязательными, но вот как быть с NaN пока не знаю. Пока сделал что он тоже инициирует значения по умолчанию.
Потратил много времени и задача-то в общем не первой важности, стандартный splice тоже прекрасно справляется. Но сдаваться не хотелось и я всё же добил его! Назовём его пока что mySplice:
mySplice(array[, start, deleteCount, item1[, item2[, ...]]])

Все аргументы, кроме массива опциональны!
Это будет работать как
array.push(1, 2, 3);
mySplice(array, null, null, 1, 2, 3);

Удаление двух элементов с начала:
mySplice(array, null, 2);
or
mySplice(array, 0, 2); // Like original

Удаление двух элементов с конца:
mySplice(array, null, -2);
or
mySplice(array, -2, 2); // Like original
or
mySplice(array, Infinity, -2);

Оставление двух элементов в начале:
mySplice(array, 2); // Like original
or
mySplice(array, 2, null); // Not like original
or
mySplice(array, 2, Infinity); // Like original

Оставление двух элементов в конце:
mySplice(array, -2);
or
mySplice(array, -2, null);
or
mySplice(array, 0, array.length - 2); // Like original

Но отрицательные числа приводят к другому эффекту, который, при желании, можно исправить, новые элементы будут добавляться с другой стороны.
Добавит элементы перед оставшимися:
mySplice(array, -2, null, 1, 2, 3);

Добавит элементы после оставшихся:
mySplice(array, 0, array.length - 2, 1, 2, 3);

И другие возможности, которые можно понять по коду (который, к сожалению, получился не простым) или, если будет спрос, я опишу позже. isNumeric() и trunc() интегрированы, чтоб не создавать зависимостей. Жду советов по доработке. Вот сама функция:
function mySplice (arr, start, deleteCount) {
  if (!Array.isArray(arr)) {
    throw new Error('Argument is not an Array.');
  }

  var len = arr.length;

  // isNumeric. Non numeric triggers default
  if (!isNaN(parseFloat(start))) {
    // Truncate
    start = (start - start % 1) || (!isFinite(start) || start === 0 ? start : start < 0 ? -0 : 0);
  } else {
    start = null;
  }

  // isNumeric. Non numeric triggers default
  if (!isNaN(parseFloat(deleteCount))) {
    // Truncate
    deleteCount = (deleteCount - deleteCount % 1) || (!isFinite(deleteCount) || deleteCount === 0 ? deleteCount : deleteCount < 0 ? -0 : 0);
  } else {
    deleteCount = null;
  }

  var s = start;
  var dc = deleteCount;

  if (start == null) {
    if (deleteCount == null) {
      s = len;
    } else if (-len < deleteCount && deleteCount < 0) {
      s = len + deleteCount;
      dc = -deleteCount;
    } else if (len <= deleteCount || deleteCount <= -len) { // 2
      dc = len;
    }
  } else if (len <= start) {
    if (deleteCount == null) {
      dc = 0;
    } else if (deleteCount <= -len) {
      s = 0;
      dc = len;
    } else if (-len < deleteCount && deleteCount < 0) {
      s = len + deleteCount;
      dc = -deleteCount;
    }
  } else if (0 < start && start < len) {
    if (deleteCount == null) {
      dc = len - start;
    } else if (-start < deleteCount && deleteCount < 0) {
      s = start + deleteCount;
      dc = -deleteCount;
    } else if (deleteCount <= -start) {
      dc = start;
      s = 0;
    }
  } else if (start <= 0) {
    if (deleteCount == null || len <= deleteCount) {
      dc = len;
    }

    if (-len < start && start < 0) {
      if (deleteCount == null || deleteCount <= -(len + start)) {
        s = 0;
        dc = len + start;
      } else if (-(len + start) < deleteCount && deleteCount < 0) {
        s = start + len + deleteCount;
        dc = -deleteCount;
      }
    } else if (start <= -len) {
      if (deleteCount == null) {
        dc = 0;
      }
    }
  }

  // Arguments object may be not connected to locals
  arguments[1] = s;
  arguments[2] = dc;

  var aProto = Array.prototype;
  return aProto.splice.apply(arr, aProto.slice.call(arguments, 1))
}


Часовой пояс GMT +3, время: 15:07.