Javascript: в чем разница между функцией и классом

С выпуском ECMAScript 6 в июне 2015 года был введен синтаксис классов Javascript.

синтаксис:

class Polygon {
      constructor(width, height) {
        this.width = width;
        this.height = height;
      }
}

в основном то же, что:

function Polygon(width, height) {
    this.width = width;
    this.height = height;
}

Итак, в чем преимущество использования класса вместо традиционной функции? И в каком состоянии я должен использовать class вместо function?

2 ответов


есть некоторые различия между классом и функцией - большинство людей начнут с того, что класс "просто синтаксический сахар", но этот сахар имеет большое значение. Когда парсер JS обрабатывает код JavaScript, парсер сохранит их в разных узлах AST, как показано здесь ClassDeclaration и ClassExpression различные типы узлов в результирующем AST дерево:

https://github.com/estree/estree/blob/master/es2015.md#classes

вы можете видеть, что для этого парсера новая спецификация классов ES6 вводит ряд новых элементов AST в синтаксис:

  • ClassBody
  • MethodDefinition
  • ClassDeclaration
  • ClassExpression
  • Метасвойства

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

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

class notWorking {
  return 1;  // <-- creates a parser error
};

это связано с тем, что когда анализатор встречает ключевое слово class, он начнет обрабатывать следующий код как ClassBody либо ClassDeclaration, либо ClassExpression, а затем он expexts для поиска MethodDefinitions.

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

function myClass() {
    var privateVar;
}

объявление класса не может быть такого:

class myClass {
    var privateVar; // ERROR: should be a method
}

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

однако существует предложение по созданию частных полей:

https://github.com/zenparsing/es-private-fields

таким образом, в будущем вы могли бы сказать

class myClass {
   #privateVar; // maybe this works in the future?
}

существует отдельный ответ, рассматривающий частные свойства в классах ES6, который предлагает некоторые обходные пути, такие как использование символов:

частные свойства в JavaScript ES6 классы

var property = Symbol(); // private property workaround example
class Something {
    constructor(){
        this[property] = "test";
    }
}

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

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

объявления классов и объявления функций очень похожи;

function foo1() {} // can be used before declaration
class  foo2{}      // new foo2(); works only after this declaration

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

var myClass = class foobar {};

больше различия 1

  1. тело выражения / объявления класса всегда выполняется в строгого режима - нет необходимости указывать это вручную
  2. классы специальное ключевое слово конструктор - там может быть только один из них, или ошибка. Функции могут иметь несколько определений переменной функции с именем "конструктор"
  3. классы имеют специальное ключевое слово супер который относится к конструктору родительских классов. Если вы находитесь внутри конструктора вы можете позвонить супер (x, y); для вызова конструктора родительского класса, но внутри метода вы можете вызвать супер.foobar () создать вызов любая функция родительского класса. Такая функциональность недоступна для стандартных функций, хотя вы можете эмулировать ее с помощью некоторых пользовательских взломов.
  4. внутри тела класса вы можете определить функцию с static ключевое слово, поэтому его можно вызвать, используя только ClassName.FunctionName () -синтаксис.
  5. объявления и выражения классов могут использовать выходит ключевое слово класс собака расширяется Животное!--80-->
  6. MethodDeclaration не нуждается в префиксе функции, поэтому вы можете определить функцию " ok "внутри класса" m " следующим образом: класс m { ok () { } }. На самом деле даже не разрешается определять функцию как класс m { функция ok () { } }

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

новый синтаксис класса ES6 по существу, более ясный способ выражения объектов традиционным способом ООП, и если вам это нравится, то вы должны использовать его.

EDIT: кроме того, синтаксис класса ES6 имеет еще одно ограничение: он не позволяет функциям-членам использовать лексически связанные с помощью fat arrow. ES7 кажется экспериментальная функция позволяю. Это может быть полезно, например, при привязке методов к обработчикам событий, связанный вопрос здесь.

1 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes


class его ничего, кроме синтаксического сахара над созданием класса логики javascript с помощью function. если вы используете function as class вся функция действует как конструктор, если вы хотите поместить другие функции-члены, вам нужно сделать это в конструкторе, как this.something = ... или var something = ... в случае частных членов (если вы не вводите извне, предположим, что вы создаете объект с другими методами / свойствами), но в случае класса вся функция фактически не действует конструктор вы можете явно разделить его с другими функциями-членами и данными.