欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何編寫(xiě)高質(zhì)量JS代碼

 更新時(shí)間:2014年12月28日 10:09:58   投稿:hebedich  
這篇文章主要介紹了如何編寫(xiě)高質(zhì)量JS代碼的方法及相關(guān)資料,需要的朋友可以參考下

想寫(xiě)出高效的javascript類(lèi)庫(kù)卻無(wú)從下手;

嘗試閱讀別人的類(lèi)庫(kù),卻理解得似懂給懂;

打算好好鉆研js高級(jí)函數(shù),但權(quán)威書(shū)上的內(nèi)容太零散,

即使記住“用法”,但到要“用”的時(shí)候卻沒(méi)有想“法”。

也許你和我一樣,好像有一顧無(wú)形的力量約束著我們的計(jì)劃,讓我們一再認(rèn)為知識(shí)面的局限性,致使我們?cè)靥げ?,難以向前跨越。

這段時(shí)間,各種作業(yè)、課程設(shè)計(jì)、實(shí)驗(yàn)報(bào)告,壓力倍增。難得擠出一點(diǎn)點(diǎn)時(shí)間,絕不睡懶覺(jué),整理總結(jié)往日所看的書(shū),只為了可以離寫(xiě)自己的類(lèi)庫(kù)近一點(diǎn)。

本文參考自《javascript語(yǔ)言精粹》和《Effective JavaScript》。例子都被調(diào)試過(guò),理解過(guò)后,我想把一些“深?yuàn)W”的道理說(shuō)得淺顯一點(diǎn)點(diǎn)。

1.變量作用域

作用域?qū)τ诔绦騿T來(lái)說(shuō)就像氧氣。它無(wú)處不在,甚至,你往往不會(huì)去想他。但當(dāng)它被污染時(shí)(例如使用全局對(duì)象),你會(huì)感覺(jué)到窒息(例如應(yīng)用響應(yīng)變慢)。javascript核心作用域規(guī)則很簡(jiǎn)單,被精心設(shè)計(jì),且很強(qiáng)大。有效地使用javascript需要掌握變量作用域的一些基本概念,并了解一些可能導(dǎo)致難以捉摸的、令人討厭的問(wèn)題的極端情況。

1.1盡量少用全局變量

javascript很容易在全局命名空間中創(chuàng)建變量。創(chuàng)建全局變量毫不費(fèi)力,因?yàn)樗恍枰魏涡问降穆暶鳎夷鼙徽麄€(gè)程序的所有代碼自動(dòng)地訪問(wèn)。

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

復(fù)制代碼 代碼如下:

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

另外,你或許會(huì)認(rèn)為,“先怎么怎么寫(xiě),日后再整理”比較方便,但優(yōu)秀的程序員會(huì)不斷地留意程序的結(jié)構(gòu)、持續(xù)地歸類(lèi)相關(guān)的功能以及分離不相關(guān)的組件,并這些行為作為編程過(guò)稱(chēng)中的一部分。

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

復(fù)制代碼 代碼如下:

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

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

鑒于引用為綁定的全局變量會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤,因此,保存作用域清晰和簡(jiǎn)潔會(huì)使代碼的使用者更容易理解程序聲明了那些全局變量。

由于全局對(duì)象提供了全局環(huán)境的動(dòng)態(tài)反應(yīng)機(jī)制,所以可以使用它查詢一個(gè)運(yùn)行環(huán)境,檢測(cè)在這個(gè)平臺(tái)下哪些特性可用。

eg.ES5引入了一個(gè)全局的JSON對(duì)象來(lái)讀寫(xiě)JSON格式的數(shù)據(jù)。

