JavaScript 是對初學者比較友好的一門編程語言,基本上花個半小時看下語法就能寫出能運行的代碼。JavaScript 是動態腳本語言,對數據類型沒有太多的限制,寫起來非常靈活。但正因為如此,初學者如果不深入了解語言本身,往往會犯一些錯誤,從而導致一些很難發現的 bug。
拋開 JavaScript 語言設計層面的問題不說,畢竟它是 Brendan Eich 當年用短短十天時間設計出來的,有點缺陷也是在所難免。作為開發者,我們該怎樣避免一些常見的低級錯誤呢?本文就列舉幾個常見錯誤,看看你有沒有似曾相識。
混淆 undefined 和 null
JavaScript 中的undefined
和 null
都可用來表示沒有值,但是二者之間有所區別。undefined
字面意思是“未定義”,但它的含義其實已經超出了變量未定義的范疇:嘗試讀取對象不存在的屬性、沒有return
語句的函數的返回值、聲明后沒有賦值的變量甚至顯式賦值為undefined
的變量等,它們的結果都是undefined
。用typeof
測試它的類型,是字符串 'undefined'
。而 null
就比較純粹了,變量只有設置為null
才有這個值。另外,null
是對象類型,即typeof(null)
的值是字符串'object'
。
需要注意的是,用if
判斷這兩個值都是false
,而且null==undefined
是成立的,這一點初學者通常容易搞混。因此,盡量統一把“沒有值”都設置為undefined
,這樣就省去了判斷區分的麻煩。
返回 undefined
的函數:
const f = () => {}
設置變量的值為 undefined
:
x = undefined;
判斷屬性是否為 undefined
:
typeof obj.prop === 'undefined'
obj.prop === undefined
判斷變量是否為 undefined
:
typeof x === 'undefined'
變量聲明后沒有賦值,自動就有了 undefined
值。
如果一定要判斷null
,用全等判斷:
obj.prop === null
x === null
使用 typeof
是無法判斷 null
的,因為它是對象類型。
混淆數字相加和字符串拼接
在 JavaScript 中,加號 +
操作符既可用於數字相加,也可以用於字符串拼接。由於 JavaScript 是動態語言,操作符會自動將變量轉成相同數據類型再運算。比如:
let x = 1 + 1; // 2
結果是 2
,是我們期望的數字相加操作,因為兩個值都是數字。
但是,如果是下面這種表達式:
let x = 1 + '1'; // “11”
結果是'11'
,因為第一個數字會轉換成字符串。這里的加號+
運算符被用作字符串拼接,而不是數字相加。這里能直接看到表達式的值還算清楚,如果是由多個變量組成的表達式就很難判斷類型了。
為了解決這個問題,我們可以把字符串都轉成數字類型,再進行運算。例如:
let x = 1;
let y = '2';
let z = Number(x) + Number(y);
這樣,運行結果就是3
了。 Number
函數接收任意類型的值,如果能轉成數字就返回數字,否則返回NaN
。還可以用 new Number(...).valueOf()
函數:
let x = 1;
let y = '2';
let z = new Number(x).valueOf() + new Number(y).valueOf();
由於 new Number(...)
是實例化一個構造函數,返回的是一個對象,並不是數字類型。如果要得到原始的數字類型,需要用該對象的valueOf
方法。其實還有個更簡潔的方法:
let x = 1;
let y = '2';
let z = +x + +y;
變量前面的 +
作用是將它轉換成數字,或者NaN
,跟Number
函數的作用相同。
return 語句換行問題
JavaScript 語法規定換行代表語句結束。例如:
const add = (a, b) => {
return
a + b;
}
add(1,2); // undefined
本以為會返回 3
,實際上是undefined
。這是因為在a + b
之前,函數已經執行了return
。要解決這個問題,有兩個做法:要么把表達式跟return
放在一行,要么把表達式套一層括號。
const add = (a, b) => {
return a + b;
}
// 或者
const add = (a, b) => {
return (
a + b
);
}
加括號為什么可以換行呢?因為括號里的是表達式,不是語句。表達式可以拆成多行,如果很長的話。用箭頭函數會更直觀:
const add = (a, b) => a + b
箭頭函數里的單行表達式自帶return
效果,當然也可以在表達式外面套一層括號:
const add = (a, b) => (a + b)
這個括號在返回對象字面量的箭頭函數里有點用處,因為不加圓括號()
的話,{}
只是函數體的開始和結束標記,要返回對象字面量,還要顯式return {...}
。
如果某行代碼中的語句不完整,JavaScript 解析器會將下一行的語句合並一起解析。比如:
const power = (a) => {
const
power = 10;
return a ** 10;
}
// 等同於:
const power = (a) => {
const power = 10;
return a ** 10;
}
但是對於完整的語句,比如return
,就不會合並多行。
用 return 跳出 forEach 循環
JavaScript 數組有個 forEach
方法,用於對數組元素進行循環操作。初學者很容易聯想到 for
循環的break
或continue
關鍵字,用來中止循環。但是對不起,forEach
沒有這兩個關鍵字。那用return
行不行?可以用,但它的作用就是提前返回函數,跟continue
的效果類似,用於結束本次循環。要跳出整個循環,return
做不到。
const nums = [1, 2, 3, 4, 5, 6];
let firstEven;
nums.forEach(n => {
if (n % 2 ===0 ) {
firstEven = n;
return n;
}
});
console.log(firstEven); // 6
代碼本意是想找出第一個偶數,找到就退出循環。但實際並沒有退出循環,因此最終結果是最后一個偶數。
有解決辦法嗎?這種情況可以用for
循環,或者用數組filter
、find
之類的方法。
總結
雖然 JavaScript 很容易上手,但稍不注意還是比較容易犯錯。本文簡單介紹了幾種容易犯的錯,希望對你有所幫助。
更多前端技術干貨盡在微信公眾號:1024譯站