В JavaScript наследование: мое решение правильное?


Я разрабатываю JavaScript на несколько месяцев, и, как бывший программист Java, нужен простой способ, чтобы проанализировать наследование классов.

Мои потребности:

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

Цель этого запроса, чтобы указать мне, если я разрабатывал должны быть применены в моем проекте, или если есть некоторые риски неправомерного поведения с его помощью, и если у вас есть замечания, как улучшить его.

Мой код ниже, Спасибо за ваши отзывы.

/**
* Allows to retrieve the global object (used to test if the 'new' keyword is needed)
*/
function getGlobal(){
    return (function(){
            return this;
    }).call(null);
}

if (typeof Object.extend !== 'function') {
    Object.extend = function (object, superClassConstructor, superConstructorArgs) {
        //Inherits from the super object
        superClassConstructor.apply(object, superConstructorArgs);

        //make this.super allow to access to inherited object original functions
        object.super = {};
        for (var property in object){
            object.super[property] = object[property];
        }
    };
}
//The superclass
function SuperClass(options){
    //Make sure we will not alter global object
    if (this === getGlobal()){ 
        throw new Error("Constructor cannot be called as a function (new keyword should not be omitted)");
    }
    //Use of jshashtable-2.1:
    var attributes = new Hashtable();

    for (var key in options){
        attributes.put(key, options[key]);
    }

    this.setValue = function(key, value){
        if(value != null){
            attributes.put(key, value);
        }
        else{
            attributes.remove(key);
        }
    };

    this.getValue = function(key){
        return attributes.get(key);
    };
}

/**
* Inheriting class
*/
function ProjectModel(projectId) {
    //Make sure we will not alter global object
    if (this === getGlobal()){ 
        throw new Error("Constructor cannot be called as a function (new keyword should not be omitted)");
    }
    //extends SuperClass
    Object.extend(this, SuperClass, [{
                                    id:projectId,
                                    'one':1,
                                    'two':"2"
                                    }]);

    this.myType = "ProjectNumber";
    //Overriding a function
    this.getValue = function(key){
        return this.myType + ":" + this.super.getValue(key);
    };
}

var project = new ProjectModel(123);
alert(project.getValue('one')); //this displays 'ProjectNumber:123'


379
6
задан 4 ноября 2011 в 01:11 Источник Поделиться
Комментарии
3 ответа

Это вообще плохая идея, чтобы попробовать писать код на одном языке, как если бы это был другой язык.

Не борись ваш инструмент; используйте его, как он был разработан. JavaScript имеет прототипов ОО, а не на основе классов ОО, так что используйте это.

Читать "в JavaScript - хорошие части" и научиться писать хороший код JavaScript, а не "на Java в JavaScript" (для которого другим разработчикам работать с вашим кодом будут ненавидеть и/или издеваться над вами).

15
ответ дан 7 ноября 2011 в 10:11 Источник Поделиться

Нет, это неправильно. В JavaScript наследование-это очень легко.

var SomeKlass = {
...
};

var someInstance = Object.create(SomeKlass);

Более полный пример / преобразования кода см. В следующем примере


чтобы принять наследство простой,

Не может быть проще, чтобы наследовать любой объект называют объектом.создать на нем.


чтобы избежать новой ошибки ключевые слова,

Вы не используете новый больше, так что проблема исчезла


пусть методы суперкласса можно с помощью этого.супер собственность.

Эмуляция супер элегантный синтаксис-это серьезно не тривиальная задача

Лучший механизм я видел функцию замена либо установив этот.$супер по разумной стоимости до и после или перекомпиляции функции для ссылки на супер объект. Оба эти решения являются уродливые, я бы рекомендовал просто ссылка на супер-объект прямо по имени.


имея закрытые члены не доступны (инкапсуляции),

Вы не можете сделать не доступными закрытые члены в JavaScript с помощью прототипической ОО. Вы можете использовать замыкания, но это не прототип ОО и что не работает с прототипом ОО.