復(fù)制代碼 代碼如下:

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

 如果你提供了JSON的實(shí)現(xiàn),你當(dāng)然可以簡(jiǎn)單無(wú)條件地使用自己的實(shí)現(xiàn)。但是由宿主環(huán)境提供的內(nèi)置實(shí)現(xiàn)幾乎更適合的,因?yàn)樗鼈兪怯肅語(yǔ)言寫(xiě)進(jìn)瀏覽器的。因?yàn)樗鼈儼凑找欢ǖ臉?biāo)準(zhǔn)對(duì)正確性和一致性進(jìn)行了嚴(yán)格檢查,并且普遍來(lái)說(shuō)比第三方實(shí)現(xiàn)提供更好的性能。

當(dāng)初數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)模擬串的基本操作,要求不能使用語(yǔ)言本身提供的方法。javascript對(duì)數(shù)組的基本操作實(shí)現(xiàn)得很好,如果只是出于一般的學(xué)習(xí)需要,模擬語(yǔ)言本身提供的方法的想法很好,但是如果真正投入開(kāi)發(fā),無(wú)需考慮第一時(shí)間選擇使用javascript內(nèi)置方法。

1.2避免使用with

with語(yǔ)句提供任何“便利“,讓你的應(yīng)用變得不可靠和低效率。我們需要對(duì)單一對(duì)象依次調(diào)用一系列方法。使用with語(yǔ)句可以很方便地避免對(duì)對(duì)象的重復(fù)引用:

復(fù)制代碼 代碼如下:

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

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

復(fù)制代碼 代碼如下:

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

事實(shí)上,javascript對(duì)待所有的變量都是相同的。javascript從最內(nèi)層的作用域開(kāi)始向外查找變量。with語(yǔ)言對(duì)待一個(gè)對(duì)象猶如該對(duì)象代表一個(gè)變量作用域,因此,在with代碼塊的內(nèi)部,變量查找從搜索給定的變量名的屬性開(kāi)始。如果在這個(gè)對(duì)象中沒(méi)有找到該屬性,則繼續(xù)在外部作用域中搜索。with塊中的每個(gè)外部變量的引用都隱式地假設(shè)在with對(duì)象(以及它的任何原型對(duì)象)中沒(méi)有同名的屬性。而在程序的其他地方創(chuàng)建或修改with對(duì)象或其原型對(duì)象不一定會(huì)遵循這樣的假設(shè)。javascript引擎當(dāng)然不會(huì)讀取局部代碼來(lái)獲取你使用了那些局部變量。javascript作用域可被表示為高效的內(nèi)部數(shù)據(jù)結(jié)構(gòu),變量查找會(huì)非??焖?。但是由于with代碼塊需要搜索對(duì)象的原型鏈來(lái)查找with代碼里的所有變量,因此,其運(yùn)行速度遠(yuǎn)遠(yuǎn)低于一般的代碼塊。

替代with語(yǔ)言,簡(jiǎn)單的做法,是將對(duì)象綁定在一個(gè)簡(jiǎn)短的變量名上。

復(fù)制代碼 代碼如下:

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

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

復(fù)制代碼 代碼如下:

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

1.3熟練掌握閉包

理解閉包有單個(gè)概念:

a)javascript允許你引用在當(dāng)前函數(shù)以外定義的變量。

復(fù)制代碼 代碼如下:

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

b)即使外部函數(shù)已經(jīng)返回,當(dāng)前函數(shù)仍然可以引用在外部函數(shù)所定義的變量

復(fù)制代碼 代碼如下:

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的函數(shù)值包含了比調(diào)用它們時(shí)所執(zhí)行所需要的代碼還要多的信息。而且,javascript函數(shù)值還在內(nèi)部存儲(chǔ)它們可能會(huì)引用的定義在其封閉作用域的變量。那些在其所涵蓋的作用域內(nèi)跟蹤變量的函數(shù)被稱(chēng)為閉包。

 make函數(shù)就是一個(gè)閉包,其代碼引用了兩個(gè)外部變量:magicIngredient和filling。每當(dāng)make函數(shù)被調(diào)用時(shí),其代碼都能引用這兩個(gè)變量,因?yàn)殚]包存儲(chǔ)了這兩個(gè)變量。

