Основы JavaScript 5. Объектно-ориентированное программирование

В основе объектно-ориентированного программированиия (ООП) лежат две сущности: класс и объект.

Основные парадигмы ООП:

Глобальный объект

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

Порядок инициализации

Выполнение программы происходит в два этапа:

  1. этап подготовки
  2. этап выполнения

Лексическое окружение

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

Доступ ко внешним переменным

Функция имеет доступ не только к локальным, но и к глобальным переменных. При доступе к переменной она сначала ищется в LexicalEnvironment функции, а затем — в LexicalEnvironment того объекта, в котором была вызвана функция, пока переменная не будет обнаружена. Внешние по отношению к данной функции переменные хранятся в скрытом объекте [[Scope]], который является ссылкой на LexicalEnvironment, в котором функция была создана.

Вложенные функции

Внутри функций можно создавать другие, вспомогательные функции. Такие функции так же, как и обычные переменные, будут иметь локальную область видимости для "функции-родителя". У таких функций будет свой [[Scope]], состоящий из LexicalEnvironment "функции-родителя".

Свойства функции

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

Преобразование объектов

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

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

При строковом преоборазовании выведется результат выполнения метода toString, если такой есть в объекте, а иначе - просто строка [object Object]. Созданный программистом метод toString может возвращать любое примитивное значение, причем не только строку, так что такое преобразование называется именно строковым преобразованием, а не преобразованием к строке.

Для численного преобразования объекта используется метод valueOf, а если такого метода нет — то метод toString. Метод valueOf также может возвращать любой примитив, необязательно число. У большинства встроенных объектов метод valueOf отсутствует, поэтому для численного преобразования применяется метод toString.

Ключевое слово this

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

Конструктор

Конструктором является любая функция, вызванная через new

function Car(name) {
    this.name = name;
    this.wheels = 4;
    this.addWheel = function(wheelNum) {
        this.wheels += wheelNum;
    };
}

var car = new Car("Mersedes");

Обработка return у функции-конструтора

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

Если return вернет примитив, то он не будет учитываться, т.е. функция-конструктор отработает так, как если бы return не было. Если return вернет объект, то функция вернет этот.

Если в конструктор не нужно передавать никакие параметры, то его можно вызывать без скобок.

Дескрипторы

Помимо обычного создания свойств объекта есть ещё "продвинутое" — через метод Object.defineProperty. Метод принимает три параметра, третьим является дескриптор — объект-конфигурация вновь созданного свойства.

var car = {};
car.color = "red"; // обычное добавление свойства

Object.defineProperty(car, "speed", { // добавление свойства с помощью дескриптора
    value: 100, // значение свойства
    configurable: true, // возможность удалять свойство (только в use strict)
    writable: true, // возможность изменять значение свойства (только в use strict)
    enumerable: true // "перечисляемость" свойства
});
Object.defineProperty(car, "carInfo", {
    get: function() {
        return "My speed is " + this.speed;
    },
    set: function(value) {
        this.speed = value;
    },
});