后面的算法描述是这样的。
- 得到当前数组的
this
对象- 求出当前数组的
length
属性- 如果报错就返回
- 如果 map 方法的参数
callbackfn
不可执行,就报错- 如果 map 方法的参数之中,指定了
this
,就让T
等于该参数,否则T
为undefined
- 生成一个新的数组
A
,跟当前数组的length
属性保持一致- 如果报错就返回
- 设定
k
等于 0- 只要
k
小于当前数组的length
属性,就重复下面步骤
- 设定
Pk
等于ToString(k)
,即将K
转为字符串- 设定
kPresent
等于HasProperty(O, Pk)
,即求当前数组有没有指定属性- 如果报错就返回
- 如果
kPresent
等于true
,则进行下面步骤
- 设定
kValue
等于Get(O, Pk)
,取出当前数组的指定属性- 如果报错就返回
- 设定
mappedValue
等于Call(callbackfn, T, «kValue, k, O»)
,即执行回调函数- 如果报错就返回
- 设定
status
等于CreateDataPropertyOrThrow (A, Pk, mappedValue)
,即将回调函数的值放入A
数组的指定位置- 如果报错就返回
k
增加 1- 返回
仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第 10 步中第 2 步时,kPresent
会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。
V8 引擎对map
方法的如下,可以看到跟规格的算法描述完全一致。
function ArrayMap(f, receiver) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
// loop will not affect the looping and side effects are visible.
var array = TO_OBJECT(this);
var length = TO_LENGTH_OR_UINT32(array.length);
return InnerArrayMap(f, receiver, array, length);
}
function InnerArrayMap(f, receiver, array, length) {
if (!IS_CALLABLE(f)) throw MakeTypeError(kCalledNonCallable, f);
var accumulator = new InternalArray(length);
var is_array = IS_ARRAY(array);
var stepping = DEBUG_IS_STEPPING(f);
for (var i = 0; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
accumulator[i] = %_Call(f, receiver, element, i, array);
}
}
var result = new GlobalArray();
%MoveArrayContents(accumulator, result);