当前位置:K88软件开发文章中心编程语言JavaScriptECMAScript → 文章内容

读懂 ECMAScript 规格

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 15:38:45

e to the length of the Array.”翻译如下。"数组成员可以省略。只要逗号前面没有任何表达式,数组的length属性就会加1,并且相应增加其后成员的位置索引。被省略的成员不会被定义。如果被省略的成员是数组最后一个成员,则不会导致数组length属性增加。”上面的规格说得很清楚,数组的空位会反映在length属性,也就是说空位有自己的位置,但是这个位置的值是未定义,即这个值是不存在的。如果一定要读取,结果就是undefined(因为undefined在JavaScript语言中表示不存在)。这就解释了为什么in运算符、数组的hasOwnProperty方法、Object.keys方法,都取不到空位的属性名。因为这个属性名根本就不存在,规格里面没说要为空位分配属性名(位置索引),只说要为下一个元素的位置索引加1。至于为什么数组的map方法会跳过空位,请看下一节。数组的map方法规格的22.1.3.15小节定义了数组的map方法。该小节先是总体描述map方法的行为,里面没有提到数组空位。后面的算法描述是这样的。Let O be ToObject(this value).ReturnIfAbrupt(O).Let len be ToLength(Get(O, "length")).ReturnIfAbrupt(len).If IsCallable(callbackfn) is false, throw a TypeError exception.If thisArg was supplied, let T be thisArg; else let T be undefined.Let A be ArraySpeciesCreate(O, len).ReturnIfAbrupt(A).Let k be 0.Repeat, while k < len a. Let Pk be ToString(k). b. Let kPresent be HasProperty(O, Pk). c. ReturnIfAbrupt(kPresent). d. If kPresent is true, then d-1. Let kValue be Get(O, Pk). d-2. ReturnIfAbrupt(kValue). d-3. Let mappedValue be Call(callbackfn, T, ?kValue, k, O?). d-4. ReturnIfAbrupt(mappedValue). d-5. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue). d-6. ReturnIfAbrupt(status). e. Increase k by 1.Return A.翻译如下。得到当前数组的this对象如果报错就返回求出当前数组的length属性如果报错就返回如果map方法的参数callbackfn不可执行,就报错如果map方法的参数之中,指定了this,就让T等于该参数,否则T为undefined生成一个新的数组A,跟当前数组的length属性保持一致如果报错就返回设定k等于0只要k小于当前数组的length属性,就重复下面步骤 a. 设定Pk等于ToString(k),即将K转为字符串 b. 设定kPresent等于HasProperty(O, Pk),即求当前数组有没有指定属性 c. 如果报错就返回 d. 如果kPresent等于true,则进行下面步骤 d-1. 设定kValue等于Get(O, Pk),取出当前数组的指定属性 d-2. 如果报错就返回 d-3. 设定mappedValue等于Call(callbackfn, T, ?kValue, k, O?),即执行回调函数 d-4. 如果报错就返回 d-5. 设定status等于CreateDataPropertyOrThrow (A, Pk, mappedValue),即将回调函数的值放入A数组的指定位置 d-6. 如果报错就返回 e. k增加1返回A仔细查看上面的算法,可以发现,当处理一个全是空位的数组时,前面步骤都没有问题。进入第10步的b时,kpresent会报错,因为空位对应的属性名,对于数组来说是不存在的,因此就会返回,不会进行后面的步骤。const arr = [, , ,];arr.map(n => { console.log(n); return 1;}) // [, , ,]上面代码中,arr是一个全是空位的数组,map方法遍历成员时,发现是空位,就直接跳过,不会进入回调函数。因此,回调函数里面的console.log语句根本不会执行,整个map方法返回一个全是空位的新数组。V8引擎对map方法的实现如下,可以看到跟规格的算法描述完全一致。function ArrayMap(f, receiver) { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map"); // Pull out the length so that modifications to the length in the // 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); return result;}

上一页  [1] [2] 


读懂 ECMAScript 规格