【问题标题】:Why are the MDC prototype functions written this way?为什么 MDC 原型函数是这样写的?
【发布时间】:2011-05-11 18:49:40
【问题描述】:

在 MDC 中有大量代码 sn-ps 用于在不支持它们的浏览器中实现对新 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 &gt;&gt;&gt; 0; 而不是 var len = t.length;

【问题讨论】:

    标签: javascript


    【解决方案1】:
    var len = t.length >>> 0;    
    

    this question 很好地涵盖了这一点,基本上它确保该数字是非负的 32 位整数。

    至于 Object 构造函数:

    var t = Object(this);
    

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

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

    它们都是快速纠正错误的方法。

    编辑:我对 thisp 部分想得太认真了。我假设使用参数数组是一种确保参数默认为未定义的方法,但无论如何它们都是自己做的。 Mike Hofer 在 cmets 中做对了。表示可选参数是 Mozilla 的编码风格。如果 null 或 undefined 作为第一个参数传入,则 Function.call 默认为 global。来自MDC Docs on Function.call

    这个参数: 确定 this 里面的值 乐趣。如果 thisArg 为 null 或未定义, this 将是全局对象。 否则,this 将等于 Object(thisArg) (如果 thisArg 已经是一个对象,或者一个 如果 thisArg,则为字符串、布尔值或数字 是的原始值 对应类型)。因此它是 typeof this == 总是正确的 函数执行时的“对象”。

    【讨论】:

    • 谢谢! (但你知道function(fun, thisp) 的员工吗?)
    • 是的,我刚刚意识到我错过了,稍后编辑。
    • function(fun /*, thisp */) 是一个编码 style,表示 thisp 是一个可选参数。 fun,当然是后来使用fun.call调用的委托函数,将thisp作为“上下文”传递(即函数执行时会变成this的值)。
    • @Mike-Hofner 谢谢,我想太多了:/
    【解决方案2】:

    var t = Object(this);

    基于 ES5 规范。它特别声明this 应该被传递到Object 构造函数中。

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

    这是 ES5 规范:

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

    1. 令 O 为调用 ToObject 并将 this 值作为参数传递的结果。
    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

      1. 令 Pk 为 ToString(k)。
      2. 设 kPresent 为使用参数 Pk 调用 O 的 [[HasProperty]] 内部方法的结果。
      3. 如果 kPresent 为真,则
        • 设 kValue 为使用参数 Pk 调用 O 的 [[Get]] 内部方法的结果。
        • 设 mappedValue 为调用 callbackfn 的 [[Call]] 内部方法的结果,其中 T 为 包含 kValue、k 和 O 的 this 值和参数列表。
        • 使用参数 Pk、Property 调用 A 的 [[DefineOwnProperty]] 内部方法 描述符 {[[Value]]: mappedValue, [[Writable]]: true, [[Enumerable]]: true, [[可配置]]:真},假。
        • 将 k 增加 1。
    9. 返回 A。

    令 O 为调用 ToObject 并将 this 值作为参数传递的结果。

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

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

    让 len 成为 ToUint32(lenValue)。

    第 2 步和第 3 步具体说 get t.length 然后调用 ToUint32,在此处实现为 &gt;&gt;&gt; 0

    规范中提到的实际签名是

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 2019-06-05
      • 2015-05-04
      • 1970-01-01
      相关资源
      最近更新 更多