话很少说,直接看代码javascript
const arr = [1, 2, 3, 4, 5, 6];
复制代码
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循环,有的小伙伴可能会说,return不行咩。java
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源码👀markdown
/* 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循环了。app
由于咱们传入的方法,这里为if(item === 3) return
,是在for循环内部执行的,return只结束了当item === 3
所执行的fn,即return
,可是for循环仍是会继续执行。因此上面的代码log的结果是1 2 4 5 6函数
tips: 这里咱们也能够看出来forEach的返回值是void 0
,即undefined
,那么下次当咱们再听到forEach
和map
的区别是forEach没有返回值时,咱们就能够很装x的说:forEach也有返回值,只不过是undefined
,没有意义而已🌚oop
知道了怎么回事,咱们本身撸一个forEachui
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) - MDNthis
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
循环,那固然也不是没有办法,抛出错误就好了spa
try {
arr.forEach((item) => {
if (item === 3) {
throw new Error("exit foreach");
}
console.log(item); // 1 2
});
} catch (e) {}
复制代码
这里能够看一下MDN上对forEach的说明:
map与forEach相似,惟一的区别就是
map
方法会给原数组中的每一个元素都按顺序调用一次callback
函数。callback
每次执行后的返回值(包括undefined
)组合起来造成一个新数组。
这里再贴一下MDN对map的使用说明
由于map生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请用forEach或者for-of替代。你不应使用map:
A)你不打算使用返回的新数组,
B)你没有从回调函数中返回值。
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
}
复制代码
这里能够看到,key
为1
的元素比key
为name
的元素先打印了出来,
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
用来遍历数组时,遍历的结果为当前元素索引值的字符串形式
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
遍历普通对象的两种方法:
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
复制代码
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,
};
},
};
};
复制代码