为什么 MDC 原型函数是这样编写的
Why are the MDC prototype functions written this way?
在 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;
?
var len = t.length >>> 0;
这个问题很好地涵盖了这个问题,基本上它确保数字是一个非负的 32 位 int。
至于对象构造函数:
var t = Object(this);
如果为 null 或未定义,它将返回一个空对象。 来自对象上的 MDC 文档
对象构造函数创建一个 给定值的对象包装器。如果 值为空或未定义,它 将创建并返回一个空 对象,否则,它将返回一个 对应于 给定值。
它们都只是进行纠错的快速方法。
编辑:我对thisp部分想得太辛苦了。 我假设使用参数数组是确保参数默认为 undefined 的一种方法,但无论如何他们自己这样做。迈克·霍费尔(Mike Hofer)在评论中说得对。 这是Mozilla的编码风格,用于指示可选参数。 如果将 null 或未定义作为第一个参数传入,则 Function.call 默认为全局。来自 MDC Docs on Function.call
这个Arg: 确定此内部的值 乐趣。如果 thisArg 为 null 或未定义, 这将是全局对象。 否则,这将等于 Object(thisArg) (这是这个Arg if thisArg 已经是一个对象,或者 字符串、布尔值或数字(如果此Arg) 是 的基元值 对应类型)。因此,它是 总是正确的类型这个== 函数执行时的"对象"。
var t = Object(this);
基于 ES5 规范。它明确指出this
应传递到Object
构造函数中。
如果你仔细观察ES5规范中指定的确切算法,那么Mozilla提供的方法几乎完全反映了它(它受到ES3功能的限制)。这就是这段代码似乎有一些怪癖的原因。
以下是 ES5 规范:
当用一个调用地图方法时 或两个参数,以下步骤 被采取:
- 设 O 是调用 ToObject 的结果,将此值作为参数传递。
- 让 lenValue 是使用参数 "length" 调用 O 的 [[Get]] 内部方法的结果。
- 让 len 成为 ToUint32(lenValue)。
- 如果 IsCallable(callbackfn) 为 false,则抛出 TypeError 异常。
- 如果提供了 thisArg,则让 T 是 thisArg;否则让 T 未定义。
- 设 A 是一个新数组,就像由表达式 new Array(len) 创建一样,其中 Array 是具有该名称的标准内置构造函数,len 是 len 的值。
- 设 k 为 0。
-
重复,而 k
- 设 Pk 为 ToString(k)。
- 让 kPresent 是使用参数 Pk 调用 O 的 [[HasProperty]] 内部方法的结果。
- 如果 kPresent 为真,则
- 让 kValue 是使用参数 Pk 调用 O 的 [[Get]] 内部方法的结果。
- 让 mappedValue 是调用 [[Call]] 内部方法的 callbackfn 的结果,其中 T 为包含 kValue、k 和 O 的此值和参数列表。
- 调用 A 的 [[DefineOwnProperty]] 内部方法,参数为 Pk, Property描述符 {[[Value]]: mappedValue, [[Writable]]: true, [[Enumerable]]: true,[[可配置]]:真}和假。
- 将 k 增加 1。
- 返回 A。
设 O 是调用 ToObject 的结果,将此值作为参数传递。
请注意,第一步明确表示您应该调用Object(this)
让 lenValue 成为调用的结果 O 的 [[Get]] 内部方法 参数"长度"。
让伦成为 ToUint32(lenValue).
步骤 2 和 3 特别说获取t.length
然后调用ToUint32
,此处>>> 0
实现。
规范中提到的实际签名是
Array.prototype.map ( callbackfn [ , thisArg ] )
在上面的签名中,callbackfn
是一个必需的参数,[ ]
是一个只包含一个thisArg
的可选参数数组。
Mozilla在他们的function(fun /*, thisp */) {
定义中反映了这一点,以指定thisp
是一个可选参数,很明显,从函数签名而不是查看代码来看就是这种情况。
- 使用“;这个“;JavaScript原型方法中的关键字
- 引用类变量中的原型方法
- 如何从对象的原型方法访问JavaScript对象属性
- 为什么要包装每一个原型“;类“;JS中具有匿名函数的对象
- Node.js中的JavaScript原型对象效率
- 重载JS'firefox中的对象原型
- “util.inherits”和在NodeJS中扩展原型之间的区别
- 附加到原型属性的Do函数没有闭包
- 使用方括号访问插件原型函数
- 为什么JSON.stringify没有序列化原型值
- 为什么要返回'这'在导致循环的JavaScript原型中
- 带有对象/原型的链式承诺(Q延期)
- 如何覆盖原型中的事件侦听器
- 如何在Mocha/Chai中测试JS原型(非模块)
- 我将如何将Base的原型分配给User
- 原型和用法 Javascript
- 别名或以其他方式合并两个具有不同名称的相同对象原型
- JavaScript对象不是从原型链继承的
- 得到"未定义不是函数“;使用显示原型图案时出错
- 为什么 MDC 原型函数是这样编写的