Статьи

ECMAScript.next: прототипы как классы

Это сообщение описывает предложение для создания классов и наследования проще в ECMAScript.next: «Прототипы как классы».

Наследование в JavaScript прототипичных трудно понять, особенно для людей, приезжающих из других языков, которые используются для классов. Это сообщение объясняет, что он не должен быть таким образом: Есть планы упростить вещи в ECMAScript.next. Что интригует об этом упрощении, что это не радикальный отход от существующей практики, а уточнение их.

Это сообщение объясняет, как новый язык особенности работы пути введения гипотетического языка программирования под названием «NextScript», который имеет классы нового стиля, но без унаследованного багажа в JavaScript. Затем мы рассмотрим, как JavaScript в настоящее время обрабатывает классы и заключить с передачей классов NextScript на JavaScript, оставаясь при этом совместимым с унаследованным кодом.

1. NextScript

NextScript является JavaScript без функций конструкторы. Отношения между объектами прообраза работает как в JavaScript, но есть оператор для установки прототипа.

  • При желании объект может иметь прототип , указывая на другой объект через внутреннее свойство [[Prototype]]. Значение этого свойства можно получить через Object.getPrototypeOf (). Прототип объекта может снова иметь прототип. Последовательность объектов, являющихся прототипами друг друга, называется цепочкой прототипов .
  • Если NextScript не может найти свойство в объекте, он продолжает искать в прототипе, затем прототип прототипа и т. Д.
  • Оператор-прототип <| устанавливает прототип литерала объекта:
        var obj = A <| { ... };
    

    После вышеуказанного объявления объект obj имеет прототип A.

Когда вы думаете о классе как конструкция, которая производит экземпляры, то ближе всего к классу, который JavaScript имеет являются функции конструкторы. В отличие от этого, NextScript использует обычный старый (не-функции) объектов:

  • Классы: Класс С является объектом. Она содержит данные, совместно используемые всеми экземплярами ( в основном методы). Специальный метод , называемый «конструктор» устанавливает экземпляр конкретных данных ( в основном свойство данных).
  • Создание экземпляров: Создание нового экземпляра с помощью нового С (х, у) выполняет следующие действия :

    • Создать новый объект О, чей прототип C.
    • Вызов o.constructor (x, y)
  • Проверка экземпляра:
        o instanceof C
    

    проверяет, находится ли C в цепочке прототипов o. Это синтаксически

        C.isPrototypeOf(o)
    
  • Получение класса: Класс объекта является его прототипом. Пример: Являются obj1 и obj2 (прямые) экземпляры одного и того же класса?
        Object.getPrototypeOf(obj1) === Object.getPrototypeOf(obj2)
    
  • Подклассы: Вы расширяете существующий класс C путем создания нового объекта D , чей прототип C. Если вы хотите , чтобы свойства экземпляра унаследует, вы должны вызвать C.constructor () из D.constructor ().

