首頁 > web前端 > js教程 > JavaScript程式碼編寫中各種各樣的坑和填坑方法_javascript技巧

JavaScript程式碼編寫中各種各樣的坑和填坑方法_javascript技巧

WBOY
發布: 2016-05-16 16:45:50
原創
1380 人瀏覽過

坑」這個字,在此的意思是「陷阱」。由於JavaScript 「弱語言」的性質,使得其在使用過程中異常的寬鬆靈活,但也極為容易「中招」。這些坑往往隱藏著,所以必須擦亮雙眼,才能在學習與應用JS 的道路上走的一帆風順。

一、全域變數

JavaScript 透過函數管理作用域。在函數內部宣告的變數只在這個函數內部,函數外面不可用。另一方面,全域變數就是在任何函數外面聲明的或是未宣告直接簡單使用的。

“未聲明直接簡單使用”,指的是不用 var 關鍵字來聲明變數。這個我們已經很清楚,避免造成隱式產生全域變數的方法就是宣告變數盡量用 var 關鍵字。

可你以為用了 var 就 ok 了?來看看這個坑:


複製程式碼 程式碼如下:
function foo() {
    var a = b = 0;
    // 身體...
}

也許你期望得到的是兩個局部變量,但 b 卻是貨真價實的全域變數。 why? Because 賦值運算是自右往左的,所以這相當於:


複製程式碼 程式碼如下:

程式碼如下:

 
function foo() {
    var a = (b = 0);    // body...

}

所以 b 是全域變數。

填坑:變數聲明,最好一個個來,別搞批發~_~;

二、變量聲明

先來看坑:複製代碼

代碼如下:

 
myName = "global";

function foo() {
    alert(myName);
   alert(myName);
}

foo();

乍看上去,我們預期期望兩次alert 的結果分別為“global” 與“local”,但真實的結果是“undefined” 與“local”。 why? Because 變數在同一作用域(同一函數)中,宣告都是被提至作用域頂部先進行解析的。

所以以上程式碼片段的執行行為可能就像這樣:複製程式碼
程式碼如下:


function foo() {
    var myName;
    alert(myName); // "undefined"
    myName = "local";

    myName = "local";
🎜>}
用另一個坑來測試下你是否真的理解了預解析:複製代碼

代碼如下:

 
if (!("a" in window)) {
    var a = 1;
}

alert(a);
}alert(a);}alert(a);
a 變數的宣告被提前到了程式碼頂端,此時還未賦值。接下來進入 if 語句,判斷條件中 "a" in window 已成立(a 已被宣告為全域變數),所以判斷語句計算結果為 false,直接就跳出 if 語句了,所以 a 的值為 undefined。




複製程式碼


程式碼如下:

var a; // "undefined"

var a; // "undefined"

var a; // "un .log("a" in window); // true

