Вложенный класс в javascript, наследование приватных методов - PullRequest
12 голосов
/ 18 февраля 2010

Я новичок в javascript, и я провожу некоторое время, пытаясь создать объекты пространства имен в js.

Вот что я пытаюсь сделать:

MainObject = function() {

    var privateVariable = "i'm private";

    var privateMethod = function() {
        // doSomething
    }

    this.publicMethod = function() {
        // doPublicSomething
    }
}

MainObject.prototype.nested = function() {

    this.publicNestedMethod = function() {

        // that's not working at all
        this.privateMethod(privateVariable);

    }
}

MyObject = new MainObject();

MyObject.publicMethod();
MyObject.publicNestedMethod();

Я попытался включить вложенный класс в первый, но он не работает, даже если я попытаюсь:

this.nested = function() {

    var mainObject = this;

    return {
        publicNestedMethod = function() {
            mainObject.privateMethod();             
        }   
    }
}();

Кто-то может мне помочь, пожалуйста?Я схожу с ума по этому поводу.

Федра.

Ответы [ 6 ]

14 голосов
/ 18 февраля 2010

Замыкания - это лексическая, а не семантическая особенность. Если объект находится за пределами лексической области видимости другого, он больше не может быть «вложенным» и обращаться к локальным переменным предыдущего. В коде вашей вложенной функции / класса нет такой вещи, как this.privateMethod, потому что privateMethod никогда не является , созданным как свойство MainObject. Это просто локальная переменная внутри функции.

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

Итак, плохая идея - писать Java-код со всеми его методами OO в JS, так же как плохая идея - писать C-код со всеми его указателями и неограниченными буферами в C #. Конечно, в обоих случаях вы можете сделать это, но вы не сможете оценить и использовать возможности языка таким образом.

И теперь, когда я закончил с разглагольствованием, вы можете сделать что-то вроде этого, чтобы получить функции "namespaced":

MainObject = function() {
    var privateVariable = "I'm private";

    var privateMethod = function() {
        alert('Private');
    }

    this.publicMethod = function() {
        alert('Public');
    }

    this.nested = {
      publicNestedMethod: function() {
        privateMethod();
      }
    };

    // or

    this.nested = (function() {
      var nestedPrivate = 5;

      return {
        publicNestedMethod: function() {
          alert(nestedPrivate);
          privateMethod();
        }
      };
    })();
}

MyObject = new MainObject();

MyObject.publicMethod();
MyObject.nested.publicNestedMethod();​
6 голосов
/ 06 сентября 2010

Использование соглашения о подчеркивании для «частных» методов - разумный способ сохранить порядок.

  MainObject = function() {

       this._privateVariable = "i'm private";

       this._privateMethod = function() {
          // doSomething
       }

        this.publicMethod = function() {
          // doPublicSomething
        }
}
4 голосов
/ 09 декабря 2011

Хорошо, чтобы обеспечить преимущество наследования прототипов, когда все «подклассы» совместно используют один экземпляр метода в прототипе, но ТАКЖЕ предоставляют возможность наследования частных экземпляров ... Я придумал:

function Person(name,latentPower){
    var privatesForChildren =   { password:"xyz"
                                 ,latentPower:"invisibility"}
    this.inherit = function(){
        for(v in privatesForChildren){
            eval("var " + v + "=privatesForChildren['" + v + "'];");
        }
    }
    this.name = name;
    this.revealName = function(){ alert("My name is" + this.name + "."); }  
    this.revealPowers = function(){ alert("I'm normal."); } 
}       
function Mutant(name,latentPower,fuel){
    this.inherit.call(this);   // Inherit private instance variables
    var fuel = fuel;
    this.name = name;
    this.revealPowers = function(){
    alert("I manifest the powers of " + latentPower + " when I " + fuel + ".");
    }
}
Mutant.prototype = new Person;
Mutant.prototype.constructor = Mutant;

bob = new Person("Bob","telekenesis");
jim = new Mutant("Jim","nausea","eat pizza");
buford = new Mutant("Buford","Teflon Man","breathe");

