[Предыдущая: Модуль QtSvg] [Модули Qt] [Следующая: Модуль QtXml] Модуль QtScript
Модуль QtScript предоставляет классы для придания приложениям Qt возможности выполнять скрипты. Далее... Классы
Подробное описание
Конфигурирование процесса сборкиПриложения, использующие классы Qt Script, нужно сконфигурировать для сборки вместе с модулем QtScript. Для включения определений классов этого модуля используйте следующую директиву: #include <QtScript> Для линковки приложения с этим модулем, добавьте в ваш qmake файл проекта .pro: QT += script Модуль QtScript является частью Выпуска Qt Desktop и Выпуска Qt Open Source. Обзор языкаQt Script основан на языке сценариев ECMAScript, как описано в стандарте ECMA-262. JScript от Microsoft и JavaScript от Netscape также основаны на стандарте ECMAScript. Обзор ECMAScript смотрите в Справочнике по ECMAScript. Если вы не знакомы с языком ECMAScript, существует несколько учебных пособий и книг, которые освещают эту тему, например, JavaScript: Полное руководство. Существующие пользователи Qt Script for Applications (QSA) при портировании сценариев QSA в Qt Script могут найти полезным документ Миграция с QSA на Qt Script. Основное использованиеДля выполнения кода сценария создайте QScriptEngine и вызовите его функцию evaluate(), передавая в качестве аргумента код сценария (текст) для вычисления. QScriptEngine engine; qDebug() << "the magic number is:" << engine.evaluate("1 + 2").toNumber(); Возвращаемое значение будет результатом вычисления (представленный объектом QScriptValue); его можно конвертировать в стандартные типы C++ и Qt. Пользовательские свойства можно сделать доступными для сценариев, зарегистрировав их с помощью механизма сценариев. Сделать это легче всего установив свойства глобального объекта механизма сценариев: QScriptValue val(&engine, 123); engine.globalObject().setProperty("foo", val); qDebug() << "foo times two is:" << engine.evaluate("foo * 2").toNumber(); Это поместит свойства в окружение сценария, делая их таким образом доступными из кода сценария. Делаем QObject доступным для механизма сценарияЛюбой подкласс QObject можно сделать доступных для использования в сценариях. Когда QObject передаётся в функцию QScriptEngine::newQObject(), создаётся объект-обёртка QtScript, который может быть использован для того, чтобы сделать доступными скрипту сигналы, слоты, свойства и дочерние объекты QObject'а. Поскольку QtScript использует мета-объектную систему Qt, нет необходимости реализовывать каких-либо дополнительных обёрток или привязок. Вот пример создания экземпляра подкласса QObject, доступного из кода сценария под именем "myObject": QScriptEngine engine; QObject *someObject = new MyObject; QScriptValue objectValue = engine.newQObject(someObject); engine.globalObject().setProperty("myObject", objectValue); Функция newQObject() принимает два дополнительных необязательных аргумента: один - режим владения, а другой - набор опций, которые позволяют вам управлять некоторыми аспектами того, как будет себя вести QScriptValue, который служит обёрткой QObject. Мы вернёмся к использованию этих аргументов позднее. Использование сигналов и слотовQtScript использует для соединения с сигналами и отсоединения от сигналов синтаксис, отличный от привычного синтаксиса C++; т.е., QObject::connect()). Для соединения с сигналом вы ссылаетесь на соответствующий сигнал как на свойство объекта отправителя и вызываете его функцию connect(). Имеется три перегрузки для connect(), каждой из них соответствует перегруженная disconnect(). В следующих подразделах описываются эти три формы. Соединения сигнала с функциейconnect(function) В этом виде соединения аргумент для connect() - функция для соединения с сигналом. function myInterestingScriptFunction() { ... } ... myQObject.somethingChanged.connect(myInterestingScriptFunction); Аргумент может быть функцией Qt Script, как в вышеприведенном примере, или он может быть слотом QObject как в следующем примере: myQObject.somethingChanged.connect(myOtherQObject.doSomething); Когда аргументом является слот QObject, типы аргументов сигнала и слота необязательно должны быть совместимы; QtScript будет, если необходимо, выполнять преобразование аргументов сигнала к типам, соответствующих слоту. Для отсоединения от сигнала вы вызываете функцию сигнала disconnect(), передавая в качестве аргумента функцию для отсоединения: myQObject.somethingChanged.disconnect(myInterestingFunction); myQObject.somethingChanged.disconnect(myOtherQObject.doSomething); Когда функция скрипта вызывается в ответ на сигнал, объект `this' будет глобальным объектом. Соединения сигнала с функцией-членомconnect(thisObject, function) В этом виде функции connect() первый аргумент является объектом this, который будет связан с переменной когда вызывается функция, заданная вторым аргументом. Если у вас в форме имеется кнопка, обычно вам нужно что-нибудь сделать на форме в ответ на сигнал кнопки clicked; в таком случае имеет смысл передать форму в качестве объекта this. var obj = { x: 123 }; var fun = function() { print(this.x); }; myQObject.somethingChanged.connect(obj, fun); Для отсоединения от сигнала передайте те же аргументы в disconnect(): myQObject.somethingChanged.disconnect(obj, fun); Соединения сигнала с именованной функцией-членомconnect(thisObject, functionName) В этой форме функции connect() первый аргумент - объект this, который будет связан с переменной, когда в ответ на сигнал вызывается функция. Второй аргумент задает имя функции, которая соединяется с сигналом, и это относится к функции-члену объекта, переданного в качестве первого аргумента (thisObject в вышеприведённой схеме). Обратите внимание на то, что функция разрешается когда производится соединение, а не при испускании сигнала. var obj = { x: 123, fun: function() { print(this.x); } }; myQObject.somethingChanged.connect(obj, "fun"); Для отсоединения от сигнала передайте те же аргументы в disconnect(): myQObject.somethingChanged.disconnect(obj, "fun"); Обработка ошибокКогда connect() или disconnect() выполнены успешно, функция будет возвращать undefined; в противном случае возбуждено исключение сценария. Вы можете извлечь сообщение об ошибке из полученного объекта Error. Пример: try { myQObject.somethingChanged.connect(myQObject, "slotThatDoesntExist"); } catch (e) { print(e); } Испускание сигналов из скриптовДля испускания сигнала из кода сценария просто вызовите функцию сигнала, передав соответствующие аргументы: myQObject.somethingChanged("hello"); Перегруженные сигналы и слотыКогда перегружается сигнал или слот, QtScript будет пытаться выбрать правильную перегрузку основываясь на фактических типах аргументов QScriptValue, содержащихся в вызове функции. Например, если ваш класс имеет слоты myOverloadedSlot(int) и myOverloadedSlot(QString), следующий код сценария будет работать корректно: myQObject.myOverloadedSlot(10); // будет вызвана перегрузка int myQObject.myOverloadedSlot("10"); // будет вызвана перегрузка QString Вы можете указать определённую перегрузку, используя доступ к свойству как к массиву, с нормализованной сигнатурой функции C++ в качестве имени свойства: myQObject['myOverloadedSlot(int)']("10"); // вызывает перегрузку int; аргумент преобразуется к типу int myQObject['myOverloadedSlot(QString)'](10); // вызывает перегрузку QString; аргумент преобразуется к типу string Если перегрузки имеют разное количество аргументов, QtScript выберет перегрузку с тем количеством аргументов, которое лучше всего соответствует фактическому количеству аргументов переданных в слот. Для перегруженных сигналов, QtScript будет соединять с наиболее общей перегрузкой, если вы не укажите сигнал с полной нормализованной сигнатурой. Получение доступа к свойствамСвойства QObject доступны как свойства соответствующего объекта Qt Script. Когда вы работаете со свойством в коде сценария, методы получения/установки значения C++ для этого свойства будут вызываться автоматически. Например, если ваш класс C++ имеет свойство, объявленное как изложено ниже: Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) тогда в коде сценария можно делать примерно такие вещи: myQObject.enabled = true; ... myQObject.enabled = !myQObject.enabled; Получение доступа к дочерним объектам QObjectКаждый дочерний объект QObject по умолчанию доступен как свойство соответствующего объекта Qt Script. Например, если у вас имеется QDialog с дочерним виджетом, чьё свойство objectName() равно "okButton", вы можете получить доступ к этому объекту в коде сценария посредством выражения myDialog.okButton Так как само свойство objectName является Q_PROPERTY, вы можете воспользоваться именем в коде сценария, например, чтобы переименовать объект: myDialog.okButton.objectName = "cancelButton";
// в дальнейшем myDialog.cancelButton ссылается на кнопку
Для поиска дочерних объектов вы можете также использовать функции findChild() и findChildren(). Эти две функции ведут себя точно также как QObject::findChild() и QObject::findChildren(), соответственно. Например, мы можем использовать эти функции для поиска объектов, используя строки и регулярные выражения: var okButton = myDialog.findChild("okButton"); if (okButton != null) { // делаем что-нибудь с кнопкой OK } var buttons = myDialog.findChildren(RegExp("button[0-9]+")); for (var i = 0; i < buttons.length; ++i) { // делаем что-нибудь с buttons[i] } Обычно вы хотите использовать findChild() когда обрабатываете форму, которая использует вложенные компоновки; при этом способе сценарий изолирован от деталей о том, в какой именно компоновке располагается виджет. Управление владением QObjectПо умолчанию, механизм сценариев не получает владения над объектом QObject, который передаётся в QScriptEngine::newQObject(); объект управляется в зависимости от принадлежности объекта Qt (смотрите Деревья объектов и владение объектами). Вы можете изменить это поведение указывая другой режим владения в качестве второго аргумента, перегружая режим по умолчанию (QScriptEngine::QtOwnership). Указание QScriptEngine::ScriptOwnership как режима владения будет приводить механизм сценария к получению полного владения над объектом QObject и удалению его, когда определено что делать это безопасно. Этот режим владения подходит, если QObject не имеет родительского объекта и/или QObject создаётся в контексте механизма сценария и не предназначен для существования после механизма сценария. Например, функция конструктора, которая создаёт объекты QObject только для использования в окружении сценария, является лучшим кандидатом: QScriptValue myQObjectConstructor(QScriptContext *context, QScriptEngine *engine)
{
// позволим механизму управлять временем жизни нового объекта.
return engine->newQObject(new MyQObject(), QScriptEngine::ScriptOwnership);
}
Другим режимом владения является QScriptEngine::AutoOwnership, где владение основано на том имеет ли QObject родителя или нет. Если сборщик мусора QtScript обнаружит, что на QObject больше никто не ссылается в окружении сценария, то QObject будет удалён только если у него нет родителя. Настраиваем доступ к QObjectQScriptEngine::newQObject() может получить третий аргумент, который позволяет вам контролировать различные аспекты доступа к QObject посредством возвращаемого им объекта-обёртки QScriptEngine::ExcludeChildObjects указывает, что дочерние объекты QObject не будут появляться в качестве свойств объекта-обёртки. QScriptEngine::ExcludeSuperClassProperties и QScriptEngine::ExcludeSuperClassMethods могут использоваться чтобы не показывать члены, которые унаследованы от суперкласса QObject'а. Это полезно для определения "чистого" интерфейса, где унаследованные члены не имеют смысл с точки зрения перспективы работы со сценарием; например, вы не хотите, чтобы авторы сценария могли изменить свойство objectName объекта или вызывать слот deleteLater(). QScriptEngine::AutoCreateDynamicProperties указывает, что свойства, которые ещё не существуют в QObject, будут созданы как динамические свойства QObject, а не свойств объект-обёртки QtScript. Если вы хотите чтобы новые свойства действительно стали постоянными свойствами QObject, а не свойствами, которые уничтожаются вместе с объектом-обёрткой (и которые не используются совместно, если QObject обёрнут несколько раз с помощью newQObject()), вы должны использовать эту опцию. Преобразование между типами QtScript и C++QtScript выполняет преобразование типов когда значение нужно преобразовать со стороны сценария на сторону C++ или наоборот; например, когда сигнал C++ запускает функцию сценария, когда вы получаете доступ к свойству QObject в коде сценария, или когда вы вызываете в C++ QScriptEngine::toScriptValue() или QScriptEngine::fromScriptValue(). QtScript предоставляет операции преобразования по умолчанию для многих встроенных типов Qt. Вы можете изменить операцию преобразования типа, зарегистрировав свои собственные функции преобразования с помощью qScriptRegisterMetaType(). В следующей таблице описывается преобразование по умолчанию из QScriptValue в тип C++.
Кроме того, QtScript будет обрабатывать следующие случаи:
В следующей таблице описывается поведение по умолчанию при создании QScriptValue из типа C++:
Другие типы будут обёрнуты используя QScriptEngine::newVariant(). Для нулевых указателей любого типа, результатом будет QScriptEngine::nullValue(). Как спроектировать и реализовать объекты приложенияЭтот раздел объясняет, как реализовать объекты приложения и предоставляет необходимые технические первоисточники. Делаем объект C++ доступным для сценариев, написанных в Qt ScriptСделать классы и объекты C++ доступными для языка сценариев - это не является тривиальным, потому что языки сценариев имеют тенденцию быть более динамичными, чем C++, и они должны иметь возможность анализировать свои объекты (запрашивать во время выполнения такую информацию, как имена функций, сигнатуры функций, свойства и так далее). Стандартный C++ не предоставляет средств для этого. Мы можем добиться желаемой функциональности расширив C++, используя собственные возможности C++ так что наш код останется стандартным C++. Мета-объектная система Qt предоставляет необходимую дополнительную функциональность. Это позволяет нам писать используя расширенный синтаксис C++, но преобразовать это в стандартный C++ используя небольшую утилиту с именем moc (мета-объектный компилятор). Классы, которые желают получить преимущества от мета-объектных возможностей, либо являются подклассами QObject, либо используют макрос Q_OBJECT. Qt использует этот подход многие годы и он доказал свою компактность и надёжность. Qt Script использует эту мета-объектную технологию чтобы представить создателям сценариев динамический доступ к классам и объектам C++. Чтобы полностью понять как сделать объекты C++ доступными для Qt Script, очень полезны некоторые базовые знания мета-объектной системы Qt. Мы рекомендуем прочитать Объектную модель Qt. Информация в этом документе и в документах, на которые в нём ссылаются, очень поможет в понимании того, как реализовывать объекты приложения. Однако, это знание не важно в простейших случаях. Чтобы сделать объект доступным в Qt Script, он должен быть унаследован от QObject. Все классы, которые унаследованы от QObject, могут быть подвергнуты интроспекции и могут предоставлять информацию, необходимую механизму сценариев во время выполнения; например, имя класса, функции, сигнатуры. Поскольку мы получили нужную нам информацию о классах динамически во время выполнения, нет необходимости писать обёртки для классов унаследованных от QObject. Делаем функции-члены класса C++ доступными в Qt ScriptМета-объектная система также делает динамически доступной во время выполнения информацию о сигналах и слотах. По умолчанию, для подклассов QObject только сигналы и слоты автоматически становятся доступными для сценариев. Это очень удобно, поскольку на практике мы обычно хотим сделать доступными для создателей сценариев только специально отобранные функции. Когда вы создаете подкласс QObject, убедитесь что функции, которые вы хотите сделать видимыми для Qt Script, являются открытыми слотами. Например, в следующем определении класса работа со сценариями разрешается только для некоторых функций: class MyObject : public QObject
{
Q_OBJECT
public:
MyObject( ... );
void aNonScriptableFunction();
public slots: // эти функции (слоты) будут доступны в QtScript
void calculate( ... );
void setEnabled( bool enabled );
bool isEnabled() const;
private:
....
};
В примере выше, aNonScriptableFunction() не объявлена как слот, поэтому она не будет доступна в Qt Script. Другие три функции автоматически станут доступны в Qt Script, поскольку они объявлены в разделе public slots определения класса. Можно сделать любую функцию вызываемой из сценария указав модификатор Q_INVOKABLE при объявлении функции: class MyObject : public QObject { Q_OBJECT public: Q_INVOKABLE void thisMethodIsInvokableInQtScript(); void thisMethodIsNotInvokableInQtScript(); ... }; Однажды объявленный с Q_INVOKABLE, метод может быть вызван из кода Qt Script как если бы он был слотом. Несмотря на то, что такой метод не является слотом, вы можете по-прежнему указывать его как целевую функцию в вызове connect() в коде сценария; connect() принимает и "родные" и "не родные" функции в качестве целевых. Делаем свойства класс C++ доступными в Qt ScriptВ предыдущем примере, если вы хотите получить или установить свойство используя Qt Script нам нужно написать код аналогичный следующему: var obj = new MyObject; obj.setEnabled( true ); print( "obj is enabled: " + obj.isEnabled() ); Языки сценариев часто предоставляют синтаксис свойств для модификации и получения значения свойств (в нашем случае состояние задействованности) объекта. Многие создатели сценариев захотят переписать вышеприведённый код примерно так: var obj = new MyObject; obj.enabled = true; print( "obj is enabled: " + obj.enabled ); Чтобы сделать это возможным, вы должны определить свойства в подклассе C++ QObject. Например, в следующем объявлении класса MyObject объявлено булево свойство с именем enabled, которое использует функцию setEnabled(bool) как свою функцию установки значения и isEnabled() - как свою функцию получения значения: class MyObject : public QObject { Q_OBJECT // определяем задействованное свойство Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // эти функции (слоты) будут доступны в QtScript void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; private: .... }; Единственным отличием от первоначального кода заключается в использовании макроса Q_PROPERTY, который получает в качестве аргументов тип и имя свойства, а также имена функций установки и получения значения. Если вам не нужно, чтобы свойство вашего класса было доступно в QtScript, установите атрибут SCRIPTABLE в значение false когда объявляете свойство; по умолчанию, атрибут SCRIPTABLE равен true. Например: Q_PROPERTY(int nonScriptableProperty READ foo WRITE bar SCRIPTABLE false) Реагируем в сценариях на сигналы объектов C++В объектной модели Qt сигналы используются как механизм уведомления между объектами QObject. Это означает, что один объект может соединить сигнал со слотом другого объекта и каждый раз, когда испускается сигнал, будет вызываться слот. Это соединение устанавливается используя функцию QObject::connect(). Механизм сигналов и слотов также доступен программистам Qt Script. Код для объявления сигнала в C++ такой же, независимо от того соединен сигнал со слотом в C++ или в Qt Script. class MyObject : public QObject { Q_OBJECT // определяем задействованное свойство Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // эти функции (слоты) будут доступны в QtScript void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; signals: // сигналы void enabledChanged( bool newState ); private: .... }; Мы сделали единственное изменение в коде в предыдущем разделе - объявили раздел сигналов с соответствующим сигналом. Теперь, создатель сценария может определить функцию и соединить с объектом примерно так: function enabledChangedHandler( b )
{
print( "state changed to: " + b );
}
function init()
{
var obj = new MyObject();
// соединяем функцию скрипта с сигналом
obj["enabledChanged(bool)"].connect(enabledChangedHandler);
obj.enabled = true;
print( "obj is enabled: " + obj.enabled );
}
Проектируем объекты приложенияВ предыдущем разделе описывается, как реализовать объекты C++, которые могут быть использованы в Qt Script. Объекты приложения - это объекты того же рода, и они делают доступной функциональность вашего приложения для создателей сценариев в Qt Script. Поскольку приложение C++ написано на Qt, многие объекты уже являются объектами QObject. Самым лёгким подходом будет просто добавить все эти объекты QObject как объекты приложения в механизм сценария. Для небольших приложений это может быть достаточно, но для больших приложений это, вероятно, не правильный подход. Проблема заключается в том, что этот метод открывает слишком много внутреннего API и даёт программистам сценариев доступ к внутреннему содержимому приложения, которое не должно быть открытым. Как правило, лучшим способом сделать функциональность приложения доступной для создателей сценариев - закодировать несколько объектов QObject, которые определяют открытые API приложения используя сигналы, слоты и свойства. Это даст вам полный контроль над функциональностью, доступной в приложении. В реализациях этих объектов просто вызывайте функции приложения, которые делают реальную работу. Итак, вместо того, чтобы сделать все ваши объекты QObject доступными для механизма сценария, добавьте только объекты-обёртки QObject. Используем наследование, основанное на прототипахВ ECMAScript, наследование базируется на концепции совместно используемых объектов-прототипов; это полностью отличается от наследования на основе классов, привычного для программистов C++. С Qt Script, вы можете связать пользовательский объект-прототип с типом C++ используя QScriptEngine::setDefaultPrototype(); это является ключевым для предоставления интерфейса сценария для этого типа. Так как модуль QtScript построен на основе системы мета-типов Qt, это можно сделать для любого типа C++. Этот раздел объясняет базовые концепции наследования, основанного на прототипах. Поняв эти концепции, связанные приёмы работы могут быть применены по всему QtScript API для того, чтобы создать удобные, согласованные привязки к C++, которые будут хорошо подходит для области ECMAScript. При экспериментировании с объектами QtScript и наследованием может быть полезным использование интерактивного интерпретатора, включённого в примеры QtScript, расположенного в examples/script/qscript. Объекты-прототипы и совместно используемые свойстваВ Qt Script назначение объекта-прототипа заключается в определении поведения, которое будет совместно использоваться набором объектов QtScript. Мы говорим, что объекты которые используют совместно одни и те же объекты-прототипы принадлежат одному и тому же классу (кроме того, с технической стороны они не будут смешиваться с классами, создаваемыми языками наподобие C++ и Java; ECMAScript не имеет такой конструкции). Базовый механизм наследования, основанного на прототипах, работает следующим образом: Каждый объект QtScript имеет внутреннюю ссылку на другой объект, его прототип. Когда в объекте ищется свойство, а сам объект не имеет свойства, то вместо этого свойство ищется в объекте-прототипе; если прототип имеет свойство, тогда возвращается это свойство. В противном случае, свойство ищется в прототипе объекта-прототипа, и так далее; эта цепочка объектов составляет последовательность прототипов. Последовательность объектов-прототипов прослеживается до тех пор, пока свойство не найдётся или не будет достигнут конец цепочки. Например, когда вы создаёте новый объект с помощью выражения new Object(), результирующий объект будет иметь своим прототипом стандартный прототип Object, Object.prototype; посредством этих отношений прототипов, новый объект наследует набор свойств, включая функцию hasOwnProperty() и функцию toString(): var o = new Object(); o.foo = 123; print(o.hasOwnProperty('foo')); // истина print(o.hasOwnProperty('bar')); // ложь print(o); // вызывает o.toString(), которая возвращает "[object Object]" Сама функция toString() не определена в o (так как мы ничего не присвоили o.toString), таким образом вместо функции toString() стандартного объекта Object вызывается прототип, который возвращает сильно обобщённое строковое представление o ("[object Object]"). Обратите внимание на то, что свойства объекта не копируются в новый объект; поддерживается только ссылка из нового объекта на объект прототипа. Это означает, что изменения, произведённые в объекте-прототипе, немедленно отразятся на поведении всех объектов, для которых модифицированный объект является прототипом. Определение классов в области, основанной на прототипахВ Qt Script класс не определяется явно; ключевого слова class нет. Вместо этого вы определяете новый класс в два этапа:
С таким расположением, открытое свойство prototype конструктора будет автоматически установлено в качестве прототипа объектов, созданных применением оператора new к вашей функции конструктора; например, прототипом объекта, созданного new Foo(), будет значение Foo.prototype. Функции, которые не работают с объектом this ("статические" методы) обычно сохраняются как свойства функции конструктора, а не как свойства объекта-прототипа. Тоже самое верно для констант, например, значений перечисления. В следующем коде определяется простая функция конструктора для класса с именем Person: function Person(name) { this.name = name; } Затем вы хотите настроить Person.prototype как ваш объект-прототип; т.е., определить интерфейс, который будет общим для всех объектов Person. Qt Script автоматически создаёт объект-прототип по умолчанию (с помощью выражения new Object()) для каждой функции сценария; вы можете добавить свойства в этот объект, или вы можете присвоить ваш собственный пользовательский объект. (Вообще говоря, любой QtScript объект может действовать как прототип для любого другого объекта.) Вот пример того, как вы можете перегрузить функцию toString(), которая унаследовала Person.prototype от Object.prototype, чтобы дать вашим объектам Person более подходящие строковые представления: Person.prototype.toString = function() { return "Person(name: " + this.name + ")"; } Это имеет сходство с процессом переопределения виртуальной функции в C++. Впредь, когда ищется прототип с именем toString в объекте Person, он будет разрешён в Person.prototype, а не в Object.prototype как до этого: var p1 = new Person("John Doe"); var p2 = new Person("G.I. Jane"); print(p1); // "Person(name: John Doe)" print(p2); // "Person(name: G.I. Jane)" Имеется еще несколько других интересных вещей, которые узнали об объекте Person: print(p1.hasOwnProperty('name')); // 'name' - переменная экземпляра, поэтому это вернёт true print(p1.hasOwnProperty('toString')); // вернёт false; унаследовано от прототипа print(p1 instanceof Person); // истина print(p1 instanceof Object); // истина Функция hasOwnProperty() не унаследована от Person.prototype, а точнее от Object.prototype, который сам является прототипом для Person.prototype; т.е., цепочка прототипов объектов Person - это Person.prototype следом за Object.prototype. Эта цепочка прототипов устанавливает иерархию классов, как продемонстрирует применение оператора instanceof; instanceof проверяет значение открытого свойства prototype функции конструктора с правой стороны - достигается ли следуя по цепочке прототипов объекта с левой стороны. Когда определяются подклассы, имеется общий шаблон, который вы можете использовать. В следующем примере показано, как он может создать подкласс Person вызывая Employee: function Employee(name, salary) { Person.call(this, name); // вызывает базовый конструктор this.salary = salary; } // устанавливает прототип экземпляра базового класса Employee.prototype = new Person(); // инициализирует прототип Employee.prototype.toString = function() { ... } С другой стороны, вы можете использовать instanceof для проверки того, что отношения между классами Employee и Person были установлены правильно: var e = new Employee("Johnny Bravo", 5000000); print(e instanceof Employee); // истина print(e instanceof Person); // истина print(e instanceof Object); // истина print(e instanceof Array); // ложь Это показывает, что цепочка прототипов объектов Employee такая же что и у объектов Person, но с Employee.prototype добавленным в головную часть цепочки. Программирование на основе прототипов с помощью QtScript C++ APIВы можете использовать QScriptEngine::newFunction() для обёртывания "родных" функций. При реализации функции конструктора вы также передаёте объект-прототип в качестве аргумента в QScriptEngine::newFunction(). Вы можете вызывать QScriptValue::construct() для вызова функции конструктора, и вы можете использовать QScriptValue::call() изнутри "родной" функции конструктора если вам нужно вызвать конструктор базового класса. Класс QScriptable предоставляет удобный способ реализации объекта-прототипа на основе слотов и свойств C++. Ознакомьтесь с Примером "Default Prototypes" чтобы увидеть, как это делается. В качестве альтернативы, функциональность прототипа может реализована на основе автономных "родных" функций, которые вы обёртываете с помощью QScriptEngine::newFunction() и устанавливаете как свойства вашего объект-прототипа вызывая QScriptValue::setProperty(). В реализации функций вашего прототипа, вы используете QScriptable::thisObject() (или QScriptContext::thisObject()) для получения ссылки на QScriptValue, с которой работаете; затем вы вызываете qscriptvalue_cast() для приведения его к вашему типу C++, и выполнению соответствующих операций используя для этого типа обычный C++ API. Вы связываете объект-прототип с типом C++ вызывая QScriptEngine::setDefaultPrototype(). Однажды установив это отображение, Qt Script будет автоматически присваивать правильный прототип когда значение типа такого типа обёрнуто в QScriptValue; когда вы явно вызываете либо QScriptEngine::toScriptValue(), либо когда значение такого типа возвращается из слота C++ и передаётся изнутри механизмом обратно в код сценария. Это означает, что вы не можете реализовать классы-обёртки, если используете этот подход. Совместимость с ECMAScriptQt Script реализует все встроенные классы и функции, определённые в стандарте ECMA-262. Функции синтаксического разбора и строковых преобразований Date реализованы с использованием QDateTime::fromString() и QDateTime::toString(), соответственно. Класс RegExp является обёрткой вокруг QRegExp. Семантика QRegExp точно не совпадает с семантикой регулярных выражений, описанной в ECMA-262. Расширения Qt Script для ECMAScript
[Предыдущая: Модуль QtSvg] [Модули Qt] [Следующая: Модуль QtXml]
|
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |