Javascript "классы" прототип против объявления внутренней функции против и т.д. - PullRequest
10 голосов
/ 29 мая 2011

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

Я пришел из Java-фона, так что если вы можете определить что-либо как статическое, частное, общедоступное и т. Д., То это должно помочь мне понять.

По сути, я хочу создать полностью собственный класс, но не уверен насчет прототипа / etc. Пример (с использованием одного типа функции):

function myClass()
{
    var a;
    var b;

    var helper = function()
    {
        this.a += this.b;
    }

    var helper2 = function(a,b)
    {
        return(a + b);
    }

    var getA = function()
    {
        return(this.a);
    {

    var staticMethodThatNeedsToBePublic = function()
    {}
}

var myInstance = new myClass();

myClass.prototype.example1 = function(){};
myClass.example2 = function(){};

Так как же это должно было быть написано? (Я попытался включить все основные типы функций, но если я пропустил какие-либо из них, не стесняйтесь добавлять их потом) просто ответь на мой общий вопрос]

Ответы [ 3 ]

13 голосов
/ 29 мая 2011

Краткий ответ на ваш вопрос: используйте прототипы. Всегда используйте прототипы.

Основным отличием является то, что если вы присоединяете функцию с помощью this.foo = function(){}, функция повторно объявляется для каждого экземпляра класса. Присоединение с использованием func.prototype.foo = function(){} означает, что только функция ever объявляется один раз, а свойство this изменяется при обращении к экземпляру класса, на который следует ссылаться.

Ваш код становится:

function myClass(){
    // constructor
}

myClass.prototype   = new superClass();
myClass.constructor = myClass;
myClass.prototype = {
    helper  : function(){},
    helper2 : function(){}
};

var myInstance = new myClass();

Полный список того, как вы можете добавить методы и свойства в класс из статьи, которую я написал около 5 лет назад:

http://www.htmlgoodies.com/primers/jsp/article.php/3600451/Javascript-Basics-Part-8.htm

function Cat(name, color){
    /*
    Constructor: any code in here is run when the object is created
    */
    Cat.cats++;

    /*
    Private variables and functions - may only be accessed by private or privileged functions.

    Note that 'name' and 'color', passed into the Class, are already private variables.
    */
    var age  = 0;
    var legs = 4;
    function growOlder(){
        age++;
    }

    /*
    Public variables - may be accessed publicly or privately
    */
    this.weight = 1;
    this.length = 5;

    /*
    Privileged functions - may be accessed publicly or privately
    May access Private variables.

    Can NOT be changed, only replaced with public versions
    */
    this.age = function(){
        if(age==0) this.length+=20;

        growOlder();
        this.weight++;
    }
}

/*
Prototyped Functions - may be accessed publicly
*/
Cat.prototype = {
    talk:     function(){ alert('Meow!'); },
    callOver: function(){ alert(this.name+' ignores you'); },
    pet:      function(){ alert('Pet!'); }
}

/*
Prototyped Variables - may be accessed publicly.
May not be overridden, only replaced with a public version
*/
Cat.prototype.species = 'Cat';

/*
Static variables and functions - may be accessed publicly
*/
Cat.cats = 0;
4 голосов
/ 30 мая 2011

Summery:

function MyClass(){
    //You can access everything from in here (and from all sub functions) including prototypes and statics that are defined afterwards.
    var privateVariable = "PriTest"; //Pair cannot by seen outside of MyClass
    function privateFunction(){
    }

    this.publicVariable = "pubTest"; //Pair can be seen by everything except static functions
    function publiFunction(){
    }this.publiFunction = publiFunction;

    this.prototypeFunction();      //This group could of been called like this from anywhere in this object
    alert(this.prototypeVariable);
    MyClass.staticFunction();
    alert(MyClass.staticVariable);
}

MyClass.prototype.prototypeFunction = function(){
    //Can access other prototypes, statics, and public functions and variables
    this.publicFunction();
    this.prototypeVariable;
    MyClass.staticFunction();
}
MyClass.prototype.prototypeVariable = "proTest"

MyClass.staticFunction = function(){
    //Can access other statics only
    alert(MyClass.staticVariable);
}
MyClass.staticVariable = "staTest"

Пожалуйста, скажите мне, если я что-то не так в следующем.

Приватный (доступен изнутри): [То же, что и java] var variableName || function functionName внутри объекта. Доступ к ним возможен только через другие частные или привилегированные функции.

Публично и Привилегировано (доступно извне {может работать со всеми внутренними объектами}): [То же, что и общедоступное java] this.variableName || this.functionName = function(){ ... } внутри объекта.

Prototype (доступный из других прототипов): [почти вне класса и может получить доступ только к общедоступным объектам] Class.prototype.variableName || Class.prototype.functionName Функции, объявленные таким образом, будут иметь доступ к любым общедоступным или прототипным переменным. Попытки изменить переменную, созданные таким образом, вместо этого создадут новую публичную переменную на объекте, и переменная прототипа будет недоступна.

Статика: [То же, что и Java?] Class.variableName || Class.functionName Может быть изменен любой функцией или методом.

function MyClass(){
    //public, privileged, and private
    //Everything in here can see each other
    //Everything in here can see everything outside
}
//Prototype and Static
//Prototype, Basically a template that is used on an instance of a class (And therefore does not have access to any of the non public fields)

Пример прототипа:

MyClass.prototype.proExample = function(){
    this.doSomething;
}
//Is basically equivalent to
function proExample(instanceOfMyClass){
    instanceOfMyClass.doSoemthing;
}

Добавлю к этому после того, как сделаю несколько тестов.

3 голосов
/ 29 мая 2011

Это смущает многих людей, потому что Javascript использует совершенно другое понятие наследования и класса. В Javascript все , включая классы, является просто объектом. Все методы и такие, которые составляют часть class , содержатся в объекте с именем prototype. Частично это функция с именем init. Когда вы делаете new Foo(), вы создаете новый объект, и некоторый метод init копирует соответствующее содержимое, включая прототип, в этот новый объект.

Итак, когда вы добавляете функцию к prototype через

 myClass.prototype.example1 = function(){};

вы фактически добавляете в класс 1016 * новый метод, который затем наследуется в любом экземпляре myClass, который вы создаете. Во втором случае

 myClass.example2 = function(){};

вы просто добавляете новый метод в исходный объект myClass. В терминах Java это в основном меняет его на объект нового типа, который действует как myClass , за исключением , теперь у него есть метод example2().

Обновление

В другом ответе упоминается Классическая записка Крокфорда о наследовании. Я бы порекомендовал прочитать также бумагу Prototypal Inheritance .

Еще одно обновление

Хорошо, давайте вернемся на секунду. Во-первых, что это за объект? По сути, это структура, которая сочетает в себе состояние и поведение .

У нас есть идея Числа, у которого есть метод add, и у нас есть своего рода Число, называемое Целым числом, которое «ведет себя как» Число, но ограничено значениями в определенном диапазоне. На таком языке, как Java, у вас может быть

abstract class Number {
    public void addTo(Number arg);
}

, а затем

class Integer extends Number {
    int val;
    public void addTo(Integer arg){ val += arg; }
}

(И не беспокойте меня о деталях Java, я пытаюсь сделать вывод.)

То, что вы сказали здесь, это то, что потенциально есть много объектов, которые являются числами, и все они имеют поведение, называемое addTo. Математически набор вещей, которые идентифицируются общим свойством, иногда называют «классом эквивалентности», и именно так мы получаем имя «класс».

Мы также определили особый вид Number, называемый Integer, который имеет ограниченный диапазон значений, от -32767 до 32768. (Тест: почему эти значения?) Тем не менее, он действует во всех отношениях как Number: Вы также можете addTo целых чисел. Это утверждение «действует во всех отношениях как - но с этими ограничениями» обычно сокращается до «является» и является тем, что мы подразумеваем под «наследованием».

Итак, теперь вы пишете

Integer a, b;
// they get initial values somehow, left as an exercise
a.addTo(b);

и компилятор выясняет, чтобы найти объект a, находит его конкретное поведение addTo и знает, как все подключить, чтобы он работал. Иногда - как в ранних версиях C ++ - это нужно было делать во время компиляции; в более поздних версиях C ++ и Java также есть способ установить соединение во время выполнения («позднее связывание»), что в основном сводится к тому, чтобы разместить таблицу где-нибудь с надписью

Если у меня есть целое число и мне нужен метод addTo, вот его адрес; используйте это.

Javascript и некоторые предыдущие языки, начиная с Self, делают это немного по-другому. Теперь объект - это просто структура, которая содержит ... материал. Некоторые из этих вещей могут быть данными, а некоторые могут быть функциями. Идея «класса» может быть полностью абстрагирована; «класс» - это просто набор всех объектов, имеющих одинаковое содержимое. Итак, в Javascript мы могли бы сделать наш класс "Integer" как

 var Integer = {  // we're defining an object as a literal
     int val,
     addTo : function(b){ val += b ; }
 }

(Опять же, не беспокойтесь, если это действительно идеальный javascript, смысл в том, чтобы объяснить концепцию.)

Если мы скопируем этот объект с именем Integer, скажем, Integer2, тогда оба будут содержать val и функцию с именем addTo. Мы можем сказать, что они оба «одного и того же класса», потому что они имеют одинаковое состояние и методы.

Вопрос в том, как мы можем реализовать это копирование?Вы можете просто пройтись по всему понемногу, но у него есть некоторые другие проблемы, поэтому мы определили специальный объект в содержимом каждого объекта javascript с именем prototype и поместили все методы ивещи - все, что мы хотели бы скопировать для создания другого объекта в том же классе - в этом.Теперь у нас будет что-то вроде

  var Integer = {
      prototype : {
        int val,
        addTo : function(b){ val += b; }
      }
  }

Мы добавим к языку оператор new, который просто копирует объект-прототип.Когда мы пишем

  var a = new Integer();

a, это теперь объект, который имеет тот же прототип, что и все другие Integer объекты.Когда мы пишем

  a.addTo(b);

, все, что нужно сделать интерпретатору, - это посмотреть на объект prototype, содержащийся в a, и найти его метод с именем addTo.

Зачем это?Потому что теперь вся сложность компиляции в классах, добавления синтаксиса и выяснения того, когда связывать во время компиляции или во время выполнения, плюс управление таблицами времени выполнения и т. Д., Превращается в две простые операции:

  • знать, как сделать глубокую копию из prototype
  • как найти что-то по имени в prototype.

Этот второй подходэто «наследование прототипа».

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