我正在浏览MooTools来源,尝试了解其.implement()
和.extend()
实用程序。
每个的定义指的是这样定义的函数:
var enumerables = true;
for (var i in {toString: 1}) enumerables = null;
if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
Function.prototype.overloadSetter = function(usePlural){
var self = this;
return function(a, b){
if (a == null) return this;
if (usePlural || typeof a != 'string'){
for (var k in a) self.call(this, k, a[k]);
if (enumerables) for (var i = enumerables.length; i--;){
k = enumerables[i];
if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
}
} else {
self.call(this, a, b);
}
return this;
};
};
然而,我很难理解它的作用。
你能解释一下这个功能是如何运作的吗?
答案 0 :(得分:29)
<强> overloadSetter 强>
overloadSetter
和overloadGetter
一起是两个函数装饰器方法。 overloadSetter
函数用于将具有签名fn(key, value)
的函数转换为可以接受对象参数的函数,即:fn({key: value})
。
为了做到这一点,overloadSetter
必须包装原始函数。此包装函数具有签名fn(a, b)
,这是fn(key, value)
的快捷方式。这实际上成为原始函数的新重载版本。
这个重载函数的第一件事是检查传递的key
参数(a
)是否属于字符串类型。如果它不是字符串,则该函数假定我们正在传递一个对象。因此,它迭代对象中的每个键值对并将原始函数应用于它。另一方面,如果它是一个字符串,它只是将函数应用于a
和b
参数的值。
示例强>
为了说明,假设我们有以下功能:
var fnOrig = function(key, value){
console.log(key + ': ' + value);
};
var fnOver = fnOrig.overloadSetter();
fnOver('fruit', 'banana');
fnOver({'fruit': 'banana', 'vegetable': 'carrot'});
在第一次调用中,使用两个参数(键和值)调用fnOver
函数。当函数检查a
参数值的类型时,它会看到它是一个字符串。因此,它只会调用原始fnOrig
函数:fnOrig.call(this, 'fruit', 'banana')
。我们的控制台输出为'fruit: banana'
。
对于第二次调用,使用object参数调用fnOver
函数。由于我们传递了一个对象而不是一个字符串,fnOver
将遍历该对象的成员并为每个对象调用fnOrig
函数。因此,在这种情况下,fnOrig
将被调用两次:fnOrig.call(this, 'fruit', 'banana')
和fnOrig.call(this, 'vegetable', 'carrot')
。我们的控制台输出为'fruit: banana'
和'vegetable: carrot'
。
<强>附加功能强>
在包装函数中,您将看到检查usePlural
的值。这是overloadSetter
方法本身的参数。如果将此值设置为true
,则新函数会将所有参数视为对象。这意味着即使您传递字符串键参数,它仍将作为对象处理。
另一方面,排除了实际方法声明的enumerables
代码,因为它解决了某些浏览器的问题,其中Object
循环中未枚举本机for/in
方法即使对象本身实现了它自己的版本。
答案 1 :(得分:3)
让我挠了一会儿的部分是
var enumerables = true; for (var i in {toString: 1}) enumerables = null;
部分,结果证明是对某些浏览器所具有的DontEnum错误的测试。乍一看似乎应该将enumerables
设置为null
,但是DontEnum错误toString
被抑制(错误地,因为对象的prototype.toString
具有{{1}标记)和DontEnum
保留为enumerables
。
true
(或者更确切地说是结果函数)然后必须一次检查一个DontEnum bug影响的七个属性,看看它们是否存在于object参数中。