3

拡張されるオブジェクトで実行される拡張メソッドによって実装されるポリモーフィズムをサポートするマルチレベル継承を実装したいと思います(外部ユーティリティまたは関数によってではなく、拡張されるオブジェクトの観点から)。

tl;dr jsfiddle はこちら: http://jsfiddle.net/arzo/VLkF7/

私は何をしたいですか?

var MyObj = {name: 'object', toString: function() {return this.name;}};
MyObj.extend = function(objectToBeMerged) {
    var objs=[this, objectToBeMerged],
        newobj={},
        obj;
    for(var i in objs) {
            for(var k in (obj=objs[i]) ) if (obj.hasOwnProperty(k)) newobj[k]=obj[k];
    }
    return newobj;
}
console.assert(MyObj.extend, 'ERROR: this should pass');
var ActionObj = MyObj.extend({name: 'action abstract object', exec: 'implemtation', undo: 'implementation of opposite action here'});

var DragNDrop = ActionObj.extend({name: 'drag&drop action', exec: function(){console.log('did d&d');}})
//unfortunately following assert will not get through, because MyObj.extend cannot iterate over ActionObj properties
if(DragNDrop.toString) console.info('MyObj.extend iterated over MyObj\'s properties')
console.assert(DragNDrop.undo, 'but MyObj.extend did not iterate over ActionObj properties, undo action is missing in this object:', DragNDrop)
;

上記のコードの問題は何ですか? これが通常の場合、たとえば C++ 継承の場合、 DragNDrop にはundoメソッドありますが、そうでありませんが実行されます(したがって、 ActionObj.extend を実行する場合、関数のキーワードthisがMyObjではなくActionObjに評価されるように拡張したいと思います)

この問題の解決策は、次のような jQuery.extend の _.extend を使用することです。

//add here code in previous quote in this post...
MyUtils = {}
MyUtils.extend = function(objectToBeMerged, parent) {
    var objs=[parent || this, objectToBeMerged],
        newobj={},
        obj;
    for(var i in objs) {
            for(var k in (obj=objs[i]) ) if (obj.hasOwnProperty(k)) newobj[k]=obj[k];
    }
    return newobj;
}
console.assert(MyObj && ActionObj, 'are you sure you have added code from previous block?');
var DnDAction=MyUtils.extend({name: 'drag&drop action', exec: function(){console.log('did d&d');}},ActionObj);
if (DnDAction.undo) console.info('using MyUtils.extend works fine and .undo is defined as expected in', DnDAction)
;

ただし、上記の解決策には外部ツールを使用する必要があります。MyUtilsこの場合、これは実際にはポリモーフィックな解決策ではありません

MyObj.extend を強制的に実行時に評価された (when-defining-evaluated ではない)this式で反復処理する方法を知っていますか?

4

1 に答える 1

0

アンダーコードとバックボーンのソースに基づいて解決策を見つけました(特にバックボーンはすべてのクラスに適用されるメソッドを拡張します)

var obj = {
  name: 'hi',
  getKeys: function() {
    var o=[];
    try{
      o=Array.prototype.slice.apply(this,0); //in case browser's engine is fckd up ....
    } catch (e) { //implementation feature of conerting to an array
      for(var i in this) o.push(i);
    }
    var _this=this;
    return o.map(function(i,e){return _this[i];});
  },
};

var obj2 = {
  __proto__: obj,
  extension: 'impl.',
  name: 'great hi'
};

var obj3 = {
  __proto__: obj2,
  extension: 'impl2.',
  name: 'greater hi'
};

console.assert(obj.getKeys().length!=obj2.getKeys().length, 'something went wrong, they are not equal');
console.log(obj.getKeys(), obj2.getKeys(), obj3.getKeys());

ご覧のとおり、これに対する評価は多形性で期待どおりに機能します! これは、Backbone.extend関数を使用して改善できます。

于 2014-07-16T08:45:34.610 に答える