做者:valentinogagliardihtml
譯者:前端小智前端
來源:githubgit
阿里雲最近在作活動,低至2折,有興趣能夠看看: promotion.aliyun.com/ntms/yunpar…es6
爲了保證的可讀性,本文采用意譯而非直譯。github
JS 有 7 種基本類型,分別以下:算法
布爾值表示的值能夠是 true
,也能夠是 false
。另外一方面,null
是故意缺乏一個值。null
一般被賦值給一個變量,用來表示變量事後會被賦予值。編程
var maybe = null;
複製代碼
而後是 undefined
,表示是一個變量沒有任何附加項:數組
var name;
console.log(name)
undefined
複製代碼
null
和 undefined
看起來很類似,但它們是兩個大相徑庭的類型,以致於開發人員仍不肯定要使用哪一個類型。微信
可使用 typeof
操做符來查看變量的類型:編程語言
typeof "alex"
"string"
複製代碼
number
類型:
typeof 9
"number"
複製代碼
boolean
類型:
typeof false
"boolean"
複製代碼
undefined
類型:
typeof undefined
"undefined"
複製代碼
null
類型
typeof null
"object"
複製代碼
這個結果有點奇怪。null
看起來像一個對象,但實際上它是JS的一個歷史錯誤,自該語言誕生以來就一直存在。因爲這些緣由,JS 一直名聲不佳。null
只是其中的一例。另外,一種類型和另外一種類型之間的轉換有一些奇怪的規則。
先給你們介紹一下背景。各位先用 Python 作一個例子。Python 中的如下指令
'hello' + 89
複製代碼
這樣會獲得一個明確的錯誤:
TypeError: can only concatenate str (not "int") to str
複製代碼
在 JS 中徹底沒有問題:
'hello' + 89
複製代碼
結果:
"hello89"
複製代碼
更加奇怪是直接加一個數組:
'hello' + []
複製代碼
結果:
'hello'
複製代碼
再來:
'hello' + [89]
複製代碼
結果:
"hello89"
複製代碼
看起來這種轉換背後有某種邏輯,甚至還能夠有更加複雜的數組結構:
'hello' + [89, 150.156, 'mike']
複製代碼
結果:
"hello89,150.156,mike"
複製代碼
這兩行 JS 足以讓 Java 開發人員望而卻步。可是 JS 中的這種行爲是100%
故意的。所以,有必要研究一下 JS 中隱式轉換(也稱爲類型強制轉換)。
一些編程語言有一個稱爲類型轉換的概念,這意味着:若是我們想將一個類型轉換成另外一種類型,那麼必須使轉換明確。在 JS 中也有提供這種方法。考慮如下示例
var greet = "Hello";
var year = 89;
複製代碼
若是想進行顯式轉換,能夠在代碼中用 toString()
方法:
var greet = "Hello";
var year = 89;
var yearString = year.toString()
複製代碼
或者使用 String
:
var greet = "Hello";
var year = 89;
var yearString = String(year)
複製代碼
String
是JS 內置對象的一部分,它反映了一些基本類型:String
、Number
、Boolean
和Object
。這些內置組件可用於類型之間的轉換。轉換後,我們能夠拼接兩個變量
greet + yearString;
複製代碼
可是除了這種顯式轉換以外,在 JS 中還有一種微妙的機制,稱爲隱式轉換,由 JS 引擎提供。
'hello' + 89
複製代碼
結果:
"hello89"
複製代碼
可是這種轉換背後的邏輯是什麼? 你可能會驚訝地發現,若是 JS 中的加法運算符+
中的一個是字符串,則會自動將兩個操做數中的任何一個轉換爲字符串!
更使人驚訝的是,這個規則在ECMAScript規範中已經固定下來了。第11.6.1節定義了加法運算符的行爲,在這裏總結一下:
加法運算符(+) 若是 x 是字符串或者 y 是字符串那麼返回 ToString(x) 後面跟 ToString(y)
這種把戲只對數字有效嗎? 不是,數組和對象同樣的,跑不掉:
'hello' + [89, 150.156, 'mike']
複製代碼
結果:
"hello89,150.156,mike"
複製代碼
對象怎樣:
'hello' + { name: "Jacopo" }
複製代碼
結果:
"hello[object Object]"
複製代碼
爲了弄清,咋肥事,能夠經過將對象轉換爲字符串來進行快速測試:
String({ name: "Jacopo" })
複製代碼
結果:
"[object, Object]"
複製代碼
但還有另外一個問題:乘法、除法和減法的狀況又是腫麼樣的?
我們看到加法運算符在至少一個操做數是字符串時,是如何將操做數轉換成字符串。可是其餘的算術運算符呢?
操做符 | 描述 |
---|---|
+ | 加 |
++ | 自增 |
* | 乘 |
** | 指數 (es6) |
- | 減 |
-- | 自減 |
/ | 除 |
% | 取餘 |
若是對不是數字的類型使用其中一個操做符(+除外
),那麼就獲得了一種特殊類型的 : NaN
89 ** "alex"
複製代碼
結果:
NaN
複製代碼
NaN
表示不是數字,任何失敗的算術運算,以下面的代碼所示:
var obj = { name: "Jacopo" } % 508897
複製代碼
結果:
console.log(obj)
NaN
複製代碼
注意與NaN
結合的 typeof
。這個代碼看起來沒問題:
typeof 9 / "alex"
NaN
複製代碼
那下面呢?
var strange = 9 / "alex"
複製代碼
再使用 typeof
:
typeof strange
"number"
複製代碼
當 NaN
被分配給一個變量時,它就變成了number
,這就引出了一個新問題。我如何檢查一些變量是不是 NaN
? ES6 中有一個名爲 isNaN()
的新方法:
var strange = 9 / "alex"
isNaN(strange)
true
複製代碼
接着來看看 JS 中的比較運算符,它們和算術運算符同樣奇怪。
JS 中有兩大類比較運算符。首先是所說的**「弱比較」**。它是一個抽象的比較運算符(雙等號):==
。而後還有一個「強比較」:===
,又名 嚴格比較運算符。他倆兄弟的行爲方式不同,來看看一些例子。
首先,若是我們用兩個操做符比較兩個字符串,倆兄弟獲得一致的結果:
"hello" == "hello"
true
"hello" === "hello"
true
複製代碼
看起來很 nice,如今來比較兩種不一樣的類型,數字和字符串。
首先是「強比較」
"1" === 1
false
複製代碼
很明顯,字符串 1 等於數字 1。弱比較又是怎麼樣?
"1" == 1
true
複製代碼
true
表示這兩個值相等。這種行爲與我們前面看到的隱式轉換有關。原來,抽象比較操做符會在比較類型以前自動轉換類型。這是一個摘要:
抽象等式比較算法 比較
x == y
是這樣執行的:若是x
是字符串,y
是數字,返回比較的結果ToNumber(x) == y
說白了就是:若是第一個操做數是字符串,第二個操做數是數字,那麼將第一個操做數轉換爲數字。
有趣的是,JS 規範中充滿了這些瘋狂的規則,我強烈建議對此進行更深刻的研究。固然如今都建議使用強比較。
嚴格相等比較的規範指出,在將值與===
進行比較以前,不會進行自動轉換。在代碼中使用嚴格的相等比較能夠避免愚蠢的錯誤。
我們已經看到了 JS 的構建塊:String
、Number
、Boolean
、Null、Undefined
、Object
和Symbol
。它們都是大寫的,這種風格甚至出如今ECMAScript規範中。可是除了這些基本類型以外,還有一些鏡像原語的雙胞胎:內置對象。例如,String
類型有一個等效的 String
,它以兩種方式使用。若是像函數那樣調用(經過傳遞參數),它會將任何值轉換成字符串:
var someValue = 555;
String(someValue);
"555"
複製代碼
若是使用 String
做爲 new
的構造函數,那麼結果就是String
類型的對象
var someValue = 555;
var newString = new String(someValue);
複製代碼
這種方式值得在控制檯中查看對象,看看它與「普通」字符串有何不一樣
可使用 typeof
來確認它確實是一個對象:
typeof newString
"object"
複製代碼
基本類型的 Number 也有一個內置對象 Number
,它能夠(幾乎)將任何值轉換爲數字:
var someValue = "555";
Number(someValue);
555;
複製代碼
我說的幾乎是由於在試圖轉換無效的「數字」時獲得 NaN
var notValidNumber = "aa555";
Number(notValidNumber);
NaN;
複製代碼
在構造函數形式Number
中使用時,將返回number
類型的新對象:
var someValue = "555";
new Number(someValue);
Number {555}
複製代碼
內置對象 Boolean
以將任何值轉換成布爾值:
var convertMe = 'alex';
Boolean(convertMe)
true
複製代碼
用構造函數的方式會返回一個對象:
var convertMe = 'alex';
typeof new Boolean(convertMe)
"object"
複製代碼
內置的 Object
行爲也同樣:
Object('hello'); // String {"hello"}
Object(1); // Number{1}
複製代碼
若是在沒有參數的狀況下調用,它將返回一個空對象
Object()
{}
複製代碼
若是做爲構造函數調用,則返回一個新對象
new Object({
name: "Alex",
age: 33
});
{name: "Alex", age: 33}
複製代碼
此時,你可能會問本身:何時可使用內置對象,何時應該使用基本類型初始化值? 根據經驗,當你只須要一個簡單的類型時,應該避免構造函數調用:
// 不要這麼用
var bool = new Boolean("alex");
var str = new String('hi');
var num = new Number(33);
var strObj = new Object('hello')
複製代碼
除了不實用以外,這種形式還會帶來性能損失,由於這種方式每次都會建立一個新對象。 最後但一樣重要的是,當我們想要一個簡單的字符串或數字時,建立一個對象是沒有意義的。因此下面的形式是首選的
// ok 的
var bool = true
var str = 'hi';
var num = 33;
var obj = { name: "Alex", age: 33 };
複製代碼
當須要轉換某些內容時,能夠像使用函數同樣使用 Boolean
、String
和 Number
,。
JS 中有七個構建塊,即 String
、Number
、Boolean
、Null
、Undefined
、Object
和Symbol
,這些也稱爲基本類型。
JS 開發人員可使用算術和比較操做符操做這些類型。可是我們須要特別注意加法運算符+
和抽象比較運算符 ==
,它們本質上傾向於在類型之間進行轉換。
這種 JS 中的隱式轉換稱爲類型強制轉換,並在ECMAScript規範中定義。建議在代碼中始終使用嚴格的比較操做符===
代替 ==
。
做爲一種最佳實踐,當你打算在一種類型和另外一種類型之間進行轉換時,必定要弄清楚彼此之間的類型。爲此,JS 有一堆內建對象,它們基本類型的一種映射:String
、Number
、Boolean
。這些內置函數可用於顯式地在不一樣類型之間進行轉換。
44 - "alex"
的輸出結果是?
44 + "alex"
的輸出結果是?爲啥?
"alex" + { name: "Alex" }
的輸出結果是 ?
["alex"] == "alex" 輸出結果是啥?爲何呢?
undefined == null
輸出結果是啥?爲何呢?
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
阿里雲最近在作活動,低至2折,有興趣能夠看看:promotion.aliyun.com/ntms/yunpar…
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。
每次整理文章,通常都到2點才睡覺,一週4次左右,挺苦的,還望支持,給點鼓勵