亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 語言 > JavaScript > 正文

如何編寫高質量JS代碼

2024-05-06 16:13:04
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了如何編寫高質量JS代碼的方法及相關資料,需要的朋友可以參考下
 
 

想寫出高效的javascript類庫卻無從下手;

嘗試閱讀別人的類庫,卻理解得似懂給懂;

打算好好鉆研js高級函數,但權威書上的內容太零散,

即使記住“用法”,但到要“用”的時候卻沒有想“法”。

也許你和我一樣,好像有一顧無形的力量約束著我們的計劃,讓我們一再認為知識面的局限性,致使我們原地踏步,難以向前跨越。

這段時間,各種作業、課程設計、實驗報告,壓力倍增。難得擠出一點點時間,絕不睡懶覺,整理總結往日所看的書,只為了可以離寫自己的類庫近一點。

本文參考自《javascript語言精粹》和《Effective JavaScript》。例子都被調試過,理解過后,我想把一些“深奧”的道理說得淺顯一點點。

1.變量作用域

作用域對于程序員來說就像氧氣。它無處不在,甚至,你往往不會去想他。但當它被污染時(例如使用全局對象),你會感覺到窒息(例如應用響應變慢)。javascript核心作用域規則很簡單,被精心設計,且很強大。有效地使用javascript需要掌握變量作用域的一些基本概念,并了解一些可能導致難以捉摸的、令人討厭的問題的極端情況。

1.1盡量少用全局變量

javascript很容易在全局命名空間中創建變量。創建全局變量毫不費力,因為它不需要任何形式的聲明,而且能被整個程序的所有代碼自動地訪問。

對于我們這些初學者,遇到某些需求(例如,傳輸的數據被記錄下來、等待某時機某函數調用時使用;或者是某函數被經常使用)時,好不猶豫想到全局函數,甚至大一學到的C語言面向過程思想太根深蒂固,系統整整齊齊地都是滿滿函數。定義全局變量會污染共享的公共命名空間,并可能導致意外的命名沖突。全局變量也不利于模塊化,因為它會導致程序中獨立組件間的不必要耦合。嚴重地說,過多的全局(包括樣式表,直接定義div或者a的樣式),整合到多人開發過稱將會成為災難性錯誤。這就是為什么jQuery的所有代碼都被包裹在一個立即執行的匿名表達式——自調用匿名函數。當瀏覽器加載完jQuery文件后,自調用匿名函數立即開始執行,初始化jQuery的各個模塊,避免破壞和污染全局變量以至于影響到其他代碼。

 

復制代碼代碼如下:

(function(window,undefined){
    var jQuery = ...
    //...
    window.jQuery = window.$ = jQuery;
})(window);

 

另外,你或許會認為,“先怎么怎么寫,日后再整理”比較方便,但優秀的程序員會不斷地留意程序的結構、持續地歸類相關的功能以及分離不相關的組件,并這些行為作為編程過稱中的一部分。

 由于全局命名空間是javascript程序中獨立的組件經行交互的唯一途徑,因此,利用全局命名控件的情況是不可避免的。組件或程序庫不得不定義一些全局變量。以便程序中的其他部分使用。否則最好使用局部變量。

 

復制代碼代碼如下:

this.foo ;//undefined
foo = " global foo";
this.foo ;//"global foo"
var foo = "global foo";
this.foo = "changed";
foo ;//changed

 

javascript的全局命名空間也被暴露在程序全局作用域中可以訪問的全局對象,該對象作為this關鍵字的初始值。在web瀏覽器中,全局對象被綁定在全局window變量。這就意味你創建全局變量有兩種方法:在全局作用域內使用var聲明他,或者將其加入到全局對象中。使用var聲明的好處是能清晰地表達全局變量在程序范圍中的影響。

鑒于引用為綁定的全局變量會導致運行時錯誤,因此,保存作用域清晰和簡潔會使代碼的使用者更容易理解程序聲明了那些全局變量。

由于全局對象提供了全局環境的動態反應機制,所以可以使用它查詢一個運行環境,檢測在這個平臺下哪些特性可用。

eg.ES5引入了一個全局的JSON對象來讀寫JSON格式的數據。

 

復制代碼代碼如下:

if(!this.JSON){
   this.JSON = {
         parse : ..,
         stringify : ...    
    }  
}

 

 如果你提供了JSON的實現,你當然可以簡單無條件地使用自己的實現。但是由宿主環境提供的內置實現幾乎更適合的,因為它們是用C語言寫進瀏覽器的。因為它們按照一定的標準對正確性和一致性進行了嚴格檢查,并且普遍來說比第三方實現提供更好的性能。

