Почему я должен использовать классы ES6?

У меня много вопросов о классах ES6.

Поскольку я понимаю, как использовать функцию и WebComponent, React и так. Я не видел много пользы от его использования.

Интересно, какая польза от использования классов? Я читал, что public/private/static будет частью ES7. Так что я не вижу смысла использовать его в настоящее время.

Кроме того, будет ли класс концепцией ООП или все же "концепцией объекта javascript"? Означает ли это, что я не могу изменить его, используя .prototype? Или это просто один и тот же объект, но 2 разных способа объявить его.

Есть ли преимущества в скорости? Может быть, легче поддерживать / понимать, если у вас есть большое приложение, такое как приложение Big Java?

tl;dr : The question is in the title.

ИНФОРМАЦИЯ: Я заметил, что люди все еще приходят, чтобы увидеть этот вопрос, который более 2 лет назад. Ответ все еще точен, но помните, что с тех пор javascript эволюционировал "немного".

4 ответа

Решение

Это (почти) полностью зависит от вас, делаете ли вы. Новый class В основном это просто синтаксический сахар. (Но, вы знаете, хороший вид сахара.)

Кроме того, будет ли класс концепцией ООП или все же "концепцией объекта javascript"?

Это то же самое прототипное наследование, которое мы всегда имели, только с более чистым и более удобным синтаксисом, если вам нравится использовать функции конструктора (new Foo, так далее.). (Особенно в случае получения от Array или же Error, что вы не могли сделать в ES5 и ранее. Теперь вы можете с Reflect.construct [ spec, MDN], но в то время как вы должны лечить Array а также Error особенно при выводе из них без classс class это точно так же, как и от чего-либо еще.)

Означает ли это, что я не могу изменить его с помощью.prototype?

Нет, вы все еще можете изменить prototype Объект в конструкторе класса, как только вы создали класс. Например, это совершенно законно:

class Foo {
    constructor(name) {
        this.name = name;
    }

    test1() {
        console.log("test1: name = " + this.name);
    }
}
Foo.prototype.test2 = function() {
    console.log("test2: name = " + this.name);
};

Есть ли преимущества в скорости?

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

Почему я должен использовать классы ES6?

Если вам не нравится использовать функции конструктора (new Foo), не используйте новый синтаксис, он ничего не делает для вас. Если вы это сделаете, то причины, по которым вы можете выбрать:

  • Синтаксис проще и менее подвержен ошибкам.

  • Намного проще (и опять же, менее подвержено ошибкам) ​​настроить иерархии наследования с использованием нового синтаксиса, чем со старым.

  • class защищает вас от распространенной ошибки отказа от использования new с помощью функции конструктора (если конструктор выдает исключение, если this не является допустимым объектом для конструктора).

  • Вызов версии метода родительского прототипа с новым синтаксисом намного проще, чем старый (super.method() вместо ParentConstructor.prototype.method.call(this) или же Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)).

  • Вы можете извлечь из Array (jQuery, вероятно, сделал бы это, если бы это было возможно, когда Resig запустил его) и Error просто вместо того, чтобы использовать Reflect.construct,

Вот сравнение синтаксиса для иерархии:

// ES6
class Person {
    constructor(first, last) {
        this.first = first;
        this.last = last;
    }

    personMethod() {
        // ...
    }
}

class Employee extends Person {
    constructor(first, last, position) {
        super(first, last);
        this.position = position;
    }

    employeeMethod() {
        // ...
    }
}

class Manager extends Employee {
    constructor(first, last, position, department) {
        super(first, last, position);
        this.department = department;
    }

    personMethod() {
        const result = super.personMethod();
        // ...use `result` for something...
        return result;
    }

    managerMethod() {
        // ...
    }
}

против

// ES5
var Person = function(first, last) {
    if (!(this instanceof Person)) {
        throw new Error("Person is a constructor function, use new with it");
    }
    this.first = first;
    this.last = last;
};

Person.prototype.personMethod = function() {
    // ...
};

var Employee = function(first, last, position) {
    if (!(this instanceof Employee)) {
        throw new Error("Employee is a constructor function, use new with it");
    }
    Person.call(this, first, last);
    this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
    // ...
};

