Qt 5.5 中Qt Script翻译 (六)

接着上一章

构造函数

一些脚本函数是构造函数;它们期望初始化 new 对象。下面的片段是一个小例子:

 function Book(isbn) {
      this.isbn = isbn;
  }

  var coolBook1 = new Book("978-0131872493");
  var coolBook2 = new Book("978-1593271473");

构造函数没有什么特别之处。事实上,任何脚本函数都可以充当构造函数(即,任何函数都可以充当new的操作数)。有些函数根据它们是否作为 new 表达式的一部分被调用而具有不同的行为;例如,表达式new Number(1)将创建一个Number对象,而Number(“123”)将执行类型转换。其他函数,如Array(),将始终创建和初始化新对象(例如,new Array()和Array()具有相同的效果)。

本地Qt Script函数可以调用QScriptContext::isCalledAsConstructor()函数来确定它是作为构造函数调用还是作为常规函数调用。当函数被调用为构造函数时(即,它是new表达式中的操作数),这具有两个重要的含义:

  • 这个对象QScriptContext::thisObject()包含要初始化的新对象;引擎在调用函数之前自动创建这个新对象。这意味着本地构造函数在被调用为构造函数时通常不必(也不应该)创建新对象,因为引擎已经准备了一个新对象。相反,您的函数应该对提供的对象进行操作。
  • 如果将构造函数当做一个普通函数调用,构造函数应该返回一个未定义的值QScriptEngine::.undefinedValue(),告诉引擎这个对象应该是new操作符的最终结果。如果通过new表达式操作,则函数可以返回这个对象本身。

当QScriptContext::isCalledAsConstructor()返回false,你的构造函数如何处理这种情况取决于你想要做什么。如果与内置Number()函数一样,普通函数调用应该执行其参数的类型转换,则执行转换并返回结果。另一方面,如果希望构造函数的行为像调用构造函数(带有new)一样,则必须显式地创建新对象(即,忽略this对象),初始化该对象并返回它。

下面的示例实现了一个构造函数,该函数总是创建和初始化新对象:

 QScriptValue Person_ctor(QScriptContext *ctx, QScriptEngine *eng)
  {
      QScriptValue object;
      if (ctx->isCalledAsConstructor()) {
          object = ctx->thisObject();
      } else {
          object = eng->newObject();
          object.setPrototype(ctx->callee().property("prototype"));  //???????
      }
      object.setProperty("name", ctx->argument(0));
      return object;
  }

给定此构造函数,脚本能够使用表达式new Person("Bob")或Person("Bob")来创建新的Person对象;二者的行为方式相同。

对于在脚本代码中定义的函数,没有等效的方法来确定它是否被作为构造函数调用。

注意,即使它不被认为是好的方式,当函数被调用为构造函数并创建自己的对象时,也没有什么可以阻止您选择忽略默认构造的(this)对象;只要让构造函数返回该对象即可。对象将“override”引擎构建的默认对象(即,默认对象将简单地在内部丢弃)。

将数据绑定到函数

即使函数是全局的,也就是说,不与任何特定的(类型)对象相关联,您可能仍然希望将一些数据与它关联起来,从而使其成为自包含的;例如,函数可以有一个指向它需要访问的C++资源的指针。如果您的应用程序只使用一个脚本引擎,或者在所有脚本引擎之间都可以共享相同的C++资源,您可以简单地使用静态C++变量,并从原生QT脚本函数中访问它。

在这种情况下,使用静态C++变量或Singleton类不合适的,可以在函数对象上调用QScriptValue::setProperty(),但是要注意,脚本代码也可以访问这些属性。

另一种方法是使用QScriptValue::setData();这个数据不是脚本可访问的。实现可以通过QScriptContext::callee()函数访问这个内部数据,该函数返回被调用的函数对象。下面的示例演示了如何使用:

