【问题标题】:In MooTools, what's the difference between .implement and .prototype在 MooTools 中,.implement 和 .prototype 有什么区别
【发布时间】:2012-07-29 00:03:27
【问题描述】:

实现改变原型,为什么不直接用'some class'.prototype来改变目录...,看起来很没用或废话

【问题讨论】:

  • 不知道在哪里可以找到文档
  • 有这个网站,Google,它将改变世界。
  • 如果您懒得去Google 获取文档,我们为什么要麻烦您?

标签: javascript mootools


【解决方案1】:

有两个方面需要实施。在类上下文和对象(类型/本地)上。

共同的好处

它们之间的共同点是,它们都是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.

【讨论】:

    【解决方案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;
    
    }
    

    如您所见,其中肯定有一些额外的逻辑。例如,您似乎可以为keyvalue 传递具有相应属性名称的对象,以使其实现一次调用向对象原型添加多个内容。

    我会使用implement() 并避免将东西直接添加到原型链中,除非您非常确定自己知道自己在做什么。毫无疑问,这些额外的东西是有原因的。

    【讨论】:

      猜你喜欢
      • 2019-11-29
      • 1970-01-01
      • 2013-12-01
      • 2011-01-05
      • 2021-11-29
      • 2011-04-26
      • 2012-03-16
      • 2012-10-29
      • 1970-01-01
      相关资源
      最近更新 更多