當初數據結構課程設計模擬串的基本操作,要求不能使用語言本身提供的方法。javascript對數組的基本操作實現得很好,如果只是出于一般的學習需要,模擬語言本身提供的方法的想法很好,但是如果真正投入開發,無需考慮第一時間選擇使用javascript內置方法。

1.2避免使用with

with語句提供任何“便利“,讓你的應用變得不可靠和低效率。我們需要對單一對象依次調用一系列方法。使用with語句可以很方便地避免對對象的重復引用:

 

復制代碼代碼如下:

function status(info){
    var widget = new Widget();
    with(widget){
           setBackground("blue");
           setForeground("white");
           setText("Status : "+info);
           show();
    }  
}

 

使用with語句從模塊對象中”導入“(import)變量也是很有誘惑力的。

 

復制代碼代碼如下:

function f(x,y){
   with(Math){
         return min(round(x),sqrt(y));//抽象引用
   }
}

 

事實上,javascript對待所有的變量都是相同的。javascript從最內層的作用域開始向外查找變量。with語言對待一個對象猶如該對象代表一個變量作用域,因此,在with代碼塊的內部,變量查找從搜索給定的變量名的屬性開始。如果在這個對象中沒有找到該屬性,則繼續在外部作用域中搜索。with塊中的每個外部變量的引用都隱式地假設在with對象(以及它的任何原型對象)中沒有同名的屬性。而在程序的其他地方創建或修改with對象或其原型對象不一定會遵循這樣的假設。javascript引擎當然不會讀取局部代碼來獲取你使用了那些局部變量。javascript作用域可被表示為高效的內部數據結構,變量查找會非??焖佟5怯捎趙ith代碼塊需要搜索對象的原型鏈來查找with代碼里的所有變量,因此,其運行速度遠遠低于一般的代碼塊。

替代with語言,簡單的做法,是將對象綁定在一個簡短的變量名上。

 

復制代碼代碼如下:

function status(info){
    var w = new Widget();
    
     w.setBackground("blue");
     w.setForeground("white");
     w.setText("Status : "+info);
     w.show();
   
}

 

其他情況下,最好的方法是將局部變量顯式地綁定到相關的屬性上。

 

復制代碼代碼如下:

function f(x,y){
    var    min    = Math.min,
           round  = Math.round,
           sqrt   = Math.sqrt;  
     return min(round(x),sqrt(y));
}

 

1.3熟練掌握閉包

理解閉包有單個概念:

a)javascript允許你引用在當前函數以外定義的變量。

 

復制代碼代碼如下:

function makeSandwich(){
   var magicIngredient = "peanut butter";
   function make(filling){
        return magicIngredient + " and " + filling;
   }
   return make("jelly");  
}
makeSandwich();// "peanut butter and jelly"

 

b)即使外部函數已經返回,當前函數仍然可以引用在外部函數所定義的變量

 

復制代碼代碼如下:

function makeSandwich(){
   var magicIngredient = "peanut butter";
   function make(filling){
        return magicIngredient + " and " + filling;
   }
   return make;  
}
var f = sandwichMaker();
f("jelly");                      // "peanut butter and jelly"
f("bananas");               // "peanut butter and bananas"
f("mallows");               // "peanut butter and mallows"

 

javascriptd的函數值包含了比調用它們時所執行所需要的代碼還要多的信息。而且,javascript函數值還在內部存儲它們可能會引用的定義在其封閉作用域的變量。那些在其所涵蓋的作用域內跟蹤變量的函數被稱為閉包。

 make函數就是一個閉包,其代碼引用了兩個外部變量:magicIngredient和filling。每當make函數被調用時,其代碼都能引用這兩個變量,因為閉包存儲了這兩個變量。

函數可以引用在其作用域內的任何變量,包括參數和外部函數變量。我們可以利用這一點來編寫更加通用的sandwichMaker函數。

 

復制代碼代碼如下:

function makeSandwich(magicIngredient){
   function make(filling){
        return magicIngredient + " and " + filling;
   }
   return make;  
}
var f = sandwichMaker(”ham“);
f("cheese");                      // "ham and cheese"
f("mustard");               // "ham and mustard"

 

閉包是javascript最優雅、最有表現力的特性之一,也是許多習慣用法的核心。

c)閉包可以更新外部變量的值。事實上,閉包存儲的是外部變量的引用,而不是它們的值的副本。因此,對于任何具有訪問這些外部變量的閉包,都可以進行更新。

 

復制代碼代碼如下:

