Javascript在polyfills中的对象(this)用法?



我在这里看到 Array.prototype.forEach()的polyfill,我对它的实现有一个问题:

/*1*/   if (!Array.prototype.forEach)
/*2*/   {
/*3*/     Array.prototype.forEach = function(fun /*, thisArg */)
/*4*/     {
/*5*/       "use strict";
/*6*/   
/*7*/       if (this === void 0 || this === null)
/*8*/         throw new TypeError();
/*9*/   
/*10*/       var t = Object(this);
/*11*/       var len = t.length >>> 0;
/*12*/       if (typeof fun !== "function")
/*13*/         throw new TypeError();
/*14*/   
/*15*/       var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
/*16*/       for (var i = 0; i < len; i++)
/*17*/       {
/*18*/         if (i in t)
/*19*/           fun.call(thisArg, t[i], i, t);
/*20*/       }
/*21*/     };
/*22*/   }

看第10行:为什么他们使用Object(this) ?

当我搜索它的用法时,我看到了这个:

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

所以他们想检查一下是不是null || undefined

好的,但是他们已经在#7-#8行检查过了!

问题:

他们使用Object(this)的原因是什么(我错过了)?

所以他们想检查它是否为null || undefined

。目的是

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

将原语转换为对象,如"foo"转换为new String("foo")

严格来说,这是没有必要的,因为.length的属性访问和索引无论如何都会将原语转换为对象。但是,当使用第三个回调参数时,可能会有一个对象(并且每次调用都是相同的对象)。

他们使用Object(this)的原因是什么?

主要是为了重现forEach规范的第1步,即在参数上调用ToObject。在规范中,这需要能够在其上使用[[Get]][[HasProperty]]内部方法。

同样,通过只在获得速度时将原语转换为对象

我正在搜索这个问题,因为我不知道自己为什么会这样。目前的正确答案并没有让我百分之百满意。所以我试图执行代码,如果我删除对象(this),只是做var O = this;forEach函数的定义在这里:ECMAScript forEach。所以你可以看到为什么要创建变量和它们的名字等等。polyfil试图尽可能精确。

由于OP只想知道对象(this),所以我将重点关注它。我找到了需要这个的原因。试试下面的代码:

Array.prototype.forEach.call("abc", func);

基本上是循环遍历abc字符串。对象(this)使abc变为:

String {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}

如果我们不这样做,abc将只是普通的"abc"。然后在填充循环中我们这样做:

kValue = O[k];

在"abc"字符串的情况下,这将获得字符串的每个字母。但这将不起作用,并将在IE <8上显示未定义。

为什么这不起作用,在这句话中解释了其他问题:这个符号在IE7中不起作用。第一个代码片段将在IE7中返回undefined。如果你碰巧在你的代码中对字符串都使用括号符号,并且你想要迁移到。charat (pos),这是一个真正的痛苦:括号在你的代码中被使用,并且没有简单的方法来检测它是用于字符串还是数组/对象。"(源)

但是当使用Object(this)时,这就没有问题了。

另一个我觉得很方便的引语:

" forEach函数故意是泛型的;它不要求它的this值是一个Array对象。因此,它可以作为一种方法转移到其他类型的对象中使用。forEach函数能否成功应用于宿主对象取决于实现。(源)

目的不是检查未定义。相反,它是处理原语。

例如,如果this是一个数字,例如42,那么它就是Object(42),它是一个值为42Number对象。

这意味着从那时起你可以像对待对象一样对待输入,即使它最初是一个原语。

要测试,请尝试在字符串上使用polyfill -字符串具有.length属性。例如,尝试…

[].forEach.call("Hello!",function(letter) {console.log(letter);});

最新更新