函數(shù)可以引用在其作用域內(nèi)的任何變量,包括參數(shù)和外部函數(shù)變量。我們可以利用這一點(diǎn)來(lái)編寫(xiě)更加通用的sandwichMaker函數(shù)。

復(fù)制代碼 代碼如下:

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最優(yōu)雅、最有表現(xiàn)力的特性之一,也是許多習(xí)慣用法的核心。

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

復(fù)制代碼 代碼如下:

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

該例子產(chǎn)生一個(gè)包含三個(gè)閉包的對(duì)象。這三個(gè)閉包是set,type和get屬性,它們都共享訪問(wèn)val變量,set閉包更新val的值。隨后調(diào)用get和type查看更新的結(jié)果。

1.4理解變量聲明提升

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

不明白這個(gè)特性將會(huì)導(dǎo)致一些微妙的bug:

復(fù)制代碼 代碼如下:

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 當(dāng)心命名函數(shù)表達(dá)式笨拙的作用域

復(fù)制代碼 代碼如下:

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

同一段函數(shù)代碼也可以作為一個(gè)表達(dá)式,卻具有截然不同的含義。匿名函數(shù)和命名函數(shù)表達(dá)式的官方區(qū)別在于后者會(huì)綁定到與其函數(shù)名相同的變量上,該變量作為該函數(shù)的一個(gè)局部變量。這可以用來(lái)寫(xiě)遞歸函數(shù)表達(dá)式。

復(fù)制代碼 代碼如下:

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

值得注意的是,變量find的作用域只在其自身函數(shù)中,不像函數(shù)聲明,命名函數(shù)表達(dá)式不能通過(guò)其內(nèi)部的函數(shù)名在外部被引用。

復(fù)制代碼 代碼如下:

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

該程序看起來(lái)會(huì)產(chǎn)生null,但其實(shí)會(huì)產(chǎn)生一個(gè)新的對(duì)象。

因?yàn)槊瘮?shù)變量作用域內(nèi)繼承了Object.prototype.constructor(即Oject的構(gòu)造函數(shù)),就像with語(yǔ)句一樣,這個(gè)作用域會(huì)因Object.prototype的動(dòng)態(tài)改變而受到影響。在系統(tǒng)中避免對(duì)象污染函數(shù)表達(dá)式作用域的辦法是避免任何時(shí)候在Object.prototype中添加屬性,以避免使用任何與標(biāo)準(zhǔn)Object.prototype屬性同名的局部變量。

    在流行的javascript引擎中另外一個(gè)缺點(diǎn)是對(duì)命名函數(shù)表達(dá)式的聲明進(jìn)行提升。

復(fù)制代碼 代碼如下:

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

一些javascript環(huán)境甚至把f和g這兩個(gè)函數(shù)作為不同的對(duì)象,從而導(dǎo)致不必要的內(nèi)存分配。

1.6 當(dāng)心局部塊函數(shù)聲明笨拙的作用域

復(fù)制代碼 代碼如下:

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"]

復(fù)制代碼 代碼如下:

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沒(méi)有塊級(jí)作用域,所以內(nèi)部函數(shù)f的作用域應(yīng)該是整個(gè)test函數(shù)。一些javascript環(huán)境確實(shí)如此,但并不是所有javascript環(huán)境都這樣,javascript實(shí)現(xiàn)在嚴(yán)格模式下將這類(lèi)函數(shù)報(bào)告為錯(cuò)誤(具有局部塊函數(shù)聲明的處于嚴(yán)格模式下的程序?qū)?bào)告成一個(gè)語(yǔ)法錯(cuò)誤),有助于檢測(cè)不可移植代碼,為未來(lái)的標(biāo)準(zhǔn)版本在給局部塊函數(shù)聲明給更明智和可以的語(yǔ)義。針對(duì)這種情況,可以考慮在test函數(shù)內(nèi)聲明一局部變量指向全局函數(shù)f。

相關(guān)文章

最新評(píng)論