2010-10-21 3 views
0

Я пытаюсь реализовать некоторую иерархию классов в JavaScript. I думаю, что я понял цепочку прототипов, но мне все же приходится разбираться в цепочке конструкторов . После Дэвид Фланегана, Definitive Guide, я написалЦепочки-конструкторы в JavaScript

function DerivedClass() 
{ 
    BaseClass.apply(this, arguments); // chain constructors 
    // do some initializations specific to DerivedClass... 
} 

var foo = new DerivedClass(); 

где BaseClass() является уроженцем функцией шахты, написанной в C++ (я с помощью QtScript). Моя проблема в том, что тогда BaseClass() называется как функция, а не как конструктор.

Я мог бы указать BaseClass(), чтобы всегда вести себя как конструктор, однако он вызывается . Но я боюсь, что когда-нибудь один из моих пользователей может забыть new и просто написать

var bar = BaseClass(); 

В такой ситуации, я хотел бы BaseClass() сделать что-то более осмысленное, чем инициализации глобального объекта. Например:

if (!context->isCalledAsConstructor()) fail_gracefully(); 

Но тогда цепь конструктора терпит неудачу!

Есть ли способ, которым я могу связать конструкторы и иметь BaseClass() действительно можно назвать конструктором? Или я должен просто обучать своих пользователей , чтобы никогда не забыть new? Сейчас я соблазн заменить тест выше по:

if (context->thisObject().strictlyEquals(engine->globalObject())) 
    fail_gracefully(); 

, но мне интересно, если есть более чистый способ справиться с этим.

Спасибо!

ответ

0

Отвечая себя ...

Я думал о моей проблеме на ночь ... и я думаю, что я нашел несколько более Удовлетворительное решение: вести себя как конструктор, если this является экземпляр Калье. Этот тест несколько более строгий, чем проверка того, является ли он не глобальным объектом, но он по-прежнему позволяет создавать цепочку построения цепочки, пока прототипы были правильно скованы.

Вот первые строки моего родного конструктора (SerialPort мой базовый класс, построенный вокруг QSerialDevice):

/* 
* Should we behave as a constructor? 
* 
* We could use context->isCalledAsConstructor() to decide. However, 
* we may want to subclass SerialPort in JavaScript and chain the 
* constructors: 
* 
*  function DerivedClass() 
*  { 
*   SerialPort.apply(this, arguments); 
*   // do some more initializations... 
*  } 
* 
* This would fail if we decided on the basis of 
* context->isCalledAsConstructor(). The test below is somewhat less 
* strict. It allows constructor chaining provided the prototypes 
* have been properly chained. 
*/ 
bool behave_as_constructor = 
    context->thisObject().instanceOf(context->callee()); 

Забавная вещь об этом: в отличие от isCalledAsConstructor(), это тест также может быть реализован в JavaScript constuctor!

0

Вы должны воспитывать своих пользователей, чтобы никогда не забыть new.

Все «конструкторы» в JavaScript просто являются функциями, поэтому вы не можете защитить от конструктора, вызываемого как функция.

Неверный JavaScript, чтобы попытаться создать новый объект, не используя new. Просто потому, что не существует «предупреждения времени компиляции», как есть в Java, это не делает его другим.

+0

Ну, технически я могу защитить их, либо выбросив исключение, либо проигнорировав «это» и вернув совершенно новый объект (например, «Массив()»). Моя проблема в том, что первый вариант мешает цепочке конструкторов, в то время как вторая не играет хорошенько с цепочкой прототипов. –

Смежные вопросы