搜尋
首頁web前端js教程如何編寫高品質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作用域可被表示為高效率的內部資料結構,變數查找會非常快速。但由於with程式碼區塊需要搜尋物件的原型鏈來尋找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           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。

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器