jim.revealName(); //Inherited properly from prototype
bob.revealPowers();
jim.revealPowers();
buford.revealPowers();  //distinct from Jim's so is an "instance var"
alert(bob.latentPower); //returns undefined 
alert(buford.latentPower); //returns undefined, so is "private".

Насколько это полезно?

1 голос
/ 05 марта 2019

Классы JavaScript и наследование (ES6)

Согласно ES6, вы можете использовать классы JavaScript и наследование, чтобы выполнить то, что вам нужно.

Классы JavaScript, представленные в ECMAScript 2015, в основном являются синтаксическим сахаром по сравнению с существующим наследованием JavaScript на основе прототипов.

Ссылка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

Я показываю примеры ниже с переменными , но это может быть применено также к функциям .


Наследование (1-й подход)

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

class Main {
  constructor() {
    let privateVariable = "private";
    this.publicVariable = "public";

    this.getPrivateVariable = () => {
      return privateVariable;
    }
  }
}

Main.Sub = class Sub extends Main {
  getAllVariables() {
    return this.publicVariable + "-" + this.getPrivateVariable();
  }
}

// Testing...

let main = new Main();
let sub = new Main.Sub();

console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"

console.log(sub.privateVariable); // undefined
console.log(sub.publicVariable); // "public"

console.log(main.getPrivateVariable()); // "private"
console.log(sub.getPrivateVariable()); // "private"
console.log(sub.getAllVariables()) // "public-private"

Вложенность (2-й подход)

Возможно, это решение лучше для вас, потому что оно не раскрывает ваши личные переменные вне классов Main и Nested.

class Main {
  constructor() {
    let privateVariable = "private";
    this.publicVariable = "public";
    
    Main.Nested = class Nested extends Main {
      getAllVariables() {
        return this.publicVariable + "-" + privateVariable;
      }
    }
  }
}

// Testing...

let main = new Main();
let nested = new Main.Nested();

console.log(main.privateVariable); // undefined
console.log(main.publicVariable); // "public"

console.log(nested.privateVariable); // undefined
console.log(nested.publicVariable); // "public"

console.log(main.getPrivateVariable); // undefined
console.log(nested.getPrivateVariable); // undefined
console.log(nested.getAllVariables()) // "public-private"
0 голосов
/ 03 ноября 2011

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

MyFunction = function(options){
   var private = {};
   //to reference MyFunction as a context
   var that = this;

   function privateFunctionThatCallPublicMethod(){
      that.publicFunction("hello");
   }

   this.publicFunction = function(params){
      alert(params + "  " + private);  
   }
   ...
}

var instance = new MyFunction({oneOption:'fsdfsad'});

Это наилучший подход, который я нашел для эмуляции ОО Java-методов ...

Но есть проблема, очень неэффективная ... Вместо этого вы должны использовать прототип, потому что в противном случае он будет создавать по одному объекту на функцию на экземпляр класса.

MyFunction = function(options){
   this._private = {};
}

MyFunction.prototype._privateFunctionThatCallPublicMethod = function(){
   this.publicFunction("hello");
}

MyFunction.prototype.publicFunction = function(params){
   alert(params + "  " + this._private);  
}

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

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

function bind(fnThis, fn) {
  return function(){
    return fn.apply(fnThis, arguments);
  };
}

function makeSomething(callback){
  callback("hello");
}

var instance = new MyFunction();
makeSomething(bind(instance, instance.publicFunction));

Это потому, что вы должны связать «this» как экземпляр в теле publicFunction, иначе вместо этого будет «window».

0 голосов
/ 18 февраля 2010

Какая система OO позволяет вам наследовать частные методы? Частично быть приватным недоступно для других объектов.

В частности, в JS «закрытые члены» - это на самом деле просто локальные переменные функции, в которой они объявлены. JS не имеет типичных ОО-понятий «класс», «наследование», «общедоступный» и «частный», поэтому вы не можете ожидать, что ваши методы ООП будут дословно скопированы из других языков ООП.

...