<dfn id="w48us"></dfn><ul id="w48us"></ul>
  • <ul id="w48us"></ul>
  • <del id="w48us"></del>
    <ul id="w48us"></ul>
  • 高效編寫JavaScript代碼的技巧

    時(shí)間:2024-08-25 02:10:08 JavaScript 我要投稿
    • 相關(guān)推薦

    高效編寫JavaScript代碼的技巧

      如何能高效的編寫出優(yōu)秀的JavaScript代碼,有哪些技巧?下面YJBYS小編為你介紹!

      原則

      不要做任何優(yōu)化除非的確需要優(yōu)化

      任何的性能優(yōu)化都必須以測(cè)量數(shù)據(jù)為基礎(chǔ),如果你懷疑代碼存在性能問(wèn)題,首先通過(guò)測(cè)試來(lái)驗(yàn)證你的想法。

      性能優(yōu)化三問(wèn)

      我還能做哪些工作從而讓代碼變得更有效率?

      流行的JavaScript引擎通常會(huì)做哪些優(yōu)化工作?

      哪些優(yōu)化是JavaScript引擎不能做的,垃圾回收器是否能清理我們期望清理的?

      對(duì)JavaScript引擎的深入了解有助于我們編寫高效的JavaScript代碼,但不要只針對(duì)某一特定引擎做性能優(yōu)化。

      V8的幾個(gè)關(guān)鍵概念

      基礎(chǔ)編譯器,解析你的JavaScript代碼并生成Native Machine Code執(zhí)行,而不是執(zhí)行字節(jié)碼或是直接對(duì)JavaScript解釋執(zhí)行。

      在V8中,對(duì)象以object model的形式存在。對(duì)象在JavaScript中是以關(guān)聯(lián)數(shù)組的形式存在,但V8采用的是Hidden

      Classes——一種對(duì)查找操作進(jìn)行了優(yōu)化的內(nèi)部類型系統(tǒng)。

      運(yùn)行時(shí)探查器監(jiān)視運(yùn)行中的系統(tǒng),并識(shí)別出Hot functions,即是耗用了較長(zhǎng)時(shí)間的代碼

      優(yōu)化編譯器重新編譯并優(yōu)化由運(yùn)行時(shí)探查器識(shí)別出來(lái)的Hot代碼

      V8支持反優(yōu)化,優(yōu)化編譯器能夠發(fā)現(xiàn)過(guò)度優(yōu)化的代碼并對(duì)其進(jìn)行處理

      V8有自己的垃圾回收器

      垃圾回收垃圾回收是一種內(nèi)存管理機(jī)制,垃圾回收器會(huì)嘗試清理掉不再被使用的對(duì)象,并回收內(nèi)存。

      在絕大多數(shù)情況下都不需要手動(dòng)解除引用

      你不可能強(qiáng)制垃圾回收器工作

      刪除引用的誤區(qū)

      盡可能不要使用delete,在下面的列子中,delete 帶來(lái)的弊遠(yuǎn)遠(yuǎn)大于利

      var o = { x: 1};delete o.x;

      主要的原因是為了避免在運(yùn)行時(shí)修改Hot對(duì)象的結(jié)構(gòu),因?yàn)楣潭ǖ膶?duì)象結(jié)構(gòu)有助于JavaScript引擎對(duì)其進(jìn)行優(yōu)化,而delete會(huì)導(dǎo)致對(duì)象結(jié)構(gòu)改變。

      另外一個(gè)誤區(qū)是將對(duì)象設(shè)置為null,將對(duì)象設(shè)置為null不會(huì)刪除對(duì)象,只是將對(duì)象指向null,這要好過(guò)采用delete,但通常也是不必要的。

      全局變量在整個(gè)頁(yè)面生命周期中都是不會(huì)被清理的,無(wú)論頁(yè)面打開(kāi)多長(zhǎng)時(shí)間,除非是刷新頁(yè)面或者轉(zhuǎn)到其他頁(yè)面。局部變量(Function-scoped)在方法執(zhí)行完后,且沒(méi)有被引用的情況下將會(huì)被回收。

      所以,請(qǐng)盡量避免使用全局變量。

      經(jīng)驗(yàn)法則為了使垃圾回收器盡早回收對(duì)象,不要保持不必要的對(duì)象引用。

      比手動(dòng)解除引用更好的方法是將對(duì)象放在合適的變量域中,能用局部變量就不要采用全局變量

      當(dāng)事件監(jiān)聽(tīng)不再需要時(shí),請(qǐng)解除事件綁定,尤其是當(dāng)事件綁定的DOM對(duì)象被刪除時(shí)

      如果有使用本地緩存,請(qǐng)確保有合適的清理機(jī)制(比如時(shí)效機(jī)制),從而避免大量無(wú)用的數(shù)據(jù)存儲(chǔ)。

      方法 (Function)

      如前面所說(shuō),垃圾回收器只有在對(duì)象不可觸及的時(shí)候才會(huì)對(duì)其做回收處理?紤]如下兩個(gè)列子:

      function foo(){

      var bar = new LargeObject()

      bar.someCall();}

      function foo(){

      var bar = new LargeObject()

      bar.someCall();

      return bar;}var b = foo();

      在第一個(gè)例子中,bar指向的對(duì)象會(huì)在方法執(zhí)行完畢后處于可回收狀態(tài);在第二個(gè)列子中,由于在局部變量外維護(hù)了一個(gè)全局變量b,bar指向的對(duì)象無(wú)法被回收。

      閉包 (Closures)

      當(dāng)一個(gè)方法返回一個(gè)內(nèi)部方法時(shí),被返回的內(nèi)部方法能訪問(wèn)外部方法的局部變量域即使外部方法已經(jīng)執(zhí)行完畢。

      function sum(x){

      function sumIt(y){

      return x + y;

      }}var sumA = sum(4);var sumB = sumA(3);

      在上面的例子中,sumIt方法即使處于sum的局部變量域中,但由于存在一個(gè)sumA全局變量,在sum執(zhí)行完畢后也無(wú)法被回收。再看兩個(gè)例子

      var a = function(){

      var largeObj = new LargeObject();

      return function(){

      return largeObj;

      }}();var a = function(){

      var smallObj = new SmallObj();

      var largeObj = new LargeObj();

      return function(n){

      return smallObj;

      }}();

      第一個(gè)例子中,largeObj可以通過(guò)變量a訪問(wèn),因此不可被回收;在第二個(gè)例子中,方法一旦執(zhí)行完畢,largeObj就無(wú)法被訪問(wèn)了,因此處于可回收狀態(tài)。

      定時(shí)器 (Timer)在setTimeout / setInterval方法中的引用,只有當(dāng)定時(shí)器執(zhí)行完成后才能被回收。

      V8優(yōu)化小貼士

      某些行為會(huì)導(dǎo)致V8停止優(yōu)化工作,比如try-catch,為了能弄清哪些代碼可以被優(yōu)化,哪些不能,你可以在V8命令行工具中使用—trace-opt file.js獲得有用的信息。

      如果你在意速度,那就盡可能保證你的方法是”單形的(monomophic)"

      不要做類似如下的嘗試

      function add(x, y){

      return x+y;}add(1,2);add('a','b');add(my_custom_object, undefined);

      不要加載沒(méi)有被初始化或者已被刪除的元素,盡管在輸出上沒(méi)有不同,但卻會(huì)讓代碼變得更慢

      不要寫大方法,因?yàn)樗麄兒茈y被優(yōu)化。

      對(duì)象還是數(shù)組, 如何選擇?

      如果存儲(chǔ)的是大量數(shù)字,或者是相同類型的對(duì)象列表,采用數(shù)組;

      如果根據(jù)語(yǔ)義你需要一個(gè)有很多屬性的對(duì)象,那就采用對(duì)象,在內(nèi)存利用方面這會(huì)很高效,同時(shí)也很快;

      無(wú)論是數(shù)組還是對(duì)象,采用整數(shù)索引都最快的。

      var sum = 0;for (var x=0; x

      sum + = arr[x].payload;}

      var sum = 0;for(var x in obj){

      sum += obj[x].payload;}

      var sum = 0;for(var x=0; x<1000,++x){

      sum += obj[x].payload;}

      var sum = 0;var keys = Objects.keys(obj);for(var x=0; x

      sum += obj[keys[x]].payload;}

      在上面的四段代碼中,第一段和第三段速度比第二段和第四段要快很多。其中,第一段代碼執(zhí)行最快,最后一段代碼執(zhí)行最慢。

      相比數(shù)組中的元素,對(duì)象的屬性在結(jié)構(gòu)上相對(duì)復(fù)雜。在引擎層面,內(nèi)存中越是簡(jiǎn)單的結(jié)構(gòu)越容易被優(yōu)化,尤其是包含數(shù)字的數(shù)組。因此,如果你需要向量,采用數(shù)組而不是一個(gè)包含x,y, z屬性的對(duì)象會(huì)有更優(yōu)的性能表現(xiàn)。

      在JavaScript中,數(shù)組和對(duì)象最重要的不同是數(shù)組的length屬性,如果你能自己維護(hù)這個(gè)值,對(duì)象在V8中也能跑出數(shù)組的速度。

      使用對(duì)象的性能小貼士

      使用構(gòu)造函數(shù)創(chuàng)建對(duì)象,因?yàn)樗胁捎猛粯?gòu)造函數(shù)創(chuàng)建的對(duì)象都具有相同的hidden class,另外,采用構(gòu)造函數(shù)創(chuàng)建對(duì)象也比Object.create()這種方法略塊。

      盡管JavaScript沒(méi)有限制類型數(shù)量和對(duì)象的復(fù)雜度,但長(zhǎng)原型鏈和大量的對(duì)象屬性會(huì)對(duì)性能造成損害。因此盡可能保持較短的原型鏈和較少的對(duì)象屬性。

      對(duì)象的拷貝for..in循環(huán)是性能殺手,通過(guò)該方法遍歷對(duì)象屬性進(jìn)行拷貝非常低效?截惔髮(duì)象始終會(huì)降低性能,盡可能不要干這樣的事情,當(dāng)然大對(duì)象的存在本身就是一個(gè)錯(cuò)誤。如果你確實(shí)需要在性能攸關(guān)的代碼中拷貝對(duì)象,可以采用如下的方式。

      function clone(original){

      this.foo = original.foo;

      this.bar = original.bar;}var copy = new clone(original);

      緩存采用模塊化編程(Module Pattern)的方法

      // prototypalKlass1 = function(){}Klass1.prototype.foo = function(){

      log('foo');}Klass1.prototype.bar = function(){

      log('bar');}

      // Module patternKlass2 = function(){

      var foo = function(){

      log('foo');

      }

      var bar = function(){

      log('bar');

      }

      return {foo:foo,bar:bar}}

      // Module pattern with cached functionsvar fooFn = function(){

      log('foo');}var barFn = function(){

      log('bar')}Klass3 = function(){

      return{

      foo: fooFn,

      bar: barFn }}

      執(zhí)行速度從快到慢依次是

      Module Pattern with Cached functions → prototypal → Module pattern

      使用數(shù)組的性能小貼士

      不要?jiǎng)h除數(shù)組元素,當(dāng)數(shù)組的Key set分布分散后,V8會(huì)將存儲(chǔ)方式轉(zhuǎn)為字典,導(dǎo)致速度變慢。

      數(shù)組常量更高效,尤其是小數(shù)組和中等大小的數(shù)組。

      var a = [1, 2, 3, 4]

      var a = [];for(var i=1, i<=4; i++){

      a.push(i);}

      不要采用第二段代碼中的方法初始化數(shù)組。

      不要在數(shù)組中存儲(chǔ)不同類型的元素

      V8中,稀疏數(shù)組( Sparse Arrays)是被當(dāng)成字典對(duì)待的,因此相比密集數(shù)組(Full Arrays),執(zhí)行速度更慢

      與緊湊的數(shù)組相比,滿身是洞的數(shù)組執(zhí)行更慢,即使是從密集數(shù)組中刪除一個(gè)元素,也會(huì)帶來(lái)性能上的損失。

      不要預(yù)先給大數(shù)組(大于64k)分配一個(gè)最大值

      var arr = [];for(var i = 0; i< 1000000; i++){

      arr[i] = 1;}

      var arr = new Array(1000000);for(var i=0; i<1000000; i++){

      arr[i]=i;}

      需要注意的是,不同引擎在這一點(diǎn)上有不同,在Nitro(Safari)中,第二段代碼跑得更快,但在V8(Chrome), SpiderMonkey(Firefox)中,第一段更快。

    【高效編寫JavaScript代碼的技巧】相關(guān)文章:

    在Java中執(zhí)行JavaScript代碼04-01

    JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)刷新代碼段03-25

    常用排序算法之JavaScript實(shí)現(xiàn)代碼段03-10

    網(wǎng)頁(yè)程序設(shè)計(jì)之實(shí)用JavaScript代碼段03-06

    如何讓JAVA代碼更高效03-20

    關(guān)jQuery彈出窗口簡(jiǎn)單實(shí)現(xiàn)代碼-javascript編程03-30

    J2EE項(xiàng)目代碼編寫規(guī)范01-23

    javascript中for/in循環(huán)以及常見(jiàn)的使用技巧04-02

    高效溝通的技巧02-26

    主站蜘蛛池模板: 久久亚洲欧美日本精品| 亚洲国产精品无码久久久久久曰| 国产亚洲精品影视在线产品| 国产精品视频色拍拍| 日韩熟女精品一区二区三区| 四虎影永久在线观看精品| 久久99精品国产自在现线小黄鸭| 久久精品国产欧美日韩| 欧美精品亚洲精品日韩1818| 婷婷五月深深久久精品| 久久露脸国产精品| 国产精品一区二区三区99| 精品亚洲永久免费精品| 精品麻豆丝袜高跟鞋AV| 在线中文字幕精品第5页| 国产一区二区三区精品视频| 久久99国产精品99久久 | 久久精品成人免费网站| 久久99精品久久久久久动态图| 热综合一本伊人久久精品| 国产精品免费久久久久影院| 国产大片91精品免费观看不卡| 少妇伦子伦精品无码STYLES| 日韩精品在线播放| 久久精品人妻一区二区三区| 国产乱人伦偷精品视频| 国产成人精品午夜福麻豆| 欧美精品一本久久男人的天堂 | 亚洲国产精品狼友中文久久久| 国产精品自在线拍国产第一页 | 国产精品午夜久久| 91国内揄拍国内精品情侣对白| 久久精品成人免费网站| 久久青青草原精品影院| 欧美亚洲国产成人精品| 日韩精品一区二区三区大桥未久| 国产原创精品视频| 久久精品视频网| 99re只有精品8中文| 国产精品免费在线播放| 国产精品部在线观看|