function box(){
    var val = undefined;
    return {
         set : function(newval) {val = newval;},
         get : function (){return val;},
         type : function(){return typeof val;}
    };
}
var b = box();
b.type(); //undefined
b.set(98.6);
b.get();//98.6
b.type();//number

 

該例子產生一個包含三個閉包的對象。這三個閉包是set,type和get屬性,它們都共享訪問val變量,set閉包更新val的值。隨后調用get和type查看更新的結果。

1.4理解變量聲明提升

javascript支持此法作用域(對變量foo的引用會被綁定到聲明foo變量最近的作用域中),但不支持塊級作用域(變量定義的作用域并不是離其最近的封閉語句或代碼塊)。

不明白這個特性將會導致一些微妙的bug:

 

復制代碼代碼如下:

function isWinner(player,others){
    var highest = 0;
    for(var i = 0,n = others.length ;i<n;i++){
          var player = others[i];
          if(player.score > highest){
                   highest = player.score;
          }
    }
    return player.score > highest;
}

 

1.5 當心命名函數表達式笨拙的作用域

 

復制代碼代碼如下:

function double(x){ return x*2; }
var f = function(x){ return x*2; }

 

同一段函數代碼也可以作為一個表達式,卻具有截然不同的含義。匿名函數和命名函數表達式的官方區別在于后者會綁定到與其函數名相同的變量上,該變量作為該函數的一個局部變量。這可以用來寫遞歸函數表達式。

 

復制代碼代碼如下:

var f = function find(tree,key){
  //....
  return find(tree.left , key) || 
             find(tree.right,key);    
}

 

值得注意的是,變量find的作用域只在其自身函數中,不像函數聲明,命名函數表達式不能通過其內部的函數名在外部被引用。

 

復制代碼代碼如下:

find(myTree,"foo");//error : find is not defined; 
var constructor = function(){ return null; }
var f= function(){
    return constructor();
};
f();//{}(in ES3 environments)

 

該程序看起來會產生null,但其實會產生一個新的對象。

因為命名函數變量作用域內繼承了Object.prototype.constructor(即Oject的構造函數),就像with語句一樣,這個作用域會因Object.prototype的動態改變而受到影響。在系統中避免對象污染函數表達式作用域的辦法是避免任何時候在Object.prototype中添加屬性,以避免使用任何與標準Object.prototype屬性同名的局部變量。

    在流行的javascript引擎中另外一個缺點是對命名函數表達式的聲明進行提升。

 

復制代碼代碼如下:

var f = function g(){return 17;}
g(); //17 (in nonconformat environment)

 

一些javascript環境甚至把f和g這兩個函數作為不同的對象,從而導致不必要的內存分配。

1.6 當心局部塊函數聲明笨拙的作用域

 

復制代碼代碼如下:

function f() {return "global" ; }
function  test(x){
    function f(){return "local";}
    var result = [];
    if(x){
         result.push(f());
    }      
     result.push(f());
     result result;
}
test(true);   //["local","local"]
test(false);  //["local"]

 

 

復制代碼代碼如下:

function f() {return "global" ; }
function  test(x){
    var result = [];
    if(x){
         function f(){return "local";}
         result.push(f());
    }      
     result.push(f());
     result result;
}
test(true);   //["local","local"]
test(false);  //["local"]

 

