JavaScript的一些常見誤區

接觸JavaScript兩年多遇到過各類錯誤,其中有一些讓人防不勝防,原來對JavaScript的誤會如此之深,僅以此文總結一下常見的各類想固然的誤區。 html

String replace

string的replace方法咱們常常用,替換string中的某些字符,語法像這樣子 正則表達式

1
string.replace(subStr/reg,replaceStr/function)

第一個參數是要查找的字符串或者一個正則表達式,第二個參數是想替換成的字符串或一個方法,咱們能夠這麼使用 數組

1
"I'm Byron".replace("B","b")// I'm byron

記過和咱們想得同樣,可是 瀏覽器

1
"I'm a student, and you?".replace("n","N");// I'm a studeNt, and you?

和咱們預期的不同,第二個‘n’沒有被替換。字符串的 replace 方法若是第一個參數傳入字符串,那麼只有第一個匹配項會被替換。若是要替換所有匹配項,須要傳入一個 RegExp 對象並指定其 global 屬性。 閉包

1
"I'm a student, and you?".replace(/n/g,"N");// I'm a studeNt, aNd you?

這樣才能夠達到咱們目的,關於string replace方法詳細使用能夠看看JavaScript string 的replace 函數

Date 對象

咱們能夠這樣構造一個Date對象 this

1
2
3
4
newDate()//Date {Fri Aug 02 2013 16:50:33 GMT+0800 (China Standard Time)}
newDate(milliseconds) //Date {Fri Aug 02 2013 16:53:26 GMT+0800 (China Standard Time)}
newDate("2013/08/02")//Date {Fri Aug 02 2013 00:00:00 GMT+0800 (China Standard Time)}
newDate(year,month,day,hours,minutes,seconds,ms)

前三種方式沒有什麼問題,但第四種獲得的結果回合咱們預期的不一致 spa

1
newDate(2013,08,02) //Date {Mon Sep 02 2013 00:00:00 GMT+0800 (China Standard Time)}

咱們能夠看到,傳入的月份是08,返回的結果倒是九月。這是由於Date對象的月份是從0開始計數的(天卻不是),即0表明一月,1表明二月…11表明12月。在調用Date實例的getMonth方法時尤爲要注意 prototype

1
2
vard =newDate(2012, 4, 15);       // 2012年5月15日
alert(d.getMonth());           // 結果爲4

Date.parse

Date.parse方法能夠識別兩種格式的字符串參數(標準的長日期格式,好比帶星期的那種,也能夠識別,不過不經常使用)線程

1. 「M/d/yyyy」: 美國的日期顯示格式。若是年傳入2位則做爲 19xx 處理

2.」yyyy-MM-dd」 或 「yyyy/MM/dd」: 注意月和日都必須是兩位

Date.parse 的返回結果不是一個Date對象,而是從1970-01-01午夜(GMT)到給定日期之間的毫秒數。能夠用Date的構造函數將其轉換爲Date對象。

1
2
3
newDate(Date.parse("8/2/2012"));   // 正確識別爲2012年8月2日
newDate(Date.parse("2012-08-02"));   // 正確識別爲2012年8月2日
newDate(Date.parse("2012-8-2"));   // 不能識別

for…in 遍歷數組

for…in用來遍歷一個對象中的成員(屬性,方法),若是用來遍歷數組的到的結果並非預期中數組每項的值,方法神馬的會被遍歷出來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Array.prototype.contains =function(item) {
for(vari = 0; i <=this.length - 1; i++) {
if(this[i] == item)
returnthis[i];
}
}
varstaff = ["Staff A","Staff B"];
// Normal Enumeration: Only the 2 items are enumerated
for(vari = 0; i <= staff.length - 1; i++) {
varsingleStaff = staff[i];
alert(singleStaff);
}
// for...in Enumeration: the method "contains" are enumerated, too
for(varsingleStaffinstaff) {
alert(singleStaff);
}

事實上不少時候咱們都會給數組加上其餘屬性。好比 jQuery 對象就是一個數組對象加上一些擴展方法;再好比 String.prototype.match 方法返回值就是一個數組(正則表達式及其子表達式的匹配項)加上 index 和 input 兩個屬性。

parseInt

語法: parseInt(stringradix)

參數 描述
string 必需。要被解析的字符串。
radix 可選。表示要解析的數字的基數。該值介於 2 ~ 36 之間。若是省略該參數或其值爲 0,則數字將以 10 爲基礎來解析。若是它以 「0x」 或 「0X」 開頭,將以 16 爲基數。若是該參數小於 2 或者大於 36,則 parseInt() 將返回 NaN。

 

當參數 radix 的值爲 0,或沒有設置該參數時,parseInt() 會根據 string 來判斷數字的基數。

舉例,若是 string(開頭結尾空格自動省略) 以 「0x」 開頭,parseInt() 會把 string 的其他部分解析爲十六進制的整數。若是 string 以 0 開頭,那麼 ECMAScript v3 容許 parseInt() 的一個實現把其後的字符解析爲八進制或十六進制的數字。若是 string 以 1 ~ 9 的數字開頭,parseInt() 將把它解析爲十進制的整數。若是字符串的第一個字符不能被轉換爲數字,那麼 parseFloat() 會返回 NaN。

