Непереносимость Javascript и использование супер: возможно ли это? - PullRequest
4 голосов
/ 25 декабря 2010
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {
        }

        F.prototype = o;
        var f = new F();

        if(f.init){
            f.init();
        };

        return f;
    };
}

var inherit = function(P, C) {
    var i;
    for(i in P) {
        // if is the current parent
        if(P.hasOwnProperty(i) === false) {
            continue;
        };

        // define the uper property
        C.uper = {};

        // methods
        if(typeof P[i] === 'function') {
            // set as super
            C.uper[i] = P[i];
            // if child already defined, skip
            if(typeof C[i] === 'function') {
                continue;
            };
            C[i] = P[i];
        }

        // properties 
        else {
            // if child already defined a property, skip
            if(!(typeof C[i] === 'undefined')) {
                continue;
            };
            C[i] = P[i];
        }
    }
    return C;
}


var Parent1 = (function(){
    var that = {};

    // private var
    var _name = 'Parent1';

    // public var
    that.lastName = 'LastName';

    // public method
    that.getName = function(){
        // if this.uper.getName.call(this)
        return _name + this.lastName;
        // else
        // return _name + that.lastName;
    }

    // return the literal object
    return that;
}());

var Parent2 = {
    // fake private var
    _name: 'Parent2',

    // public method
    getName: function(){
        // as we call this method with the call method
        // we can use this
        return this._name;
    }
}

var Child1 = inherit(Parent1, (function(){
    var that = {};

    // overriden public method
    that.getName = function(){
        // how to call the this.uper.getName() like this?
        return 'Child 1\'s name: ' + this.uper.getName.call(this);
    }

    that.init = function(){
        console.log('init');
    }

    // return the literal object
    return that;
}()));

var Child2 = inherit(Parent2, {
    getName: function(){
        // how to call the this.uper.getName() like this?
        return 'Child 2\'s name: ' + this.uper.getName.call(this);
    }
});

var child1 = Object.create(Child1);
// output: Child 1's name: Parent1LastName
console.log(child1.getName());

var child2 = Object.create(Child2);
// output: Child 2's name: Parent2
console.log(child2.getName());
// how to call the this.uper.getName() like this?

как вызвать this.uper.getName () следующим образом?

Ответы [ 2 ]

7 голосов
/ 25 декабря 2010

Да

Javascript использует Прототип наследования . Таким образом, по существу объекты наследуют объекты (и все является объектом)

Вот пара ссылок, которые должны помочь понять суть.

Вот базовый шаблон модуля:

var MODULE = (function (my) { 
    my.anotherMethod = function () { 
        // added method... 
    }; 

    return my; 
}(MODULE));

Тогда вы можете сделать что-то вроде этого, чтобы имитировать наследование:

var MODULE_TWO = (function (old) { 
    var my = {}, 
        key; 

    for (key in old) { 
        if (old.hasOwnProperty(key)) { 
            my[key] = old[key]; 
        } 
    } 

    var super_moduleMethod = old.moduleMethod; 
    my.moduleMethod = function () { 
        // override method on the clone, access to super through super_moduleMethod 
    }; 

    return my; 
}(MODULE));

Этот стиль кодирования требует некоторого привыкания, но я определенно предпочитаю его классическому наследованию. Если этот код не имеет смысла, прочитайте лекции Дугласа Крокфорда , и он должен прояснить большинство из них.


адрес редактирования: Вы можете создавать различные экземпляры этих объектов с помощью оператора new.

OR

Я бы порекомендовал использовать этот небольшой метод, расширяющий прототип объекта (опять же, если это не имеет смысла, смотрите видео Дугласа Крокфорда). Я забыл точные причины, по которым он так настоятельно рекомендовал его, но по крайней мере это устраняет некоторую путаницу в том, что оператор new немного отличается от классических языков. Излишне говорить, что использование только с использованием оператора new недостаточно.

Эта функция расширяет прототип Object методом create. Это потом ...

  1. Определяет функцию F в пространстве имен.
  2. Назначает прототип функции F объекту, который передается
  3. возвращает вновь созданный Объект.

(лучше обрисовал в общих чертах сам Дуглас Крокфорд в звене наследования прототипа)

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

Итак, используя ваш код ...

var a = Object.create(MODULE_TWO),
var b = Object.create(MODULE_TWO);
2 голосов
/ 26 декабря 2010

Отвечая на основании вашего последнего редактирования, вы можете использовать что-то вроде этого:

function Class(ctor, parent) {
    var c = Function.prototype.call;
    function clas() {

        // expose the parent as super
        this.super = parent;
        ctor.apply(this, arguments);
    }

    // save the constructor
    clas.constructor = ctor;

    // provide a static constructor
    clas.init = function() {
        c.apply(parent.constructor, arguments);
    };

    // Setup the prototype
    clas.prototype = parent ? parent.prototype : {};

    // provide an extend method
    clas.extend = function(methods) {
        for(var i in methods) {
            if (methods.hasOwnProperty(i)) {
                clas.prototype[i] = methods[i];
            }
        }
        return clas;
    };
    return clas;
}

Примеры:

var Animal = Class(function(name) {
    this.name = name;
});

var Cat = Class(function(name) {
    this.super(name);

}, Animal).extend({
    meow: function() {
        console.log('Meow! My name is ' + this.name + '.');
    }
});

new Cat('Neko').meow();

Существует как минимум триллион различных способов реализации «классов» в JavaScript, чем больше вы хотите скрыть внутренности, тем более «волшебным» становится код, тем не менее, вышеприведенное очень просто.

Вы можете (и, вероятно, должны) настроить это в соответствии со своими потребностями. Но всегда имейте в виду, что могут быть ситуации, когда полноценный подход к эмуляции класса может оказаться не лучшим.

Я уже разместил его в качестве комментария, но на тот случай, если вы хотите, чтобы все было спрятано для вас, я написал довольно богатую, но все же быструю библиотеку классов, свою собственную:
https://github.com/BonsaiDen/neko.js

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...