欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

如何在JavaScript中停止各种循环(for, forEach, map, for...in等):实用技巧与方法汇总

最编程 2024-02-06 15:22:37
...

话不多说,直接看代码

const arr = [1, 2, 3, 4, 5, 6];

for

  • break结束循环
for (let i = 0; i < arr.length; i++) {
  if (i === 3) {
    break;
  }
  console.log(arr[i]);  // 1 2 3
}
  • continue跳过当前循环
for (let i = 0; i < arr.length; i++) {
  if (i === 3) {
    continue;
  }
  console.log(arr[i]);  // 1 2 3 5 6
}

forEach

并没有优雅的方法结束forEach循环,有的小伙伴可能会说,return不行咩。

arr.forEach((item) => {
  if (item === 3) {
    // 此处return和return true,return false都一样
    return;
  }
  console.log(item);  // 1 2 4 5 6
});

这里我也有同样的疑惑,forEach实质上是Array.prototype上的一个方法,既然是方法,那为什么retrun不能直接终止呢?????

带着这样的疑惑,在网上找了一下,实在找不到v8的源码,借用mozilla的forEach源码????

/* ES5 15.4.4.18. */
function ArrayForEach(callbackfn /*, thisArg*/) {
  var O = ToObject(this);
  var len = ToLength(O.length);
  if (arguments.length === 0)
    ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.prototype.forEach");
  if (!IsCallable(callbackfn))
    ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
  var T = arguments.length > 1 ? arguments[1] : void 0;

  for (var k = 0; k < len; k++) {
    if (k in O) {
      callContentFunction(callbackfn, T, O[k], k, O);
    }
  }
  return void 0;
}

核心代码我们可以看到原来是for循环对每个元素都执行了一次fn,那这就不难理解为什么return终止不了forEach循环了。

因为我们传入的方法,这里为if(item === 3) return,是在for循环内部执行的,return只结束了当item === 3所执行的fn,即return,但是for循环还是会继续执行。所以上面的代码log的结果是1 2 4 5 6

tips: 这里我们也可以看出来forEach的返回值是void 0,即undefined,那么下次当我们再听到forEachmap的区别是forEach没有返回值时,我们就可以很装x的说:forEach也有返回值,只不过是undefined,没有意义而已????

知道了怎么回事,我们自己撸一个forEach

arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) - MDN

Array.prototype.forEach = function (fn, thisArg) {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function`);
  }
  for (var i = 0; i < this.length; i++) {
    fn.apply(thisArg, [this[i], i, this]);
  }
};

那有的小伙伴可能要说了,我就要结束forEach循环,那当然也不是没有办法,抛出错误就行了

try {
  arr.forEach((item) => {
    if (item === 3) {
      throw new Error("exit foreach");
    }
    console.log(item);  // 1 2
  });
} catch (e) {}

这里可以看一下MDN上对forEach的说明: Array.prototype.forEach()

map

map与forEach类似,唯一的区别就是

map方法会给原数组中的每个元素都按顺序调用一次 callback函数。callback每次执行后的返回值(包括undefined)组合起来形成一个新数组。

这里再贴一下MDN对map的使用说明

因为map生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请用forEach或者for-of替代。你不该使用map:
A)你不打算使用返回的新数组,
B)你没有从回调函数中返回值。

Array.prototype.map()-MDN

for...in

break结束循环

const person = {
  name: "ming",
  age: 18,
  1: 1,
  job: "student",
};

for (const key in person) {
  if (key === "age") {
    break;
  }
  console.log(`${key}: ${person[key]}`);
  // 1: 1
  // name: ming
}

continue跳过当前循环

const person = {
  name: "ming",
  age: 18,
  1: 1,
  job: "student",
};

for (const key in person) {
  if (key === "age") {
    continue;
  }
  console.log(`${key}: ${person[key]}`);
  // 1: 1
  // name: ming
  // job: student
}

这里可以看到,key1的元素比keyname的元素先打印了出来,

for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。

os: 本来for...in就是为了遍历对象的,然而对象本来就是无序的 ????️

顺手撸一个深拷贝

function deepClone(target) {
  if (typeof target !== "object" || target === null) return target;
  let result = Array.isArray(target) ? [] : {};
  for (const key in target) {
    if (target.hasOwnProperty(key)) {
      const element = target[key];
      if (typeof element === "object") {
        result[key] = deepClone(element);
      } else {
        result[key] = element;
      }
    }
  }
  return result;
}

注:当for...in用来遍历数组时,遍历的结果为当前元素索引值的字符串形式

for...of

break结束循环

for (const val of arr) {
  if (val === 3) {
    break;
  }
  console.log(val); // 1 2
}

continue跳过当前循环

for (const val of arr) {
  if (val === 3) {
    continue;
  }
  console.log(val); // 1 2 4 5 6
}

我们都知道for...of只能用来遍历那些内置iterator(Array, Atring, ArrayLike, Set, Map...)或者实现了@@iterator方法的数据类型,而普通的Object并没有内置iterator

这里简单说一下用for...of遍历普通对象的两种方法:

  1. 转成array
for (const [key, value] of Object.entries(obj)) {
  console.log(`${key}: ${value}`);
}
  1. 实现iterator
person[Symbol.iterator] = function () {
  let nextIndex = 0;
  const arr = Object.entries(this);
  return {
    next: function () {
      return nextIndex < arr.length
        ? {
            value: arr[nextIndex++],
            done: false,
          }
        : {
            done: true,
          };
    },
  };
};