var Manager = function(first, last, position, department) {
    if (!(this instanceof Manager)) {
        throw new Error("Manager is a constructor function, use new with it");
    }
    Employee.call(this, first, last, position);
    this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
    var result = Employee.prototype.personMethod.call(this);
    // ...use `result` for something...
    return result;
};
Manager.prototype.managerMethod = function() {
    // ...
};

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

Классы ES6 являются синтаксическим сахаром для прототипной системы классов, которую мы используем сегодня. Они делают ваш код более кратким и самодокументируемым, что является достаточной причиной для их использования (на мой взгляд).

Используя Babel, чтобы перенести этот класс ES6:

class Foo {
  constructor(bar) {
    this._bar = bar;
  }

  getBar() {
    return this._bar;
  }
}

даст вам что-то вроде:

var Foo = (function () {
  function Foo(bar) {    
    this._bar = bar;
  }

  Foo.prototype.getBar = function () {
    return this._bar;
  }

  return Foo;
})();

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

Поскольку классы компилируются по тем же прототипным шаблонам, которые мы использовали, вы можете выполнять с ними те же манипуляции с прототипами. Это включает добавление методов и т.п. во время выполнения, доступ к методам на Foo.prototype.getBar, так далее.

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

const BAR_NAME = 'bar';

export default class Foo {
  static get name() {
    return BAR_NAME;
  }
}

а также BAR_NAME не будет доступен для других модулей для прямой ссылки.

Многие библиотеки пытались поддержать или решить эту проблему, например, Backbone со своими extends хелпер, который принимает непроверенный хэш функций и свойств, подобных методам, но не существует системы смещения для раскрытия прототипного наследования, которая не предполагает перебора прототипа.

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

tl; dr: это сахар для того, что мы уже делаем, и проясняет ваши намерения в коде.

Классы ES6 — это синтаксический сахар поверх конструкторов, которые уже были в javascript. Наличие синтаксиса и семантики, подобных тем, что мы имеем в других языках, позволяет программистам переходить с других языков и легче понимать синтаксис. Ниже показано, как класс создается в соответствии с классами es6:

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

  getArea() {
    return this.height * this.width;
  }
}

В других языках, таких как java и c++, вы могли видеть концепцию статических свойств и методов. Вот как вы будете делать это сейчас в javascript с новым синтаксисом:

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

  getArea() {
    return this.height * this.width;
  }

  static side() {
    return "This shape have four sides";
  }
}

И вот как вы объявляете приватные поля с этим новым синтаксисом:

      class Base {
  #privateField1 = 26;
  #privateField2;

  constructor(val) {
    this.#privateField2 = val;
  }

  getprivateField2() {
    return this.#privateField2;
  }
}

let main = () => {
  let obj = new Base(27);
  console.log(`Private field 2 using getter : ${obj.getprivateField2()}`);
};

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

Синтаксис класса — это больше, чем просто синтаксический сахар в одном ключевом отношении: приватных переменных.

Я возьму немного js из одного из других примеров.

      var Foo = (function () {
  function Foo(bar) {    
    this._bar = bar;
  }

  Foo.prototype.getBar = function () {
    return this._bar;
  }

  return Foo;
})();

//similar to
class Foo {
  constructor(bar) {
    this._bar = bar;
  }

  getBar() {
    return this._bar;
  }
}

Обратите внимание_bar. Это идиома, обозначающая, что что-то является частным, но при этом становится общедоступным. Когда это было изобретено, не было возможности иметь настоящую частную переменную, не скрывая ее в замыкании. Проблема со скрытием замыкания заключается в том, что оно делает переменные по-настоящему частными, настолько частными, что их даже невозможно увидеть, когда объект регистрируется на консоли. И это САМЫЙ ГЛАВНЫЙ недостаток. Затруднение видения внутреннего состояния препятствует развитию.

Давным-давно я отказался от префикса подчеркивания для частных переменных и просто начал делать все переменные общедоступными. У меня не было никаких проблем с этим подходом, потому что из соображений дисциплины я всегда рассматриваю все переменные как частные. Доступ к ним возможен только через метод объекта-владельца, чтобы сохранить преимущества инкапсуляции. Публикация их облегчила их допрос во время интерактивного сеанса разработки/отладки.

Именно здесь рядовые класса спасают ситуацию.

      class Foo {
  #bar;

  constructor(bar) {
    this.#bar = bar;
  }

  getBar() {
    return #.bar;
  }
}

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

Другие вопросы по тегам