wingmeng / front-end-quiz

前端小测试答题收集
0 stars 0 forks source link

JS基础测试28:数组项位移、互换位置 #4

Open wingmeng opened 5 years ago

wingmeng commented 5 years ago

题目:

image


我的答案:

既然题目中用了 let ,那我就不客气了,ES6 直接用起。:tada: 主要原理是数组的 splice 操作,然后是处理各种边界情况。 封装了一下,使用链式调用,使方法看起来更语义化。


let arr = [0, 1, 2, 3, 4, 5];

// 返回对应索引的数组项
Array.prototype.index = function(index) {
    if (!(typeof index !== 'boolean' && Number.isInteger(Number(index)))) {
        throw (`\`${index}\` is not a integer.`);
    }

    let arr = [...this];  // 使用原数组的副本,以免后续操作影响原数组

    return {
        arr,
        index,
        value: arr[index]
    };
}

// 移动数组项
Object.prototype.moveTo = function(target) {
    let { arr, index, value } = this;

    const _moveTo = (targetIdx) => {
        if (!Number.isInteger(targetIdx)) {
            throw (`\`${targetIdx}\` is not a integer.`);
        }

        if (targetIdx > arr.length - 1) {
            targetIdx = arr.length - 1;
        } else if (targetIdx < 0) {
            targetIdx = 0;
        }

        arr.splice(index, 1);  // 先删除原来的
        arr.splice(targetIdx, 0, value);  // 在目标索引补上原来的
    };

    if (!arr.includes(value)) {  // 不存在
        throw (`The current index(\`${index}\`) of item is not in the array([${arr}])`);
    }

    // 各种条件判断
    if (target === 'start' || target <= 0) {  // 移到开头
        _moveTo(0)
    } else if (target === 'end' || target >= arr.length - 1) {  // 移到结尾
        _moveTo(arr.length);
    } else if (target === 'forward') {  // 向前
        _moveTo(index - 1);
    } else if (target === 'backward') {  // 向后
        _moveTo(index + 1);
    } else {
        _moveTo(target);
    }

    return arr;
}

// 交换数组项位置
Object.prototype.swapWith = function(idx) {
    let { arr, index, value } = this;

    if (!arr.includes(value)) {  // 不存在
        throw (`The current index(\`${idx}\`) of item is not in the array([${arr}])`);
    }

    if (!(typeof idx !== 'boolean' && Number.isInteger(Number(idx)))) {
        throw (`\`${idx}\` is not a integer.`);
    }

    if (idx > arr.length - 1 || idx < 0 ) {
        throw (`The index(\`${idx}\`) of item is not in the array([${arr}])`);
    }

    arr[index] = arr.splice(idx, 1, value)[0];

    return arr;
}

console.log(arr.index(3))

console.group('任意数组项向前移一位');
    console.log(arr.index(0).moveTo('forward'));  // [0, 1, 2, 3, 4, 5]
    console.log(arr.index(3).moveTo('forward'));  // [0, 1, 3, 2, 4, 5]
    console.log(arr.index(5).moveTo('forward'));  // [0, 1, 2, 3, 5, 4]
console.groupEnd();

console.group('任意数组项向后移一位');
    console.log(arr.index(0).moveTo('backward'));  // [1, 0, 2, 3, 4, 5]
    console.log(arr.index(3).moveTo('backward'));  // [0, 1, 2, 4, 3, 5]
    console.log(arr.index(5).moveTo('backward'));  // [0, 1, 2, 3, 4, 5]
console.groupEnd();

console.group('将对应数组项移动到最前面');
    console.log(arr.index(2).moveTo(0));  // [2, 0, 1, 3, 4, 5]
    console.log(arr.index(1).moveTo(-10));  // [1, 0, 2, 3, 4, 5]
    console.log(arr.index(5).moveTo('start'));  // [5, 0, 1, 2, 3, 4]
console.groupEnd();

console.group('将对应数组项移动到最后面');
    console.log(arr.index(2).moveTo(arr.length - 1));  // [0, 1, 3, 4, 5, 2]
    console.log(arr.index(1).moveTo(100));  // [0, 2, 3, 4, 5, 1]
    console.log(arr.index(3).moveTo('end'));  // [0, 1, 2, 4, 5, 3]
console.groupEnd();

console.group('任意两个数组项交换位置');
    console.log(arr.index(0).swapWith(5));  // [5, 1, 2, 3, 4, 0]
    console.log(arr.index(3).swapWith(1));  // [0, 3, 2, 1, 4, 5]
    console.log(arr.index(4).swapWith(5));  // [0, 1, 2, 3, 5, 4]
console.groupEnd();

console.group('边界情况验证');
    // 目标索引值超出数组范围,按数组边界处理
    console.log(arr.index(2).moveTo(-1));  // [2, 0, 1, 3, 4, 5]
    console.log(arr.index(2).moveTo(100));  // [0, 1, 3, 4, 5, 2]

    // 字符串数字按数字处理
    console.log(arr.index('2').moveTo('123'));  // [0, 1, 3, 4, 5, 2]
    console.log(arr.index('3').swapWith('4'));  // [0, 1, 2, 4, 3, 5]

    // 非法索引值,报错
    // Error: `abc` is not a integer.
    console.log(arr.index('abc').moveTo(4));
    console.log(arr.index(4).moveTo('abc'));
    console.log(arr.index(4).swapWith('abc'));

    // 索引元素不存在,报错
    // Error: The index(`100`) of item is not in the array([0,1,2,3,4,5])
    // Error: The index(`-2`) of item is not in the array([0,1,2,3,4,5])
    console.log(arr.index(100).moveTo(5));
    console.log(arr.index(5).swapWith(100));
    console.log(arr.index(5).swapWith(-2));

    // 非数组调用,报错(JS内部报语法错误)
    // Error: "123".index is not a function
    console.log('123'.index(2).swapWith(5));
console.groupEnd();
wingmeng commented 5 years ago

自我评分:一般

优秀、良好、一般、差劲

不足之处:

  1. 污染了原生对象的 prototype
  2. 代码逻辑有待精简。

学习收获:

  1. 数组所有的位置移动本质上都是位置交换
wingmeng commented 5 years ago

最佳实践:DEMO

function swapArrItem(arr, srcIdx, targetIdx) {
  if (!Array.isArray(arr)) {
    throw Error(`\`${arr}\` is not a array`);
  }

  if (isNaN(srcIdx) || isNaN(targetIdx)) {
    throw Error(`index is not a number`);
  }

  let len = arr.length - 1;

  srcIdx = srcIdx < 0 ? 0 : srcIdx;
  srcIdx = srcIdx > len ? len : srcIdx;
  targetIdx = targetIdx < 0 ? 0 : targetIdx;
  targetIdx = targetIdx > len ? len : targetIdx;

  arr = [...arr];
  [arr[srcIdx], arr[targetIdx]] = [arr[targetIdx], arr[srcIdx]];

  return arr;
}

function moveArrItem(arr, idx, method) {
  const _toBoundary = (arr1, idx, handle) => {
    let temp = arr1.splice(idx, 1)[0];

    arr1[handle](temp);
    return arr1;
  };

  if (!Array.isArray(arr)) {
    throw Error(`\`${arr}\` is not a array`);
  }

  arr = [...arr];

  switch(method) {
    case 'first':
      return _toBoundary(arr, idx, 'unshift');
    case 'last':
      return _toBoundary(arr, idx, 'push');
    case 'forward':
      return swapArrItem(arr, idx, idx - 1);
    case 'backward':
      return swapArrItem(arr, idx, idx + 1);
    default:
      throw Error(`${method} is not a available parameter`);
  }
}