1
2
3
4
5
6
parseInt("10");       //返回 10
parseInt("19",10);       //返回 19 (10+9)
parseInt("11",2);       //返回 3 (2+1)
parseInt("17",8);       //返回 15 (8+7)
parseInt("1f",16);       //返回 31 (16+15)
parseInt("010");       //未定:返回 10 或 8

setTimeout/setInterval執行時機

setTimeout()和setInterval()常常被用來處理延時和定時任務。setTimeout() 方法用於在指定的毫秒數後調用函數或計算表達式,而setInterval()則能夠在每隔指定的毫秒數循環調用函數或表達式,直到clearInterval把它清除。

JavaScript實際上是運行在單線程的環境中的,這就意味着定時器僅僅是計劃代碼在將來的某個時間執行,而具體執行時機是不能保證的,由於頁面的生命週期中,不一樣時間可能有其餘代碼在控制JavaScript進程。在頁面下載完成後代碼的運行、事件處理程序、Ajax回調函數都是使用一樣的線程,實際上瀏覽器負責進行排序,指派某段程序在某個時間點運行的優先級

咱們能夠能夠把JavaScript想象成在時間線上運行。當頁面載入的時候首先執行的是頁面生命週期後面要用的方法和變量聲明和數據處理,在這以後JavaScript進程將等待更多代碼執行。當進程空閒的時候,下一段代碼會被觸發

除了主JavaScript進程外,還須要一個在進程下一次空閒時執行的代碼隊列。隨着頁面生命週期推移,代碼會按照執行順序添加入隊列,例如當按 鈕被按下的時候他的事件處理程序會被添加到隊列中,並在下一個可能時間內執行。在接到某個Ajax響應時,回調函數的代碼會被添加到隊列。JavaScript中沒有任何代碼是當即執行的,但一旦進程空閒則儘快執行。定時器對隊列的工做方式是當特定時間過去後將代碼插入,這並不意味着它會立刻執行,只能表示它儘快執行。

關於setTimeout/setInterval執行時機詳細說明能夠看看 setTimeout()和setInterval() 什麼時候被調用執行

預解析

1
2
3
4
console.log(a);//Error:a is not defined ,直接報錯,下面語句無法執行,一下結果爲註釋該句後結果
console.log(b)//undefined
varb="Test";
console.log(b);//Test

很奇怪前兩句變量a,b都沒有聲明,第一句卻報錯,第二句可以輸出undefined?這是由於JavaScript 是解釋型語言,但它並非直接逐步執行的,JavaScript解析過程分爲前後兩個階段,一個是預處理階段,另一個就是執行階段。在預處理階段 JavaScript解釋器將完成把JavaScript腳本代碼轉換到字節碼,而後第二階段JavaScript解釋器藉助執行環境把字節碼生成機械 碼,並順序執行。

也就說JavaScript值執行第一句語句以前就已經將函數/變量聲明預處理了,var b=」Test」 至關於兩個語句,var b;(undefined結果的來源,在執行第一句語句以前已經解析),b=」Test」(這句是順序執行的,在第二句以後執行)。這也是爲何咱們能夠 在方法聲明語句以前就調用方法的緣由。

1
2
3
4
5
showMsg();// This is message
functionshowMsg()
{
    alert('This is message');
}

塊級做用域

JavaScript沒有塊級做用域,只有函數級做用域,這就意味着{}在JavaScript中只能起到語法塊的做用,而不能起到做用域塊做用

1
2
3
4
5
if(true){//語法塊,保證{}內代碼if條件成立執行
    //...
    vara=3;
}
console.log(a);//3

上面例子能夠清楚看到屬於window的console.log方法依然能夠訪問貌似是局部變量的a

閉包

首先從一個經典錯誤談起,頁面上有若干個div, 咱們想給它們綁定一個onclick方法,因而有了下面的代碼

1
2
3
4
5
6
<div id="divTest">
        <span>0</span> <span>1</span> <span>2</span> <span>3</span>
    </div>
    <div id="divTest2">
        <span>0</span> <span>1</span> <span>2</span> <span>3</span>
    </div>
1
2
3
4
5
6
7
8
$(document).ready(function() {
            varspans = $("#divTest span");
            for(vari = 0; i < spans.length; i++) {
                spans[i].onclick =function() {
                    alert(i);
                }
            }
        });

很簡單的功能但是卻恰恰出錯了,每次alert出的值都是4,簡單的修改就好使了

1
2
3
4
5
6
7
8
9
10
varspans2 = $("#divTest2 span");
        $(document).ready(function() {
            for(vari = 0; i < spans2.length; i++) {
                (function(num) {
                    spans2[i].onclick =function() {
                        alert(num);
                    }
                })(i);
            }
        });

 

閉包是指有權限訪問另外一個函數做用域的變量的函數,建立閉包的常見方式就是在一個函數內部建立另外一個函數,只要存在調用內部函數的可 能,JavaScript就須要保留被引用的函數。並且JavaScript運行時須要跟蹤引用這個內部函數的全部變量,直到最後一個變量廢 棄,JavaScript的垃圾收集器才能釋放相應的內存空間。

相關文章
相關標籤/搜索