对 Array.prototype.reduce 的 polyfill 感到困惑

Confused about polyfill of Array.prototype.reduce

此代码是 Mozilla 开发者网络上提供的 Array.prototype.reduce 的 polyfill。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {
  Array.prototype.map = function(callback /*, thisArg*/) {
    var T, A, k
    if (this == null) {
      throw new TypeError('this is null or not defined')
    }

    var O = Object(this)
    var len = O.length >>> 0

    if (typeof callback !== 'function') {
      throw new TypeError(callback + ' is not a function')
    }

    if (arguments.length > 1) {
      T = arguments[1]
    }

    A = new Array(len)
    k = 0

    while (k < len) {
      var kValue, mappedValue

      if (k in O) {
        kValue = O[k]
        mappedValue = callback.call(T, kValue, k, O)
        A[k] = mappedValue
      }
      k++
    }

    return A
  }
}

我不明白的是这两行

1.Why 不只是使用 this?

var O = Object(this)

2.Is 可能 thisnull,为什么需要下面的代码?

if (this == null) {
  throw new TypeError('this is null or not defined')
}

3.Why 我们需要 k in O?而 k < lenk 总是处于 O,这是无用状态吗?

if (k in O) {
    kValue = O[k]
    mappedValue = callback.call(T, kValue, k, O)
    A[k] = mappedValue
  }

1.Why not just use this?

var O = Object(this)

在第 3 版中,未定义或空的 thisArg 被替换为全局对象,ToObject 应用于所有其他值,结果作为 this 值传递。

所以我的猜测是这样做的原因是为了保持一致性。

2.Is it possible this be null, why need this code below?

if (this == null) {
  throw new TypeError('this is null or not defined')
}

是的,这可能为空。

使用和不使用严格模式执行以下代码。您会注意到在严格模式下输出为空,而在其他情况下它是 window.

// "use strict";
var x = function(){
    console.log(this);
    return this;
}

x.call(null);

3.Why we need k in O? while k < len, k always in O, is it useless condition?

if (k in O) {
    kValue = O[k]
    mappedValue = callback.call(T, kValue, k, O)
    A[k] = mappedValue
  }

不是无用条件,因为它会检查 属性 是否存在。(参见 in 运算符示例)

添加一个稀疏数组示例:

var a = new Array(3);
console.log(a); // [ , , ]
console.log(a.length); // 3
console.log(a[0]); // undefined