if (!("a" in window)) {    var a = 1; // 不執行} alert(a); // "undefined"填坑:變數聲明,最好手動置於作用域頂部,對於無法當下賦值的變量,可採取先聲明後賦值的手法。

三、函數宣告


函數宣告也提前至作用域頂部,先於任何表達式和語句被解析和求值的


複製程式碼 程式碼如下: alert(typeof foo); // "function"
function foo() {    // body...}}可以比較一下:複製程式碼 程式碼如下:

alert(typeof foo); // "undefined"

var foo = function () {
    // body...
};















};明白了這個道理的你,是否還會踩到以下的坑呢? 複製程式碼

程式碼如下:
 
function test() {
 ");
}test();function test() {    alert("2");}
test( );


運行以上程式碼片段,看到的兩次彈跳窗顯示的都是 “2”,為什麼不是分別為 “1” 和 “2” 呢?很簡單,test 的宣告會先於 test() 被解析,由於後者覆寫前者,所以兩次執行的結果都是 “2”。

填坑:多數情況下,我用函數表達式來取代函數聲明,特別是在一些語句區塊中。

四、函數表達式

先看命名函數表達式,理所當然,就是它得有名字,例如:


複製程式碼 程式碼如下:var bar = function foo() {    // body...
};

要注意的是:函數名只對其函數內部可見。如以下坑:



複製程式碼

程式碼如下:

foo(); // 出錯:ReferenceError


填坑:盡量少用命名函數表達式(除了一些遞歸以及 debug 的用途),切勿將函數名稱使用於外部。


五、函數的自執行


對於函數表達式,可以透過後面加上 () 自執行,而且可在括號中傳遞參數,而函數宣告不可以。坑:




複製程式碼


程式碼如下:

 
// (1) 這只是分組運算符,不是函數呼叫!
// 所以這裡函數沒有執行,依舊是聲明
function foo(x) {
  alert(x);
}(1);

以下程式碼片段分別執行都彈跳視窗顯示“1”,因為在(1) 之前,都為函數表達式,所以這裡的()非分組操作符,而為運算符,表示呼叫執行。



複製程式碼

程式碼如下:// 標準的匿名函數表達式var bar>// 標準的匿名函數表達式var bar = function>var bar = function foo(x) {
  alert(x);}(1);// 前面的() 將function 宣告轉換為了表達式(function foo(x) {   alert(x);})(1);// 整個() 內為表達式(function foo(x) {  alert(x); }(1));// new 表達式new function foo(x) {  alert(x);}(1);// &&, ||, !, , -, ~ 等運算子(還有逗號),在函數表達式和函數宣告上消除歧義// 所以一旦解析器知道其中一個已經是表達式了,其它的也都預設為表達式了true && function foo(x) {  alert(x);}(1);填坑:這個坑的關鍵在於,弄清楚形形色色函數表達式的實質。 六、循環中的閉包以下演示的是一個常見的坑:複製代碼 程式碼如下:




   
文件 title><br><br>
   

點選下方的連結時,其序號


   
     href="#">連結#0
       
  • 連結#1

  •        
  • link #2

  •        
  • 連結#3

  •        
  • 連結#4

  •    


    複製程式碼程式碼如下:

    var links = 程式碼如下:


    var links = 程式碼如下:


    var links = 程式碼如下:

    var links = 程式碼如下:get. 0].getElementsByTagName("a");

    for (var i = 0, l = links.length; i     links[i].onclick = function (e ) {

            e.preventDefault();

           alert("您點選連結#" i);

       

    我們預期當點擊第 i 個鏈接時,得到這個序列索引 i 的值,實際上無論點擊哪個鏈接,得到的都是 i 在循環後的最終結果:”5”。

    解釋一下原因:當alert被呼叫時,對於循環內的匿名函數表達式,保留了對外部變數i的引用(閉包),此時循環已結束,i的值被修改為“5” 。 填坑:為了得到想要的結果,需要在每次循環中建立標記 i 的副本。以下示範正確的做法:
    複製程式碼


    程式碼如下:



      >


      -8">
        文件


       

    點選下方的連結時,顯示檔案數量其序列


       
           
  • < ;a href="#">#11 a>
  •        
  • 連結#2
  •        

  • 連結#3 a>
  •        
  • 連結#4
  •     html>



    複製程式碼


    程式碼如下:


    var links = 程式碼如下:
    var links = 程式碼如下:var links = 程式碼如下:var links = 程式碼如下.get 0].getElementsByTagName(“a”);for (var i = 0, l = links.length; i     links[i].onclick = (function (index) {         return function (e) {             (e.preventDefault();    })(i);}

    可以看到,(function () { ... })() 的形式,就是上文提到的函數的自執行,i 作為參數傳給了index,alert 再次執行時,它就擁有了對index 的引用,此時這個值是不會被循環改變的。當然,明白了其原理後,你也可以這樣寫:

    複製程式碼 程式碼如下:

    for (var i = 0, l = links.length ; i     (function (index) {
            links[i].onclick = function (e) {        }
        })(i);
    }


    It works too.
    相關標籤:
    來源:php.cn
    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
    熱門教學
    更多>
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板