实现改变原型,那么为什么不只是用'some class'.prototype来改变目录......,这似乎很没用或废话
2 回答
您可以查看 MooTools 源代码或检查控制台中的 MooTools 对象,以查看它在implement()
被调用时在后台执行的操作。
在 MooTools 1.4.5 中,它是这样做的:
function (key, value){
if ($type(key) == 'object'){
for (var p in key) this.implement(p, key[p]);
return this;
}
var mutator = Class.Mutators[key];
if (mutator){
value = mutator.call(this, value);
if (value == null) return this;
}
var proto = this.prototype;
switch ($type(value)){
case 'function':
if (value._hidden) return this;
proto[key] = Class.wrap(this, key, value);
break;
case 'object':
var previous = proto[key];
if ($type(previous) == 'object') $mixin(previous, value);
else proto[key] = $unlink(value);
break;
case 'array':
proto[key] = $unlink(value);
break;
default: proto[key] = value;
}
return this;
}
如您所见,其中肯定有一些额外的逻辑。例如,您似乎可以传递具有相应属性名称的对象,key
并value
让它在一次调用中向对象原型添加多个东西。
implement()
除非您非常确定自己知道自己在做什么,否则我会使用并避免将内容直接添加到原型链中。毫无疑问,这些额外的东西是有原因的。
有两个方面要实施。在类上下文和对象(类型/本地)上。
共同利益
它们之间的共同点是,它们是 API。因为它是 API,所以 MooTools 可以添加一些方法来确保您不会(意外)覆盖受各种 Native 类型保护的原型方法。请参阅强制保护许多本机方法的这一位:https ://github.com/mootools/mootools-core/blob/master/Source/Core/Core.js#L238-282
此外,implement 是重载的——这意味着您可以传递一个同时实现多个方法的对象,而不是中断并为每个原型调用创建一个新行。
类中的函数方法被包装。
这些装饰器可用:
Function.implement({
hide: function(){
this.$hidden = true;
return this;
},
protect: function(){
this.$protected = true;
return this;
}
});
这意味着你可以做
Obj.implement({
foo: foo.hide(),
bar: bar.protect()
});
这允许您通过.hide()
添加未包装的属性来使用未包装的方法:
Number.prototype.$family = function(){
return isFinite(this) ? 'number' : 'null';
}.hide();
.protect()
由 Class 使用,见下文。
这并不意味着你不能做Number.prototype.$family = somethingElse
——你可以。
类的细节
在类构造函数上使用implement
时,请注意对 的引用$hidden
和调用wrap()
:
var implement = function(key, value, retain){
if (Class.Mutators.hasOwnProperty(key)){
value = Class.Mutators[key].call(this, value);
if (value == null) return this;
}
if (typeOf(value) == 'function'){
if (value.$hidden) return this;
this.prototype[key] = (retain) ? value : wrap(this, key, value);
} else {
Object.merge(this.prototype, key, value);
}
return this;
};
这意味着当你传递一个函数时,它会被自动包装 - 包装使你可以通过.protect()
装饰器拥有私有方法或通过.hide()
它还支持 Class Mutators - 你应该检查这个,但它能够定义可以修改构造函数的特殊键,而不是仅仅添加到原型中。
再一次,您可以轻松地做到:
ClassConstructor.prototype.foo = someFn;
这将起作用。
// but:
ClassConstructor.prototype.foo = someFn.protect();
// however...
instanceOfClassconstructor.foo(); // works also.
看到这个:
// generic method.
var foo = function() {
console.log('hi');
};
var ClassConstructor = new Class({});
// implement the foo method as private.
ClassConstructor.implement({
foo: foo.protect()
});
var instance = new ClassConstructor();
// try to call it, will throw.
try {
instance.foo();
}
catch(e) {
console.warn(e);
}
// do it directly on the prototype
ClassConstructor.prototype.foo = foo.protect();
var instance2 = new ClassConstructor();
instance2.foo(); // works.