То есть, эти объекты очень похожи на классы во многих языках программирования (такие как Python, Java или C #), но нет необходимости в новой конструкции, объект становится классом, являющегося операнд нового оператора. Пример:

    // Superclass
    var Person = {
        constructor: function (name) {
            this.name = name;
        },
        describe: function() {
            return "Person called "+this.name;
        }
    };

    // Subclass
    var Worker = Person <| {
        constructor: function (name, title) {
            Person.constructor.call(this, name);
            this.title = title;
        },
        describe: function () {
            return Person.describe.call(this)+" ("+this.title+")"; // (*)
        }
    };

Взаимодействие:

    > var john = new Person("John");
    > john.describe()               
    Person called John
    > var jane = new Worker("Jane", "CTO");
    > jane.describe()
    Person called Jane (CTO)
    > jane instanceof Worker
    true
    > jane instanceof Person
    true

Экземпляр джан имеет прототип работник, который имеет прототип Person. То есть, прототипы используются как для экземпляра-отношений и подкласса-отношений. Следующая диаграмма показывает эту цепочку прототипов:

1.1. Супер-звонки

Все становится еще проще , если мы добавим еще одну особенность: супер-звонки. Они делают его более легким для переопределения метода для вызова метода он переопределяет (его
супер-метод ). Есть два способа смотреть на методы:

  • Обычный способ поиска: obj.m (). Для того, чтобы найти метод, мы ищем первый объект в цепи прототипов OBJ , который имеет свойство м и вызывает значение этого свойства. Во время этого вызова, это связано с OBJ, объект , где начал поиск.
  • Поиск супер-метода: super.l (). Этот вызов должен быть сделан из метода m. Поиск л начинается в супер-объект т (прототип объекта , который содержит м). Во время выполнения л, это имеет такое же значение , как это было в м.

Обратите внимание, что это не меняет во время супер-вызова, только поиск метода начинается позже в цепочке прототипов. Сложная вещь с супер-метод поиска, чтобы найти супер-объект. Это может быть сделано вручную, путем непосредственного его именования, как и в методе Worker.describe () в (*). Или она может быть выполнена автоматически, с помощью языка конструкта NextScript:

    var Super = {
        foo: ...
    };
    var Sub = Super <| {
        foo: function (x, y) {
            super.foo(x, y); // (**)
        }
    };

Заявление в (**) является супер-метод поиска и синтаксически

    Object.getPrototypeOf(Sub).foo.call(this, x, y);

Теперь работник может быть упрощена следующим образом.

    var Worker = Person <| {
        constructor: function (name, title) {
            super.constructor(name);
            this.title = title;
        },
        describe: function () {
            return super.describe()+" ("+this.title+")";
        }
    };

2. Классы в JavaScript (ECMAScript 5)

Давайте посмотрим на то, как классы работают в JavaScript.

  • Классы: Класс является функцией конструктора CCprototype указывает на объект с методами экземпляра. Сама С устанавливает свойство данных экземпляра.
  • Создание экземпляров: new C (x, y) делает следующее:

    • Создать новый объект О, чей прототип C.prototype.
    • Вызовите C, указав на только что созданный экземпляр.
  • Проверка Instance: о InstanceOf проверки C ли C.prototype находится в цепи прототипов о.
  • Получение класса: через свойство конструктора. Пример: Являются obj1 и obj2 (прямые) экземпляры одного и того же класса?
        obj1.constructor === obj2.constructor
    
  • Подклассы: Вы расширяете существующий класс C, создав новую функцию конструктора DDprototype имеет прототип C.prototype.

Пример: Заменит прототип по умолчанию и, таким образом, чтобы установить Worker.prototype.constructor [3].

    // Superclass
    function Person(name) {
        this.name = name;
    }
    Person.prototype.describe = function() {
        return "Person called "+this.name;
    };

    // Subclass
    function Worker(name, title) {
        Person.call(this, name);
        this.title = title;
    }
    Worker.prototype = Object.create(Person.prototype);
    Worker.prototype.constructor = Worker;
    Worker.prototype.describe = function() {
        return Person.prototype.describe.call(this)+" ("+this.title+")";
    };

Обратите внимание, что супер-вызовы ортогональны к наследованию нового стиля и будут столь же полезным в коде выше. То же самое справедливо и для оператора прототипа <|.

3. JavaScript против NextScript

Новый подход приводит к нескольким упрощений:

  • В JavaScript экземпляр о имеют два отношения с его классом C: о является экземпляр C и имеют прототип C.prototype. В NextScript, есть только отношения между прототипом экземпляром и классом. В результате instanceof становится проще для понимания.
  • Подклассы: в JavaScript есть косвенность, связанная с подклассами. Чтобы позволить конструктору D подклассу конструктор C, вы должны сделать D.prototype прототипом C.prototype. В NextScript, вы напрямую подключить подкласс суперкласса. В результате также легко определить, является ли один класс подклассом другого.
  • Наследование методы класса: В JavaScript, если класс имеет метод, то подкласс не наследует его. В NextScript, методы класса автоматически наследуются, из-за отношения прототипа.

В целом, прототип чувствует себя подобно естественной конструкции для представления класса.

4. ECMAScript.next: обеспечение совместимости с унаследованным кодом

  • Моя первоначальная идея [1] похожа на гипотетический NextScript, как описано выше.
  • После этого, Аллен Wirfs-Брки предложили, как вещи могут быть адаптированы таким образом, что существующий «протокол класса» не должен быть изменен [2]. Это предложение может сделать это в ECMAScript.next.

    Учитывая не-объект функции C (в «объект класса», прототип как класс):

    • Убедитесь, что C.constructor.prototype указывает на C. Этот шаг необходим для нового оператора к работе, как описано ниже.
    • В следующих двух случаях лечение не-функциональные объекты C по-разному, при этом не изменяя поведение для функций:

      • Интерпретировать новый C (…) как синтаксический сахар для нового C.constructor (…).
      • Интерпретируйте о InstanceOf С, как синтаксический сахар для C.isPrototypeOf (о)
  • Подклассов классы старого стиля: Это может иметь смысл, чтобы позволить новый стиль класса унаследованы от класса старого стиля. Есть два способа сделать это:

    • Вручную: Подкласс расширяет Superclass.prototype. Конструкторы Chaining и супер-вызовы методов должны работать, как ожидалось.
    • Автоматически: Продлить оператор прототипа <| так что, когда он сталкивается с функцией F, как ее левой стороны, это делает f.prototype прототип и не ф.

Обратите внимание, что внутренняя структура все та же, что и раньше. Единственное отличие состоит в том, что переменная, имена класс относится к прототипу и не конструктор.

Улучшены объектные литералы в ECMAScript.next

Предложение «
Объект Буквального Extensions » было принято для ECMAScript.next. Он дополняет идею прототипов как классов. Особенности:

  • Оператор-прототип <|, представленный через NextScript.
  • Супер ссылка, также, как введенные выше.
  • Более короткое обозначение для методов:
        var obj = {
            data: "abc",
            mymethod(x, y) {
                ...
            }
        };
    
  • Сокращение литерала объекта: следующее
        function f(x, y) { return {x, y}; }
    

    является синтаксическим сахаром для

        function f(x, y) { return {x: x, y: y}; }
    

Связанное чтение

  1. Классы: предложения по улучшению [Первоначальная идея, позволяющая создавать новые для нефункциональных объектов]
  2. Прототипы как объявление нового класса [Предложение по обеспечению совместимости с текущим протоколом]
  3. Что случилось со свойством «конструктор» в JavaScript?
  4. Облегченные API наследования JavaScript [в особенности простое наследование Resig выглядит почти как NextScript]

 

С http://www.2ality.com/2011/06/prototypes-as-classes.html