You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
// 如果 Array.prototype.forEach 没有定义的话
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback/*, thisArg*/) {
// T 为 callback 的指向, 如果指定的话, 看 step-5
// k 为 循环的索引
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
// 1. Let O be the result of calling toObject() passing the
// |this| value as the argument.
// @see https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
// Object构造函数为给定值创建一个对象包装器。如果给定值是 null 或 undefined,将会创建并返回一个空对象,否则,将返回一个与给定值对应类型的对象。
// 当以非构造函数形式被调用时,Object 等同于 new Object()。
var O = Object(this);
// 2. Let lenValue be the result of calling the Get() internal
// method of O with the argument "length".
// 3. Let len be toUint32(lenValue).
// @see https://stackoverflow.com/questions/8286925/whats-array-length-0-used-for
// 保证 len 为一个小于 2^32 的整数
// 这里需要注意, step-7 的终止条件是 k < len;
// 所以, forEach 遍历的范围在第一次调用 callback 前就会确定
var len = O.length >>> 0;
// 4. If isCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
// 保证 callback 是个函数
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let
// T be undefined.
if (arguments.length > 1) {
T = arguments[1];
}
// 6. Let k be 0.
k = 0;
// 7. Repeat while k < len.
while (k < len) {
// 第 k 项
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator.
// b. Let kPresent be the result of calling the HasProperty
// internal method of O with argument Pk.
// This step can be combined with c.
// c. If kPresent is true, then
// 保证 k 这个索引是 O 的属性
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
// 赋值
kValue = O[k];
// ii. Call the Call internal method of callback with T as
// the this value and argument list containing kValue, k, and O.
// 调用 callback, T 为 callback 绑定的 this, 参数分别是 item, index, 和 array 本身
callback.call(T, kValue, k, O);
}
// d. Increase k by 1.
k++;
}
// 8. return undefined.
};
}
刚刚说的两条分别对应
step-3
// 3. Let len be toUint32(lenValue).
var len = O.length >>> 0;
和 step-7-c
if (k in O)
回到第一题
var a = [1, 2, 3, 1, 2, 3];
a.forEach((item, index) => {
console.log(index, item);
if (item === 1) {
a.splice(index, 1);
}
});
1. a = [1,2,3,1,2,3]; len = 6
2. k = 0; console.log(0, 1);
3. splice(0, 1) ---> a = [2,3,1,2,3]
4. k = 1; console.log(1, 3);
5. k = 2; console.log(2, 1);
6. splice(2, 1) ---> a = [2,3,2,3];
7. k = 3; console.log(3, 3);
8. k = 4; k not in a;
9. k = 5; k not in a;
原文链接
事情的起源是这样的, 同事发给我两段代码, 如下:
其实这样的事情在我们平常写代码的时候也经常发生,
如果这个改成 for 循环, 或许完全不一样. 那么
forEach
的callback
到底执行了多少次呢?这样的事情当然要看规范了, Array.prototype.forEach() 中文
这里面感觉最重要的是:
看不懂? show me the code
刚刚说的两条分别对应
step-3
和 step-7-c
回到第一题
第二题比较简单, 新添加的两个 1 都不会遍历
所以两种情况的 while 循环都是 6 次
但是第一种由于
'4'
'5'
都不在 array 里面, 所以 callback 只执行了 4 次第二种情况 callback 执行了 6 次
好啦, 你听明白了嘛~
参考资料
The text was updated successfully, but these errors were encountered: