Это сообщение описывает предложение для создания классов и наследования проще в 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}; }
Связанное чтение
- Классы: предложения по улучшению [Первоначальная идея, позволяющая создавать новые для нефункциональных объектов]
- Прототипы как объявление нового класса [Предложение по обеспечению совместимости с текущим протоколом]
- Что случилось со свойством «конструктор» в JavaScript?
- Облегченные API наследования JavaScript [в особенности простое наследование Resig выглядит почти как NextScript]