Я рекомендую вам использовать псевдо внутренние свойства с префиксом _ и стрелять из любого разработчика, который использует его.

В качестве альтернативы вы можете использовать пространства имен. Живой Пример.

var SuperClass = (function () {
// Name shim : https://gist.github.com/1344853
var privates = Name();

return {
constructor: function (options) {
privates(this).attributes = options;
},
setValue: function (key, value) {
if (value) {
privates(this).attributes[key] = value;
} else {
delete privates(this).attributes[key];
}
},
getValue: function (key) {
return privates(this).attributes[key];
}
};
})();

// Object.make : https://github.com/Raynos/pd#pd.make
var ProjectModel = Object.make(SuperClass, {
constructor: function (projectId) {
SuperClass.constructor.call(this, {
id: projectId,
one: 1,
two: "2"
});
this.myType = "ProjectModel";
},
getValue: function (key) {
return this.myType + ":" + SuperClass.getValue.apply(this, arguments);
}
});

var project = Object.create(ProjectModel);
project.constructor(123);
alert(project.getValue('one')); //this displays 'ProjectNumber:123'

5
ответ дан 7 ноября 2011 в 12:11 Источник Поделиться

С учетом замечаний и предложений, перед вами Расширенная версия моего первоначального кода: он работает и удовлетворяет мои потребности.

/**
* Allows to retrieve the global object
*/
function getGlobal(){
return (function(){
return this;
}).call(null);
}
function getFunctionName(fonction){
var nom = fonction.toString();
nom = nom.substr('function '.length);
nom = nom.substr(0, nom.indexOf('('));
return nom;
}
if (typeof Object.extend !== 'function') {
Object.extend = function (object, objectConstructor, superClassConstructor, superConstructorArgs) {
//To stop if new keyword was not used
if (object === getGlobal()){
throw new Error("Constructor should always be called with new keyword.");
}
//Check arguments:
if(objectConstructor === undefined){throw new Error("Missing argument: objectConstructor");}
if(superClassConstructor === undefined){throw new Error("Missing argument: superClassConstructor");}
if(superConstructorArgs === undefined){throw new Error("Missing argument: superConstructorArgs");}

//Calls super class' constructor, apply it to new object:
superClassConstructor.apply(object, superConstructorArgs);

//Create a super class "mirror" object
var superProperties = {};
//At this point, the new object will only have super object properties
//Copies each property:
for (var property in object){
superProperties[property] = object[property];
}
//Set it to new object:
object.super = superProperties;

//put super class name into a property
if(object.super.className === undefined){
object.super.className = getFunctionName(superClassConstructor);
}
//Set className for object
var className = getFunctionName(objectConstructor);
object.className = className;
//Set constructor for object
object.constructor = objectConstructor;
};
}
//The superclass
function SuperClass(options){
//Inherits from object:
Object.extend(this, arguments.callee, Object, [{}]);

//Use of jshashtable-2.1:
var attributes = new Hashtable();

for (var key in options){
attributes.put(key, options[key]);
}

this.setValue = function(key, value){
if(value != null){
attributes.put(key, value);
}
else{
attributes.remove(key);
}
};

this.getValue = function(key){
return attributes.get(key);
};
}

/**
* Inheriting class
*/
function ProjectModel(projectId) {
//extends SuperClass
Object.extend(this, arguments.callee, SuperClass, [{
id:projectId,
'one':1,
'two':"2"
}]);

this.myType = "ProjectNumber";
//Overriding a function
this.getValue = function(key){
return this.myType + ":" + this.super.getValue(key);
};
}

var project = new ProjectModel(123);
alert(project.getValue('one'));
//At this point, project will have:
// - a className property set to "ProjectModel"
// - a super property which will contain:
// --> className set to "SuperClass"
// --> setValue and getValue functions from SuperClass
// --> a super property set to Object parent class
// (with a className property set to "Object")

0
ответ дан 8 ноября 2011 в 09:11 Источник Поделиться