javascript沒有塊級作用域,所以內部函數f的作用域應該是整個test函數。一些javascript環境確實如此,但并不是所有javascript環境都這樣,javascript實現在嚴格模式下將這類函數報告為錯誤(具有局部塊函數聲明的處于嚴格模式下的程序將報告成一個語法錯誤),有助于檢測不可移植代碼,為未來的標準版本在給局部塊函數聲明給更明智和可以的語義。針對這種情況,可以考慮在test函數內聲明一局部變量指向全局函數f。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美午夜视频一区二区| 日韩电影在线观看中文字幕| 色综合天天综合网国产成人网| 91久久久精品| 日本伊人精品一区二区三区介绍| 日韩av大片免费看| 久久精品夜夜夜夜夜久久| 国产精品嫩草视频| 久久躁狠狠躁夜夜爽| 亚洲精品电影在线观看| 欧美性猛交xxxxx免费看| 亚洲一区二区三区四区视频| 国内揄拍国内精品少妇国语| 欧洲成人午夜免费大片| 国产欧美一区二区三区视频| 日韩人在线观看| 久久中文字幕在线视频| 北条麻妃99精品青青久久| 九九精品在线播放| 欧美在线一级va免费观看| 国产欧美一区二区三区久久| 这里精品视频免费| 国产成人精品免费久久久久| 亚洲免费精彩视频| 国产精品网站视频| 日本最新高清不卡中文字幕| 国产精品白丝av嫩草影院| 日韩中文字幕在线观看| 91亚洲精华国产精华| 亚洲欧美国产视频| 久久av在线播放| 亚洲人成网站免费播放| 日韩中文字幕在线视频| 久久久精品2019中文字幕神马| 日韩av在线精品| 57pao国产精品一区| 欧美成aaa人片免费看| 亚洲老头老太hd| 日本免费在线精品| 91免费欧美精品| 欧美一级黑人aaaaaaa做受| 热re99久久精品国产66热| 日韩精品中文在线观看| 中文字幕国产亚洲2019| 久久精品国亚洲| 亚洲国产成人精品女人久久久| 成人欧美在线观看| 亚洲伊人久久综合| 亚洲一区二区精品| 亚洲人午夜色婷婷| 91中文字幕在线观看| 日韩电影在线观看永久视频免费网站| 国产精品视频区| 国产91热爆ts人妖在线| 91国语精品自产拍在线观看性色| 在线观看欧美www| 午夜精品美女自拍福到在线| 亚洲国产精久久久久久| 国产精品久久久久久久9999| 久久久国产在线视频| 久久精品视频va| 亚洲国产精品福利| 日产精品久久久一区二区福利| 亚洲第一色在线| 亚洲午夜精品久久久久久性色| 亚洲天堂免费观看| 精品亚洲精品福利线在观看| 久久精彩免费视频| 搡老女人一区二区三区视频tv| 亚洲女人初尝黑人巨大| 国产成人a亚洲精品| 欧美国产日韩免费| 国产美女91呻吟求| 亚洲午夜性刺激影院| 久久久噜噜噜久久| 久久韩国免费视频| 亚洲毛片一区二区| 精品中文字幕在线2019| 色综合久综合久久综合久鬼88| 色视频www在线播放国产成人| 精品国产福利在线| 全球成人中文在线| 精品日本美女福利在线观看| 欧美性xxxxx极品娇小| 久久在线视频在线| 成人97在线观看视频| 美女视频黄免费的亚洲男人天堂| 日韩国产欧美精品在线| 国产精品色午夜在线观看| 国产69精品久久久久9999| 黄网站色欧美视频| 青青草一区二区| 欧洲成人性视频| 久久中文精品视频| 亚洲人成在线免费观看| 性欧美长视频免费观看不卡| 日产精品久久久一区二区福利| 亚洲国产精品电影| www日韩欧美| 九九热这里只有精品免费看| 亚洲免费视频观看| 亚洲第一色中文字幕| 国产999在线| 日韩在线观看免费| 日韩av电影手机在线| 国产成人在线一区| 色av中文字幕一区| 久久久亚洲国产天美传媒修理工| 91在线直播亚洲| 久久精品电影网| 国产精品高潮呻吟久久av野狼| 亚洲a中文字幕| 麻豆乱码国产一区二区三区| 欧美激情视频网址| 亚洲乱码av中文一区二区| 国产精品a久久久久久| 91亚洲国产成人久久精品网站| 成人写真福利网| 国产精品96久久久久久又黄又硬| 国产精品免费视频久久久| 97国产精品久久| 久久人人爽人人爽人人片av高请| 亚洲黄色av女优在线观看| 91成人天堂久久成人| 日韩av中文字幕在线播放| 国产日韩欧美视频| 亚洲成人精品久久久| 日本国产欧美一区二区三区| 亚洲欧美国产视频| 国模吧一区二区三区| 亚洲精品电影网在线观看| 久久99热这里只有精品国产| 亚洲黄色片网站| 成人h视频在线观看播放| 日本欧美中文字幕| 成人精品视频久久久久| 亚洲欧美日韩视频一区| 国产精品久久久久久久久粉嫩av| 精品国产区一区二区三区在线观看| 日本成人免费在线| 日本高清久久天堂| 高跟丝袜欧美一区| 亚洲丝袜一区在线| 午夜精品久久久久久久白皮肤| 国产精品久久久久久久电影| 91精品久久久久久久久青青| 136fldh精品导航福利| 热久久美女精品天天吊色| 自拍偷拍亚洲一区| 亚洲精品视频免费在线观看| 国产精品777| 欧美黄色成人网| 亚洲欧美999| 欧美丰满少妇xxxxx| 91日韩在线播放| 国产精品国产自产拍高清av水多| 俺也去精品视频在线观看| 亚州欧美日韩中文视频| 亚洲第一区在线观看| 激情成人中文字幕| 51ⅴ精品国产91久久久久久| 欧美最猛黑人xxxx黑人猛叫黄| 欧美xxxx14xxxxx性爽| 91精品久久久久久久久不口人|