2012-08-02 17 views
9

これはJavaScriptの達人にとっての質問です。私はJavaScriptプロトタイプモデルでより洗練された作業をしようとしています。ここに私のユーティリティコードは(それはプロトタイプとのinstanceof演算子で正しい仕事の本当のチェーンを提供します)です:JavaScriptプロトタイプ継承(プロトタイプのチェーン)

function Class(conf) { 
    var init = conf.init || function() {}; 
    delete conf.init; 

    var parent = conf.parent || function() {}; 
    delete conf.parent; 

    var F = function() {}; 
    F.prototype = parent.prototype; 
    var f = new F(); 
    for (var fn in conf) f[fn] = conf[fn]; 
    init.prototype = f; 

    return init; 
}; 

それは私がこのようなthignsを行うことができます:

var Class_1 = new Class({ 
    init: function (msg) { // constructor 
    this.msg = msg; 
    }, 

    method_1: function() { 
    alert(this.msg + ' in Class_1::method_1'); 
    }, 

    method_2: function() { 
    alert(this.msg + ' in Class_1::method_2'); 
    } 
}); 

var Class_2 = new Class({ 
    parent: Class_1, 

    init: function (msg) { // constructor 
    this.msg = msg; 
    }, 

    // method_1 will be taken from Class_1 

    method_2: function() { // this method will overwrite the original one 
    alert(this.msg + ' in Class_2::method_2'); 
    }, 

    method_3: function() { // just new method 
    alert(this.msg + ' in Class_2::method_3'); 
    } 
}); 

var c1 = new Class_1('msg'); 
c1.method_1(); // msg in Class_1::method_1 
c1.method_2(); // msg in Class_1::method_2 

var c2 = new Class_2('msg'); 
c2.method_1(); // msg in Class_1::method_1 
c2.method_2(); // msg in Class_2::method_2 
c2.method_3(); // msg in Class_2::method_3 

alert('c1 < Class_1 - ' + (c1 instanceof Class_1 ? 'true' : 'false')); // true 
alert('c1 < Class_2 - ' + (c1 instanceof Class_2 ? 'true' : 'false')); // false 

alert('c2 < Class_1 - ' + (c2 instanceof Class_1 ? 'true' : 'false')); // true 
alert('c2 < Class_2 - ' + (c2 instanceof Class_2 ? 'true' : 'false')); // true 

私の質問がある:ありこれを行うより簡単な方法?

+0

http://codereview.stackexchange.com/ –

+1

[John Resig](http://ejohn.org/blog/simple-javascript-inheritance/)のクラス継承の非常に良い例があります。これはスーパーやその他のグッズを提供します。 – elclanrs

+0

これは興味深いかもしれません:http://ejohn.org/apps/learn/ –

答えて

0

いくつかの研究の後、私はこれを行うには、より簡単な方法がないと結論付けました。

0

はい、これを行うより良い方法があります。

var call = Function.prototype.call; 

var classes = createStorage(), 
    namespaces = createStorage(), 
    instances = createStorage(createStorage); 


function createStorage(creator){ 
    var storage = new WeakMap; 
    creator = typeof creator === 'function' ? creator : Object.create.bind(null, null, {}); 
    return function store(o, v){ 
    if (v) { 
     storage.set(o, v); 
    } else { 
     v = storage.get(o); 
     if (!v) { 
     storage.set(o, v = creator(o)); 
     } 
    } 
    return v; 
    }; 
} 

function Type(){ 
    var self = function(){} 
    self.__proto__ = Type.prototype; 
    return self; 
} 

Type.prototype = Object.create(Function, { 
    constructor: { value: Type, 
       writable: true, 
       configurable: true }, 
    subclass: { value: function subclass(scope){ return new Class(this, scope) }, 
       configurable: true, 
       writable: true } 
}); 

function Class(Super, scope){ 
    if (!scope) { 
    scope = Super; 
    Super = new Type; 
    } 

    if (typeof Super !== 'function') { 
    throw new TypeError('Superconstructor must be a function'); 
    } else if (typeof scope !== 'function') { 
    throw new TypeError('A scope function was not provided'); 
    } 

    this.super = Super; 
    this.scope = scope; 

    return this.instantiate(); 
} 

Class.unwrap = function unwrap(Ctor){ 
    return classes(Ctor); 
}; 

Class.prototype.instantiate = function instantiate(){ 
    function super_(){ 
    var name = super_.caller === Ctor ? 'constructor' : super_.caller.name; 
    var method = Super.prototype[name]; 

    if (typeof method !== 'function') { 
     throw new Error('Attempted to call non-existent supermethod'); 
    } 

    return call.apply(method, arguments); 
    } 

    var Super = this.super, 
     namespace = namespaces(Super), 
     private = instances(namespace) 

    var Ctor = this.scope.call(namespace, private, super_); 
    Ctor.__proto__ = Super; 
    Ctor.prototype.__proto__ = Super.prototype; 
    namespaces(Ctor, namespace); 
    classes(Ctor, this); 
    return Ctor; 
} 

使用例:

var Primary = new Class(function(_, super_){ 
    var namespace = this; 
    namespace.instances = 0; 

    function Primary(name, secret){ 
    this.name = name; 
    _(this).secret = secret; 
    namespace.instances++; 
    } 

    Primary.prototype.logSecret = function logSecret(label){ 
    label = label || 'secret'; 
    console.log(label + ': ' + _(this).secret); 
    } 

    return Primary; 
}); 


var Derived = Primary.subclass(function(_, super_){ 

    function Derived(name, secret, size){ 
    super_(this, name, secret); 
    this.size = size; 
    } 

    Derived.prototype.logSecret = function logSecret(){ 
    super_(this, 'derived secret'); 
    } 

    Derived.prototype.exposeSecret = function exposeSecret(){ 
    return _(this).secret; 
    } 

    return Derived; 
}); 

var Bob = new Derived('Bob', 'is dumb', 20); 
Bob.logSecret(); 
console.log(Bob); 
console.log(Bob.exposeSecret()); 
+0

スーパープロパティとプライベートプロパティの操作 –

関連する問題