QScriptValue rectifier(QScriptContext *ctx, QScriptEngine *eng)
  {
      QRectF magicRect = qscriptvalue_cast<QRectF>(ctx->callee().data());
      QRectF sourceRect = qscriptvalue_cast<QRectF>(ctx->argument(0));
      return eng->toScriptValue(sourceRect.intersected(magicRect));
  }

  ...

  QScriptValue fun = eng.newFunction(rectifier);
  QRectF magicRect = QRectF(10, 20, 30, 40);
  fun.setData(eng.toScriptValue(magicRect));
  eng.globalObject().setProperty("rectifier", fun);

将本地函数作为另一个函数的参数

如前所述,函数对象可以作为参数传递给另一个函数;当然,对于本机函数也是如此。举个例子,这里是一个本地比较函数,它比较了两个参数:

 QScriptValue myCompare(QScriptContext *ctx, QScriptEngine *eng)
  {
      double first = ctx->argument(0).toNumber();
      double second = ctx->argument(1).toNumber();
      int result;
      if (first == second)
          result = 0;
      else if (first < second)
          result = -1;
      else
          result = 1;
      return result;
  }

上面的函数可以作为参数传递给Array.prototype.sort函数来对数组进行数值排序,因为下面的C++代码说明:

QScriptEngine eng;
  QScriptValue comparefn = eng.newFunction(myCompare);
  QScriptValue array = eng.evaluate("new Array(10, 5, 20, 15, 30)");
  array.property("sort").call(array, QScriptValueList() << comparefn);

  // prints "5,10,15,20,30"
  qDebug() << array.toString();

注意,在本例中,我们真正地将本地函数对象作为值对待——即,我们不将其存储为脚本环境的属性——我们只是将其作为“匿名”参数传递给另一个脚本函数,然后忘记它。

激活对象

每个Qt Script函数调用都有一个与之关联的激活对象,这个对象可以通过QScriptContext::activationObject() 函数访问。激活对象是一个脚本对象,其属性是与调用相关联的本地变量(包括脚本函数具有相应形式参数名称的参数)。因此,从C++中获取、修改、创建和删除局部变量是使用常规QScriptValue::property()和QScriptValue::setProperty()函数完成的。激活对象本身不能直接从脚本代码访问(但是无论何时从本地变量读取或写入本地变量,都会隐式地访问它)。

对于C++代码,激活对象有两个主要的应用:

  • 激活对象通过将其用作QScriptValueIterator的输入,提供了遍历与函数调用相关联的变量的标准方法。这对于调试目的非常有用。
  • 激活对象可用于准备当内联评估脚本时应该可用的本地变量;这可以被视为向脚本本身传递参数的一种方式。此技术通常与QScriptEngine::pushContext()结合使用,如下面的示例所示:
QScriptContext *ctx = eng.pushContext();
  QScriptValue act = ctx->activationObject();
  act.setProperty("digit", 7);

  qDebug() << eng.evaluate("digit + 1").toNumber(); // 8

  eng.popContext();

我们创建临时执行上下文,为其创建本地变量,评估脚本,最后恢复旧上下文。

Property Getters and Setters

脚本对象属性可以定义为一个getter/setter函数,类似于Qt C++属性如何与它相关联的读写函数。这使得脚本可以使用object.x而不是object.getX()之类的表达式;每当访问属性时,就会隐式地调用x的getter/setter函数。对于脚本,属性看起来和行为就像一个常规对象属性。

单个Qt脚本函数可以作为属性的getter和setter。当它被当做getter调用时,参数计数为0。当它作为setter调用时,参数计数为1;参数是属性的新值。在下面的示例中,我们定义了一个本地组合的getter/setter,它

 QScriptValue getSet(QScriptContext *ctx, QScriptEngine *eng)
  {
      QScriptValue obj = ctx->thisObject();
      QScriptValue data = obj.data();
      if (!data.isValid()) {
          data = eng->newObject();
          obj.setData(data);
      }
      QScriptValue result;
      if (ctx->argumentCount() == 1) {
          QString str = ctx->argument(0).toString();
          str.replace("Roberta", "Ken");
          result = str;
          data.setProperty("x", result);
      } else {
          result = data.property("x");
      }
      return result;
  }

?????????????????待续。。。。。???????????????????

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值