整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          一文讀懂QML(QtingLanguage)

          一文讀懂QML(QtingLanguage)

          ML(Qt Modeling Language)是一種用于描述用戶(hù)界面的聲明性語(yǔ)言,它是Qt框架中用于創(chuàng)建現(xiàn)代、動(dòng)態(tài)用戶(hù)界面的一種重要方式。QML提供了豐富的功能,包括但不限于以下幾個(gè)方面:

          1. 聲明式語(yǔ)法:QML使用類(lèi)似JavaScript的語(yǔ)法來(lái)描述用戶(hù)界面,使得界面的定義更加直觀(guān)和易于理解。
          2. 視圖控件:QML提供了豐富的視圖控件,如ListView、GridView等,用于展示列表、網(wǎng)格等數(shù)據(jù)結(jié)構(gòu)。
          3. 交互:QML支持豐富的交互方式,包括鼠標(biāo)、觸摸、鍵盤(pán)等輸入設(shè)備的處理,以及動(dòng)畫(huà)、過(guò)渡效果等。
          4. 繪圖和動(dòng)畫(huà):QML內(nèi)置了強(qiáng)大的繪圖和動(dòng)畫(huà)功能,可以實(shí)現(xiàn)復(fù)雜的圖形效果和動(dòng)畫(huà)效果。
          5. 狀態(tài)管理:QML提供了狀態(tài)機(jī)(State)和轉(zhuǎn)換(Transition)的支持,用于管理界面的不同狀態(tài)和狀態(tài)之間的切換。
          6. 信號(hào)與槽:QML支持信號(hào)與槽機(jī)制,使得不同組件之間可以進(jìn)行靈活的通信和交互。
          7. 嵌入JavaScript代碼:QML允許在界面描述文件中嵌入JavaScript代碼,從而可以實(shí)現(xiàn)更加復(fù)雜的邏輯和功能。
          8. 跨平臺(tái)支持:QML可以和C++代碼無(wú)縫集成,能夠在不同平臺(tái)上運(yùn)行,包括桌面、移動(dòng)設(shè)備等。
          9. 適配性:QML支持自適應(yīng)布局,可以根據(jù)不同的屏幕尺寸和分辨率進(jìn)行靈活的布局調(diào)整。

          總之,QML作為Qt框架中重要的一部分,提供了豐富的功能和靈活的特性,使得開(kāi)發(fā)者能夠快速構(gòu)建現(xiàn)代化的用戶(hù)界面,并可以輕松實(shí)現(xiàn)豐富的交互效果和動(dòng)畫(huà)效果。

          間因素

          開(kāi)發(fā)程序時(shí),必須盡可能實(shí)現(xiàn)一致的60幀/秒刷新率。60幀/秒意味著每幀之間大約有16毫秒可以進(jìn)行處理,其中包括將繪圖基元上傳到圖形硬件所需的處理。

          那么,就需要注意以下幾個(gè)重要的點(diǎn):

          1.盡可能使用異步,事件驅(qū)動(dòng)編程

          2.使用工作線(xiàn)程進(jìn)行重要處理

          3.永遠(yuǎn)不要手動(dòng)控制事件循環(huán)

          4.在阻塞函數(shù)中,每幀的花費(fèi)不要超過(guò)幾毫秒

          如果不這樣做,那么將會(huì)發(fā)生調(diào)整,影響用戶(hù)體驗(yàn)。

          注意:永遠(yuǎn)不應(yīng)該使用的模式是創(chuàng)建自己的QEventLoop或調(diào)用QCoreApplication :: processEvents(),以避免在從QML調(diào)用的C ++代碼塊中阻塞。這樣做非常危險(xiǎn),因?yàn)楫?dāng)在信號(hào)處理程序或綁定中輸入事件循環(huán)時(shí),QML引擎繼續(xù)運(yùn)行其他綁定,動(dòng)畫(huà),轉(zhuǎn)換等。然后這些綁定會(huì)導(dǎo)致副作用,例如,破壞包含整體層次結(jié)構(gòu)事件循環(huán)。

          剖析

          最重要的提示是:使用Qt Creator附帶的QML分析器。了解應(yīng)用程序在何處花費(fèi)時(shí)間將使您能夠?qū)W⒂趯?shí)際存在的問(wèn)題區(qū)域,而不是可能存在的問(wèn)題區(qū)域。有關(guān)如何使用QML分析工具的更多信息,請(qǐng)參閱Qt creator 幫助文檔。

          如果不進(jìn)行分析而直接去優(yōu)化代碼,可能效果并不會(huì)很明顯,借助分析器將會(huì)更快的定位到消耗性能的模塊,然后再進(jìn)行重新設(shè)計(jì),以便提高性能。

          JavaScript代碼

          大多數(shù)QML應(yīng)用程序?qū)⒁詣?dòng)態(tài)函數(shù)、信號(hào)處理程序和屬性綁定表達(dá)式的形式包含大量JavaScript代碼。這通常不是問(wèn)題,由于QML引擎中的一些優(yōu)化,例如對(duì)綁定編譯器所做的那些優(yōu)化,它可以(在某些用例中)比調(diào)用C ++函數(shù)更快。但是,必須注意確保不會(huì)意外觸發(fā)不必要的處理。

          綁定

          QML中有兩種類(lèi)型的綁定:優(yōu)化綁定和非優(yōu)化綁定。保持綁定表達(dá)式盡可能簡(jiǎn)單是一個(gè)好主意,因?yàn)镼ML引擎使用優(yōu)化的綁定表達(dá)式求值程序,它可以評(píng)估簡(jiǎn)單的綁定表達(dá)式,而無(wú)需切換到完整的JavaScript執(zhí)行環(huán)境。與更復(fù)雜(非優(yōu)化)的綁定相比,這些優(yōu)化的綁定的評(píng)估效率更高。優(yōu)化綁定的基本要求是在編譯時(shí)必須知道所訪(fǎng)問(wèn)的每個(gè)符號(hào)的類(lèi)型信息。

          綁定表達(dá)式時(shí)要避免的事情,以達(dá)到最大的優(yōu)化:

          1.聲明中間JavaScript變量

          2.訪(fǎng)問(wèn)“var”屬性

          3.調(diào)用JavaScript函數(shù)

          4.構(gòu)造閉包或在綁定表達(dá)式中定義函數(shù)

          5.訪(fǎng)問(wèn)直接評(píng)估范圍之外的屬性

          6.寫(xiě)作其他屬性作為副作用

          立即評(píng)估范圍可以概括為它包含:

          1.表達(dá)式范圍對(duì)象的屬性(對(duì)于綁定表達(dá)式,這是屬性綁定所屬的對(duì)象)

          2.組件中任何對(duì)象的ID

          3.組件中根項(xiàng)的屬性

          來(lái)自其他組件的對(duì)象和任何此類(lèi)對(duì)象的屬性,以及JavaScript導(dǎo)入中定義或包含的符號(hào)都不在直接評(píng)估范圍內(nèi),因此不會(huì)優(yōu)化訪(fǎng)問(wèn)任何這些對(duì)象的綁定。

          類(lèi)型轉(zhuǎn)換

          使用JavaScript的一個(gè)主要成本是,在大多數(shù)情況下,當(dāng)訪(fǎng)問(wèn)QML類(lèi)型的屬性時(shí),會(huì)創(chuàng)建一個(gè)包含底層C ++數(shù)據(jù)(或?qū)λ囊茫┑耐獠抠Y源的JavaScript對(duì)象。在大多數(shù)情況下,這是不會(huì)太影響性能,但在其他情況下,它可能相當(dāng)消耗性能。比如是將C ++ QVariantMap Q_PROPERTY分配給QML“variant”屬性。列表也可能是有損性能的,盡管(特定類(lèi)型的序列的QList為int, qreal,布bool,QString,和QUrl)應(yīng)該相對(duì)來(lái)說(shuō)不會(huì)太影響, 其他列表類(lèi)型可能會(huì)帶來(lái)昂貴的轉(zhuǎn)換成本(創(chuàng)建新的JavaScript數(shù)組,逐個(gè)添加新類(lèi)型,從C ++類(lèi)型實(shí)例到JavaScript值的每類(lèi)型轉(zhuǎn)換)。

          在一些基本屬性類(lèi)型(例如“string”和“url”屬性)之間轉(zhuǎn)換也可能很影響性能。使用最接近的匹配屬性類(lèi)型將避免不必要的轉(zhuǎn)換。

          如果必須將QVariantMap公開(kāi)給QML,請(qǐng)使用“var”屬性而不是“variant”屬性。一般來(lái)說(shuō),對(duì)于來(lái)自QtQuick 2.0及更新版本的每個(gè)用例,“property var”應(yīng)該被認(rèn)為優(yōu)于“property variant” (注意“property variant”被標(biāo)記為過(guò)時(shí)),因?yàn)樗试S真正的JavaScript引用存儲(chǔ)(可以減少某些表達(dá)式中所需的轉(zhuǎn)換次數(shù))。

          解決屬性

          雖然在某些情況下可以緩存和重用查找結(jié)果,但如果可能的話(huà),最好完全避免完成不必要的工作。

          在下面的示例中,我們有一個(gè)經(jīng)常運(yùn)行的代碼塊(在這種情況下,它是顯式循環(huán)的內(nèi)容;但它可能是一個(gè)通常評(píng)估的綁定表達(dá)式,例如),在其中,我們解決了具有“rect”id及其“color”屬性的對(duì)象多次調(diào)用:

          // bad.qml
          import QtQuick 2.3
          
          Item {
              width: 400
              height: 200
              Rectangle {
                  id: rect
                  anchors.fill: parent
                  color: "blue"
              }
          
              function printValue(which, value) {
                  console.log(which + "=" + value);
              }
          
              Component.onCompleted: {
                  var t0=new Date();
                  for (var i=0; i < 1000; ++i) {
                      printValue("red", rect.color.r);
                      printValue("green", rect.color.g);
                      printValue("blue", rect.color.b);
                      printValue("alpha", rect.color.a);
                  }
                  var t1=new Date();
                  console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
              }
          }

          我們可以在塊中只解析一次公共基數(shù):

          // good.qml
          import QtQuick 2.3
          
          Item {
              width: 400
              height: 200
              Rectangle {
                  id: rect
                  anchors.fill: parent
                  color: "blue"
              }
          
              function printValue(which, value) {
                  console.log(which + "=" + value);
              }
          
              Component.onCompleted: {
                  var t0=new Date();
                  for (var i=0; i < 1000; ++i) {
                      var rectColor=rect.color; // resolve the common base.
                      printValue("red", rectColor.r);
                      printValue("green", rectColor.g);
                      printValue("blue", rectColor.b);
                      printValue("alpha", rectColor.a);
                  }
                  var t1=new Date();
                  console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
              }
          }

          只需這一簡(jiǎn)單的改變就可以顯著提高性能。請(qǐng)注意,上面的代碼可以進(jìn)一步改進(jìn)(因?yàn)樵谘h(huán)處理期間查找的屬性永遠(yuǎn)不會(huì)改變),通過(guò)將屬性解析提升出循環(huán),如下所示:

          // better.qml
          import QtQuick 2.3
          
          Item {
              width: 400
              height: 200
              Rectangle {
                  id: rect
                  anchors.fill: parent
                  color: "blue"
              }
          
              function printValue(which, value) {
                  console.log(which + "=" + value);
              }
          
              Component.onCompleted: {
                  var t0=new Date();
                  var rectColor=rect.color; // resolve the common base outside the tight loop.
                  for (var i=0; i < 1000; ++i) {
                      printValue("red", rectColor.r);
                      printValue("green", rectColor.g);
                      printValue("blue", rectColor.b);
                      printValue("alpha", rectColor.a);
                  }
                  var t1=new Date();
                  console.log("Took: " + (t1.valueOf() - t0.valueOf()) + " milliseconds for 1000 iterations");
              }
          }

          屬性綁定

          如果更改了引用的任何屬性,則將重新評(píng)估屬性綁定表達(dá)式。因此,綁定表達(dá)式應(yīng)盡可能簡(jiǎn)單。

          如果你有一個(gè)循環(huán)來(lái)進(jìn)行某些處理,但只有處理的最終結(jié)果很重要,通常最好更新一個(gè)臨時(shí)累加器,然后將其分配給需要更新的屬性,而不是逐步更新屬性本身,以避免在累積的中間階段觸發(fā)重新評(píng)估結(jié)合表達(dá)。

          以下的例子說(shuō)明了這一點(diǎn):

          // bad.qml
          import QtQuick 2.3
          
          Item {
              id: root
              width: 200
              height: 200
              property int accumulatedValue: 0
          
              Text {
                  anchors.fill: parent
                  text: root.accumulatedValue.toString()
                  onTextChanged: console.log("text binding re-evaluated")
              }
          
              Component.onCompleted: {
                  var someData=[ 1, 2, 3, 4, 5, 20 ];
                  for (var i=0; i < someData.length; ++i) {
                      accumulatedValue=accumulatedValue + someData[i];
                  }
              }
          }
          

          onCompleted處理程序中的循環(huán)導(dǎo)致“text”屬性綁定被重新評(píng)估六次(然后導(dǎo)致依賴(lài)于文本值的任何其他屬性綁定,以及onTextChanged信號(hào)處理程序,每次重新評(píng)估時(shí)間,并列出每次顯示的文本)。在這種情況下,這顯然是不必要的,因?yàn)槲覀冎魂P(guān)心最終的值。

          那么,以上代碼可以改成這樣:

          // good.qml
          import QtQuick 2.3
          
          Item {
              id: root
              width: 200
              height: 200
              property int accumulatedValue: 0
          
              Text {
                  anchors.fill: parent
                  text: root.accumulatedValue.toString()
                  onTextChanged: console.log("text binding re-evaluated")
              }
          
              Component.onCompleted: {
                  var someData=[ 1, 2, 3, 4, 5, 20 ];
                  var temp=accumulatedValue;
                  for (var i=0; i < someData.length; ++i) {
                      temp=temp + someData[i];
                  }
                  accumulatedValue=temp;
              }
          }

          序列提示

          如前所述,某些序列類(lèi)型很快(例如,QList ,QList ,QList ,QList < QString >,QStringList和QList < QUrl >),而其他序列類(lèi)型則要慢得多。除了盡可能使用這些類(lèi)型而不是較慢類(lèi)型之外,還需要注意一些其他與性能相關(guān)的語(yǔ)法以獲得最佳性能。

          首先,對(duì)于序列類(lèi)型的兩種不同的實(shí)現(xiàn):一個(gè)是當(dāng)序列是Q_PROPERTY一個(gè)的QObject的(我們稱(chēng)此為參考序列),另一個(gè)用于在序列從返回Q_INVOKABLE一個(gè)功能的QObject(我們將這稱(chēng)為復(fù)制序列)。

          通過(guò)QMetaObject :: property()讀取和寫(xiě)入引用序列,因此讀取和寫(xiě)入QVariant。這意味著從JavaScript更改序列中任何元素的值將導(dǎo)致三個(gè)步驟發(fā)生:將從QObject讀取完整序列(作為QVariant,但隨后轉(zhuǎn)換為正確類(lèi)型的序列); 指定索引處的元素將在該序列中更改; 并且完整的序列將被寫(xiě)回QObject(作為QVariant)。

          復(fù)制序列更簡(jiǎn)單,因?yàn)閷?shí)際序列存儲(chǔ)在JavaScript對(duì)象的資源數(shù)據(jù)中,因此不會(huì)發(fā)生讀取/修改/寫(xiě)入循環(huán)(而是直接修改資源數(shù)據(jù))。

          因此,對(duì)參考序列的元素的寫(xiě)入將比寫(xiě)入復(fù)制序列的元素慢得多。實(shí)際上,寫(xiě)入N元素參考序列的單個(gè)元素與將N元素復(fù)制序列分配給該參考序列的成本相當(dāng)大,因此通常最好修改臨時(shí)復(fù)制序列,然后將結(jié)果分配給計(jì)算過(guò)程中的參考序列。

          假設(shè)以下C ++類(lèi)型存在,并且已經(jīng)正常注冊(cè)過(guò):

          class SequenceTypeExample : public QQuickItem
          {
              Q_OBJECT
              Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged)
          
          public:
              SequenceTypeExample() : QQuickItem() { m_list << 1.1 << 2.2 << 3.3; }
              ~SequenceTypeExample() {}
          
              QList<qreal> qrealListProperty() const { return m_list; }
              void setQrealListProperty(const QList<qreal> &list) { m_list=list; emit qrealListPropertyChanged(); }
          
          signals:
              void qrealListPropertyChanged();
          
          private:
              QList<qreal> m_list;
          };

          以下示例在多次循環(huán)中寫(xiě)入引用序列的元素,從而導(dǎo)致性能下降:

          // bad.qml
          import QtQuick 2.3
          import Qt.example 1.0
          
          SequenceTypeExample {
              id: root
              width: 200
              height: 200
          
              Component.onCompleted: {
                  var t0=new Date();
                  qrealListProperty.length=100;
                  for (var i=0; i < 500; ++i) {
                      for (var j=0; j < 100; ++j) {
                          qrealListProperty[j]=j;
                      }
                  }
                  var t1=new Date();
                  console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
              }
          }

          由表達(dá)式引起的內(nèi)部循環(huán)中的QObject屬性讀取和寫(xiě)入"qrealListProperty[j]=j"使得此代碼非常不理想。相反,更好的一種方法是:

          // good.qml
          import QtQuick 2.3
          import Qt.example 1.0
          
          SequenceTypeExample {
              id: root
              width: 200
              height: 200
          
              Component.onCompleted: {
                  var t0=new Date();
                  var someData=[1.1, 2.2, 3.3]
                  someData.length=100;
                  for (var i=0; i < 500; ++i) {
                      for (var j=0; j < 100; ++j) {
                          someData[j]=j;
                      }
                      qrealListProperty=someData;
                  }
                  var t1=new Date();
                  console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
              }
          }
          

          其次,如果屬性中的任何元素發(fā)生變化,則會(huì)發(fā)出屬性的更改信號(hào)。如果你對(duì)序列屬性中的特定元素有很多綁定,最好創(chuàng)建一個(gè)綁定到該元素的動(dòng)態(tài)屬性,并將該動(dòng)態(tài)屬性用作綁定表達(dá)式中的符號(hào)而不是sequence元素,因?yàn)樗鼘⒅挥性谄渲蛋l(fā)生變化時(shí)才會(huì)重新評(píng)估綁定。

          // bad.qml
          import QtQuick 2.3
          import Qt.example 1.0
          
          SequenceTypeExample {
              id: root
          
              property int firstBinding: qrealListProperty[1] + 10;
              property int secondBinding: qrealListProperty[1] + 20;
              property int thirdBinding: qrealListProperty[1] + 30;
          
              Component.onCompleted: {
                  var t0=new Date();
                  for (var i=0; i < 1000; ++i) {
                      qrealListProperty[2]=i;
                  }
                  var t1=new Date();
                  console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
              }
          }

          請(qǐng)注意,即使在循環(huán)中僅修改索引2處的元素,也會(huì)重新評(píng)估三個(gè)綁定,因?yàn)楦男盘?hào)的粒度是整個(gè)屬性已更改。因此,添加中間綁定有時(shí)可能是有益的:

          // good.qml
          import QtQuick 2.3
          import Qt.example 1.0
          
          SequenceTypeExample {
              id: root
          
              property int intermediateBinding: qrealListProperty[1]
              property int firstBinding: intermediateBinding + 10;
              property int secondBinding: intermediateBinding + 20;
              property int thirdBinding: intermediateBinding + 30;
          
              Component.onCompleted: {
                  var t0=new Date();
                  for (var i=0; i < 1000; ++i) {
                      qrealListProperty[2]=i;
                  }
                  var t1=new Date();
                  console.log("elapsed: " + (t1.valueOf() - t0.valueOf()) + " milliseconds");
              }
          }

          在上面的示例中,每次僅重新評(píng)估中間綁定,從而導(dǎo)致顯著的性能提升。

          值類(lèi)型提示

          值類(lèi)型屬性(font,color,vector3d等)具有類(lèi)似的QObject屬性,并將通知語(yǔ)義更改為序列類(lèi)型屬性。因此,上面給出的序列提示也適用于值類(lèi)型屬性。雖然它們通常不是值類(lèi)型的問(wèn)題(因?yàn)橹殿?lèi)型的子屬性的數(shù)量通常遠(yuǎn)小于序列中元素的數(shù)量),所以重新評(píng)估的綁定數(shù)量的任何增加不必要地會(huì)對(duì)績(jī)效產(chǎn)生負(fù)面影響。

          其他JavaScript對(duì)象

          不同的JavaScript引擎提供不同的優(yōu)化。Qt Quick 2使用的JavaScript引擎針對(duì)對(duì)象實(shí)例化和屬性查找進(jìn)行了優(yōu)化,但它提供的優(yōu)化依賴(lài)于某些標(biāo)準(zhǔn)。如果你的應(yīng)用程序不符合標(biāo)準(zhǔn),則JavaScript引擎會(huì)回退到“慢速路徑”模式,性能會(huì)更差。因此,請(qǐng)始終盡量確保您符合以下條件:

          1.盡可能避免使用eval()

          2.不要?jiǎng)h除對(duì)象的屬性

          【領(lǐng)QT開(kāi)發(fā)教程學(xué)習(xí)資料,點(diǎn)擊下方鏈接莬費(fèi)領(lǐng)取↓↓,先碼住不迷路~】

          點(diǎn)擊這里:「鏈接」

          t Quick 為 Qt 引入了一門(mén)叫 QML(Qt Meta/Modeling Language)的腳本語(yǔ)言,它是 ECMAScript 標(biāo)準(zhǔn)的實(shí)現(xiàn)。所以 QML 語(yǔ)法是在 ECMAScript 語(yǔ)法的基礎(chǔ)上實(shí)現(xiàn)的。

          ECMAScript 語(yǔ)言的標(biāo)準(zhǔn)是由 Netscape、Sun、微軟、Borland 等公司基于 JavaScript 和 JScript 錘煉、定義出來(lái)的。

          ECMAScript 僅僅是一個(gè)描述,定義了腳本語(yǔ)言的所有屬性、方法和對(duì)象。其他語(yǔ)言可以實(shí)現(xiàn) ECMAScript 來(lái)作為功能的基礎(chǔ),正如 JavaScript 那樣。這個(gè)實(shí)現(xiàn)又可以被擴(kuò)展,包含特定于宿主環(huán)境的新特性,比如 QML 就引入了 Qt 對(duì)象系統(tǒng)中的信號(hào)與槽,還增加了動(dòng)態(tài)屬性綁定等非常有特色的新功能。

          作為一種全新的編程語(yǔ)言,QML 有三個(gè)核心:

          • ECMAScript
          • Qt 對(duì)象系統(tǒng)
          • Qt Quick 標(biāo)準(zhǔn)庫(kù)

          1、語(yǔ)法

          下面一個(gè)個(gè)來(lái)看 ECMAScript 的語(yǔ)法。(QML 是 ECMAScript 標(biāo)準(zhǔn)的實(shí)現(xiàn),所以?xún)烧哒Z(yǔ)法是基本一樣的)

          1. 1、區(qū)分大小寫(xiě)

          與 C++ —樣,變量、函數(shù)名、運(yùn)算符以及其他一切東西都是區(qū)分大小寫(xiě)的,也就是說(shuō), 變量 area 和 Area 是不同的。


          1.2、弱類(lèi)型

          與 C++ 不同,ECMAScript 中的變量沒(méi)有特定的類(lèi)型,定義變量時(shí)只用 var 運(yùn)算符,可以將它初始化為任意的值,你可以隨時(shí)改變變量所存儲(chǔ)的數(shù)據(jù)類(lèi)型(實(shí)際上應(yīng)當(dāng)盡量避免這樣做)。例如:

          var i=0
          console.log(i)
          i="hello"
          console.log(i)

          盡管在語(yǔ)法上這么做沒(méi)有問(wèn)題,但好的編碼習(xí)慣是一個(gè)變量始終存放相同類(lèi)型的值。

          1.3. 語(yǔ)句后的分號(hào)可有可無(wú)

          C、C++、Java 等語(yǔ)言都要求每條語(yǔ)句以分號(hào)(;)結(jié)束。ECMAScript 則允許開(kāi)發(fā)者自行決定是否以分號(hào)結(jié)束一行代碼。如果沒(méi)有分號(hào),ECMAScript 就把這行代碼的結(jié)尾看作該語(yǔ)句的結(jié)束(與 Lua、Python、Visual Basic 相似)。至于加不加分號(hào),那就看自己的喜好了。下面兩行代碼的語(yǔ)法都是正確的:

          var background="white"
          var i=0

          2、變量

          在 ECMAScript 中使用 var 運(yùn)算符聲明變量,與 C++ 類(lèi)似,變量名需要遵循一定的規(guī)則。

          2.1、變量聲明

          變量用 var 運(yùn)算符加變量名來(lái)定義。例如:

          var i=0

          在這個(gè)例子中,聲明了變量 i 并把它初始化為 0。你也可以不初始化,在用到時(shí)再初始化。

          一個(gè) var 語(yǔ)句可以定義多個(gè)變量。例如:

          var i=0 , name="j"

          這個(gè)例子定義了變量 i,初始化為數(shù)字;還定義了變量 name,初始化為字符串。你看到了,這和 C++ 或 Java 不同,一個(gè) var 語(yǔ)句定義的多個(gè)變量可以有不同的類(lèi)型。

          2.2、變量命名規(guī)則

          變量命名需要遵守兩條簡(jiǎn)單的規(guī)則:

          • 第一個(gè)字符必須是字母、下畫(huà)線(xiàn)(_)或美元符號(hào)($)。
          • 余下的字符可以是下畫(huà)線(xiàn)、美元符號(hào)或者任何字母或數(shù)字字符。

          下面這些變量名都是合法的:

          var test
          var objectName
          var —phone
          var $1

          為了代碼的可讀性,在命名變量時(shí)還應(yīng)該遵循一定的命名風(fēng)格。因?yàn)?Qt 是基于 C++ 的應(yīng)用框架,QML 又是 Qt 框架的一部分,這里建議和 Qt C++ 代碼采取同樣的命名風(fēng)格—駝峰命名法。

          對(duì)于變量(包括函數(shù)名),以小寫(xiě)字母開(kāi)始,單詞之間采用駝峰命名法。對(duì)于類(lèi)名,以大寫(xiě)字母開(kāi)始,單詞之間采用駝峰命名法。

          QT開(kāi)發(fā)交流+貲料君羊:714620761

          3、原始類(lèi)型

          ECMAScript 有 5 種原始類(lèi)型,即 Undefined、Null、Boolean、Number 和 String。每種原始類(lèi)型定義了它包含的值的范圍及其字面量表示形式。

          ECMAScript 提供了 typeof 運(yùn)算符來(lái)判斷一個(gè)值的類(lèi)型,如果這個(gè)值是原始類(lèi)型,typeof 還會(huì)返回它具體的類(lèi)型名字;而如果這個(gè)值是引用值,那么 typeof 統(tǒng)一返回 ”object” 作為類(lèi)型名字。示例如下:

          import QtQuick 2.2
          
          Rectangle {
          	Component.onCompleted:{
          		var name="Zhang San Feng"
                  console.log(typeof name) // 輸出:qml:string
                  console.log(typeof 60) // 輸出:qml:number
          	}
          }
          

          變量 name 的類(lèi)型是 string,字面量 60 的類(lèi)型是 number。其中 “qml:” 是使用 console.log 輸出信息時(shí)攜帶的前綴。

          3.1、Undefined 類(lèi)型

          Undefined 類(lèi)型只有一個(gè)值,即 undefined。當(dāng)聲明的變量未初始化時(shí),該變量的默認(rèn)值就是 undefined。例如:

          var temp

          上面的代碼聲明了變量 temp 但并未顯式地講行初始化,它的值將被設(shè)置為 undefined, 這和 C++ 不同。ECMAScript 的這一特性:未初始化的變量也有固定的初始值,我們可以將一個(gè)變量和 undefined 比較來(lái)實(shí)現(xiàn)一些業(yè)務(wù)邏輯。比如:

          var runOnce;
          ...
          if(runOnce==undefined) {
              runOnce=true
          }
          else {
              ...
          }
          

          當(dāng)函數(shù)沒(méi)有明確的返回值時(shí),返回的值也是 undefined,如下所示:

          function blankFunc(){}
          console.log(blankFunc()==undefined) // 輸出:true
          

          3.2、Null 類(lèi)型

          Null 類(lèi)型也只有一個(gè)值,即 null。

          你可以顯式地將一個(gè)變量初始化為 null,然后據(jù)此實(shí)現(xiàn)一些邏輯。

          3.3、Boolean 類(lèi)型

          Boolean 是 ECMAScript 中最常用的類(lèi)型之一,它有 true 和 false 兩個(gè)值。

          3.4、Number 類(lèi)型

          Number 類(lèi)型是最特殊的,它既可以表示 32 位的整數(shù),也可以表示 64 位的浮點(diǎn)數(shù)。你在 QML 代碼中直接輸入的任何數(shù)字都被看作是 Number 類(lèi)型的字面量。

          下面的代碼聲明了存放整數(shù)值的變量:

          var integer=10
          

          數(shù)字類(lèi)型的最大值是 Number.MAX_VALUE,最小值是 Number.MlN_VALUE,它們定義了 Number 值的外邊界,所有的 ECMAScript 數(shù)都必須在這兩個(gè)值之間。


          3.5、String 類(lèi)型

          ECMAScript 中的 String 類(lèi)型是作為原始類(lèi)型存在的,它存儲(chǔ) Unicode 字符,對(duì)應(yīng)的 Qt C++ 類(lèi)型為 QString。當(dāng)你混合 C++ 和 QML 編程時(shí),所有的 QString 類(lèi)型的變量都會(huì)被映射為 ECMAScript 中的 String。

          字符串字面量可以用雙引號(hào)(")或單引號(hào)(')來(lái)聲明。而在 Qt 中,只能用雙引號(hào), 單引號(hào)表示字符。為了一致性,建議你盡可能不要使用單引號(hào)表示字符串。在 ECMAScript 中沒(méi)有字符類(lèi)型,這也是為什么你可以使用單引號(hào)來(lái)表示字符串的原因。下面的兩行代碼都是有效的:

          var name='Lv Bu'
          var name="Guan Yu"

          4、類(lèi)型轉(zhuǎn)換

          如果一種編程語(yǔ)言不支持類(lèi)型轉(zhuǎn)換,那真是無(wú)法想象。在 ECMAScript 中,類(lèi)型轉(zhuǎn)換非常簡(jiǎn)單。

          4.1、轉(zhuǎn)換成字符串

          Boolean、Number、String 三種原始類(lèi)型,都有 toString() 方法,可以把它們的值轉(zhuǎn)換為字符串。比如下面的代碼在 Qt 中可以正常運(yùn)行:

          var name="Zhang San Feng"
          console.log(name.toString())
          console.log(true.toString())
          var visible=false
          console.log(visible.toString())
          var integer=3.14159
          console.log(integer.toString())
          

          Number 類(lèi)型的 toString() 方法還可以按基轉(zhuǎn)換,比如:

          var integer=13
          console.log (integer.toString(16)) // 輸出: D
          

          如果你不指定數(shù)基,那不管原來(lái)是用什么形式聲明的 Number 類(lèi)型,toString() 都按十進(jìn)制輸出。

          4.2、轉(zhuǎn)換成數(shù)字

          parselnt() 和 parseFloat() 可以把非數(shù)字的原始值轉(zhuǎn)換成數(shù)字,前者把值轉(zhuǎn)換為整數(shù),后者把值轉(zhuǎn)換成浮點(diǎn)數(shù)。這兩個(gè)方法只能用于 String 類(lèi)型,如果你對(duì)其他類(lèi)型調(diào)用它們, 返回值將是奇葩的 NaN。

          parselnt() 和 parseFloat() 會(huì)掃描字符串,直到遇到第一個(gè)非數(shù)字字符時(shí)停止,將轉(zhuǎn)換的結(jié)果返回。比如parselnt(”2014年")將會(huì)返回 2014。對(duì)于 parseFloat(),會(huì)將第一個(gè)小數(shù)點(diǎn)作為有效字符,而 parselnt() 則不會(huì)。

          下面是一些示例:

          var numl=parselnt ("2014 年") // 輸出:2014
          var num2=parselnt ("OxC") // 輸出:12
          var num3=parselnt ("3.14") // 輸出:3
          var num4=parselnt ("green") // 輸出:NaN_
          var num5=parseFloat ("3.14159") // 輸出:3.14159
          var num7=parseFloat ("Am I Float") // 輸出:NaN
          

          parselnt() 還支持基模式,下面是一些示例:

          var numl=parselnt ("AK47", 16) // 輸出:10
          var num2=parselnt ("AK47", 10) // 輸出:NaN
          var num3=parselnt ("010", 8) // 輸出:8
          var nun4=parselnt ("010", 10) // 輸出:10
          

          需要注意的是,代表浮點(diǎn)數(shù)的字符串必須以十進(jìn)制形式表示,比如parseFloat(“OxFE”),返回 NaN。

          4.3、強(qiáng)制類(lèi)型轉(zhuǎn)換

          如果你是 C/C++ 程序員,對(duì)強(qiáng)制類(lèi)型轉(zhuǎn)換一定又愛(ài)又恨。ECMAScript 也支持強(qiáng)制類(lèi)型 轉(zhuǎn)換,有三種轉(zhuǎn)換:

          • Boolean(value),把 value 轉(zhuǎn)換成 Boolean 類(lèi)型。
          • Number(value),把value轉(zhuǎn)換為數(shù)字(整數(shù)或浮點(diǎn)數(shù))。
          • String(value),把value轉(zhuǎn)換成字符串。

          5、函數(shù)

          ECMAScript 中的函數(shù),就是具名的、可重復(fù)使用的代碼塊。另外,ECMAScript 不支持函數(shù)重載。

          5.1、函數(shù)語(yǔ)法

          函數(shù)語(yǔ)法如下:

          function functionName(arg1, arg2, ..., argN){
          	// 要執(zhí)行的代碼
          }

          function 是定義函數(shù)時(shí)必須使用的關(guān)鍵字。functionName可以任意取,符合變量命名規(guī)則即可。 arg1 到 argN 是函數(shù)的參數(shù),當(dāng)然也可以沒(méi)有參數(shù)。花括號(hào)內(nèi)是要執(zhí)行的代碼塊。

          無(wú)參函數(shù)示例:

          function quitApp(){
          	Qt .quit ();
          }
          

          帶參函數(shù)示例:

          function showError(msg){
          	console.log("error - ", msg);
          }
          
          function travel(country, city){
          	console.log("Welcome to ", city, " , ", country);
          }
          

          當(dāng)我們使用函數(shù)參數(shù)的時(shí)候,參數(shù)就像不帶 var 運(yùn)算符的變量聲明一樣。這與 C++ 中必須給函數(shù)參數(shù)指明類(lèi)型大相徑庭。

          5.2、函數(shù)的返回值

          ECMAScript 中的函數(shù),默認(rèn)都是有返回值的,即便你沒(méi)有顯式使用 return 語(yǔ)句,它也會(huì)返回 undefined。如果你想把函數(shù)運(yùn)算的結(jié)果返回給調(diào)用它的地方,可以使用 return 語(yǔ)句。下面是個(gè)簡(jiǎn)單的示例:

          function add(numberl, number2){
          	var result=number1 + number2;
          	console.log(number1, "+" ,number2, result);
          	return result;
          }
          QT開(kāi)發(fā)交流+貲料君羊:714620761

          你可以這樣調(diào)用 add() 函數(shù):var ret=add(100, 34);。

          6、運(yùn)算符

          ECMAScript 的運(yùn)算符和 C++、Java 等語(yǔ)言的差不多,具體內(nèi)容不再贅述。這里只重點(diǎn)介紹一下關(guān)鍵字運(yùn)算符。void、typeof、instanceof、new、delete 這些都是關(guān)鍵字運(yùn)算符。

          • void 運(yùn)算符比較特殊,它放在一個(gè)表達(dá)式前,舍棄表達(dá)式的值,返回 undefined。
          • typeof 前面講過(guò)了,對(duì)于原始值,返回原始類(lèi)型;對(duì)于引用值,返回 object。這導(dǎo)致你無(wú)法準(zhǔn)確判斷一個(gè)對(duì)象的引用類(lèi)型,所以 ECMAScript 引入了 instanceof 運(yùn)算符。
          • instanceof 用來(lái)測(cè)試一個(gè)對(duì)象的實(shí)際類(lèi)型,你需要顯式指定要測(cè)試的類(lèi)型。例如:
          • var str=new String ("hello world"); console.log (str instanceof String); // 輸出:true
          • new 運(yùn)算符用來(lái)創(chuàng)建一個(gè)對(duì)象,前面用了很多次了,不再贅述。 delete 運(yùn)算符比較特別,在 QML 中,一般它只能刪除一個(gè)對(duì)象內(nèi)由你定義的屬性,而框架定義的那些核心屬性,多數(shù)是你不能刪除的。我們?cè)?ECMAScript 中調(diào)用 delete,多數(shù)時(shí)候是解除對(duì)對(duì)象的引用,以免老有人引用某個(gè)對(duì)象而導(dǎo)致它逍遙法外。

          7、使用 console

          console 提供了輸出日志信息、斷言、計(jì)時(shí)器、計(jì)數(shù)器、性能分析等功能,這里只介紹前三個(gè)我們經(jīng)常用到的功能。

          7.1、輸出日志信息

          console對(duì)象提供了多個(gè)打印調(diào)試信息的方法:

          • console.log();
          • console.debug();
          • console.info();console.warn();
          • console.error();

          7.2、斷言

          console.assert() 提供斷言功能,它接受一個(gè)表達(dá)式,當(dāng)表達(dá)式的值為 false 時(shí)會(huì)輸出調(diào)試信息,打印 QML 所在行。例如:console.assert (false)。

          如果你傳遞了額外的參數(shù)給 console.assert(),它會(huì)在控制臺(tái)輸出這些信息。示例:

          var years=0;
          
          for (; years < 18; years++){
          	console.log("I\'m minor"); 
              continue;
          	console.log ("You shoult not see me"};
          }
          
          console.assert(years < 18, years);
          

          上面的斷言語(yǔ)句,將會(huì)輸出下列信息:

          18
          onCompleted (file:///F:/projects/qtquick/qmls/show_type.qml:187)
          

          需要注意的是,在 QML 中,使用 console.assert(),斷言失敗,程序并不會(huì)終止運(yùn)行。

          7.3、計(jì)時(shí)器

          console 提供了計(jì)時(shí)器功能,方便我們測(cè)量某些代碼的耗時(shí)情況。

          console.time(tag) 啟動(dòng)定時(shí)器,字符串類(lèi)型的 tag 是必需的。console.timeEnd(tag) 停止計(jì)時(shí)器,在控制臺(tái)輸出某個(gè)標(biāo)簽對(duì)應(yīng)的耗時(shí)信息。tag 是必需的。 下面是簡(jiǎn)單的示例:


          主站蜘蛛池模板: 精品一区二区三区中文字幕| 人妻无码一区二区不卡无码av| 日本精品无码一区二区三区久久久| 无码人妻精品一区二区三区99仓本| 国产精品毛片一区二区三区 | 一区二区三区免费看| 亚洲成av人片一区二区三区| 性无码一区二区三区在线观看| 曰韩人妻无码一区二区三区综合部| 在线精品自拍亚洲第一区| 国产情侣一区二区三区 | 精品国产一区二区三区久久 | 国产精品久久久久久一区二区三区 | 日韩好片一区二区在线看| 一区二区三区高清视频在线观看| 无码乱人伦一区二区亚洲| 精品视频一区二区三区四区五区| 精品亚洲av无码一区二区柚蜜| 人妻少妇精品一区二区三区| 日韩精品一区二区三区在线观看| 一区二区三区日韩精品| 岛国无码av不卡一区二区| 日韩少妇无码一区二区三区| 好吊妞视频一区二区| 国内精品一区二区三区东京| 日本激情一区二区三区| 日韩精品一区二区三区中文精品| 亚洲日本精品一区二区 | 在线精品视频一区二区| 精品欧洲av无码一区二区14| 亚洲性无码一区二区三区| 97人妻无码一区二区精品免费| 精品一区精品二区制服| 日韩a无吗一区二区三区| 日韩一区二区三区视频| 亚洲AV午夜福利精品一区二区 | 日本精品啪啪一区二区三区| 日韩精品一区二区三区老鸦窝| 国产精品污WWW一区二区三区| 文中字幕一区二区三区视频播放| 伊人色综合网一区二区三区|