为什么MDC原型函数以这种方式编写?

时间:2011-05-11 18:49:40

标签: javascript

在MDC中,有大量代码片段旨在在不支持它们的浏览器中实现对新ECMAScript标准的支持,例如Array.prototype.map函数:

if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        res[i] = fun.call(thisp, t[i], i, t);
    }

    return res;
  };
}

使用此功能而不是

有什么好处(如果有的话)
function(fun, thisp)
{
  // same code, just without the "var thisp = arguments[1];" line:
  "use strict";

  if (this === void 0 || this === null)
    throw new TypeError();

  var t = Object(this);
  var len = t.length >>> 0;
  if (typeof fun !== "function")
    throw new TypeError();

  var res = new Array(len);
  for (var i = 0; i < len; i++)
  {
    if (i in t)
      res[i] = fun.call(thisp, t[i], i, t);
  }

  return res;
}

var t = Object(this);而不是var t = this;var len = t.length >>> 0;而不是var len = t.length;

2 个答案:

答案 0 :(得分:7)

var len = t.length >>> 0;    

this question中很好地介绍了它。基本上它确保数字是非负32位int。

至于Object构造函数:

var t = Object(this);

如果为null或未定义,它将返回一个空对象。来自MDC Docs on Object

  

Object构造函数创建一个   给定值的对象包装器。如果   它的值为null或undefined   将创建并返回一个空的   对象,否则,它将返回一个   对应的类型的对象   给定的价值。

他们只是快速纠正错误的方法。

编辑:我对thisp部分的思考太过分了。我假设使用arguments数组是一种确保参数默认为undefined的方法,但无论如何他们都是这样做的。 Mike Hofer在评论中说得对。这是Mozilla的编码风格,用于指示可选参数。如果将null或undefined作为第一个参数传入,则Function.call默认为global。来自MDC Docs on Function.call

  

thisArg:   确定内部的值   乐趣。如果thisArg为null或未定义,   将成为全局对象。   否则,将等于   对象(thisArg)(这是thisArg如果   thisArg已经是一个对象,或者一个   如果thisArg,则为String,Boolean或Number   是一个原始的价值   相应的类型)。因此它是   总是那个这个 ==的类型   函数执行时的“对象”。

答案 1 :(得分:3)

var t = Object(this);

基于ES5规范。它明确指出this应该传递给Object构造函数。

如果仔细观察ES5规范中指定的确切算法,那么Mozilla提供的方法几乎完全反映它(它受ES3功能的限制)。这就是这段代码似乎有些怪癖的原因。

这是ES5规范:

  

使用一个方法调用map方法时   或两个参数,以下步骤   采取:

  1. 设O是调用ToObject传递此值作为参数的结果。
  2. 让lenValue成为使用参数“length”调用O的[[Get]]内部方法的结果。
  3. 设len为ToUint32(lenValue)。
  4. 如果IsCallable(callbackfn)为false,则抛出TypeError异常。
  5. 如果提供thisArg,则让T为thisArg;否则让T不确定。
  6. 设A是一个新的数组,就像表达式new Array(len)一样,其中Array是具有该名称的标准内置构造函数,len是len的值。
  7. 设k为0.
  8. 重复,而k < LEN

    1. 设Pk为ToString(k)。
    2. 设kPresent是用参数Pk调用O的[[HasProperty]]内部方法的结果。
    3. 如果kPresent为真,那么
      • 让kValue成为用参数Pk调用O的[[Get]]内部方法的结果。
      • 让mappedValue成为调用callbackfn的[[Call]]内部方法的结果,其中T为 此值和参数列表包含kValue,k和O.
      • 使用参数Pk,Property调用A的[[DefineOwnProperty]]内部方法 描述符{[[Value]]:mappedValue,[[Writable]]:true,[[Enumerable]]:true, [[Configurable]]:true},false。
      • 将k增加1.
  9. 返回A.
  10.   

    设O是调用ToObject传递此值作为参数的结果。

    请注意,第一步明确说明您应该致电Object(this)

      

    让lenValue成为调用的结果   O的[[Get]]内部方法   论证“长度”。

         

    让len成为   ToUint32(lenValue)。

    第2步和第3步具体说得到t.length,然后在此处调用ToUint32 >>> 0

    规范中提到的实际签名是

      

    Array.prototype.map(callbackfn [,thisArg])

    在上面的签名中callbackfn是必需参数,[ ]是一个可选参数数组,只包含一个thisArg

    Mozilla在function(fun /*, thisp */) {的定义中反映了这一点,以指定thisp是一个可选参数,很明显这是函数签名的情况,而不是查看代码。