我喜歡JavaScript.它是一門集強大與靈活於一身的語言,固然前提是你得知道如何去正確的使用它.一旦你真正掌握了JavaScript,你幾乎能夠用它來作任何事情,並且能作的既快又好.javascript
若是你認爲JavaScript太簡單或者過低級,那麼你已經掉入了一個陷阱.而且你會發現有不少人已經掉入了這樣的陷阱中了.這些所謂的JavaScript開發者也許會告訴你,一些其餘的語言 「X」 更好.他們甚至會說,若是有一個將能將X語言轉換爲JavaScript的系統,那就太好了.想要逃出這個陷阱一直到真正的掌握JavaScript須要付出不少的努力和貢獻.相信我,由於從1997年開始,我就已經在學習JavaScript了.html
我是經過學習官方標準文檔掌握了JavaScript的全部高級知識,因此你也能夠經過這種方法來掌握完整的語言知識.若是你的職稱中包含了「JavaScript開發者」,那麼你應該這樣作.java
在本篇博客中,我將會給出一個短小的JavaScript代碼片斷,而後讓你給出這段代碼的正確輸出.若是你是一個JavaScript開發者,你會發現這樣的題目真是太簡單了.若是你仍然處在學習這門語言的過程當中,你可能會遇到一些困難,不過你能夠好好讀一下代碼下面的解釋部分.web
下面的JavaScript代碼顯示了一個彈出框.彈出框中顯示什麼?編程
1
2
3
|
var
five = 5;
five.three = 3;
alert(five + five.three);
|
跳到本篇文章的最後查看正確的答案.接下來是爲何會有這樣的結果的解釋.數組
在JavaScript中,一共有六種數據類型: Object, Number, String, Boolean, Null, 以及 Undefined.瀏覽器
對象(Objects)類型包含了數組(arrays), 函數(functions),以及其餘的通常對象.數字(Numbers)類型能夠是整型(integers)或者浮點數(floating point)類型以及特殊值NaN和Infinity. 字符串(Strings)類型包含了空字符串, 」". 布爾值(Booleans)類型只有兩個值:true和false.最後兩個基本數據類型有點特殊:Null類型只有一個值:null, Undefined類型只有一個值:undefined.全部Object除外的類型都稱之爲「原始值(primitive)」.JavaScript變量的類型不是在定義的時候明確指定的,仍是在腳本運行的時候自動推斷出來的.在上面的代碼中,名爲five的變量是Number類型的,由於它被賦值了一個Number字面量5.ruby
和其餘的計算機編程語言相似,JavaScript也會隱式的將某個值的類型轉換成適合對該值進行操做的運算符的類型.和其餘語言不一樣的是, JavaScript會很是積極地作這些轉換.好比表達式」5″ – 「3″的運算結果是數字2,由於減號運算符會把兩邊的操做數所有轉換爲數字再進行運算.若是一個操做數不能被轉換爲數字,則會使用NaN (「Not a Number」)來替代.例如表達式」5″ – 「Fred」會被隱式的轉換爲5 – NaN,則運算結果也會是NaN.編程語言
一套完整的隱式轉換規則並非十分複雜,你只須要知道每一個操做符須要什麼類型的操做數.函數
任意值轉換爲原始值遵循這樣的規則「任意值轉換爲原始值」. 其中對象到原始值的轉換比較複雜:若是操做數的類型必須是Number類型,這就意味着JavaScript引擎會調用對象的valueOf()方法,若是返回的結果仍然不是一個原始值,則會調用對象的toString()方法轉換成一個String類型的值.若是操做數的類型必須是String類型,則會首先調用對象的toString()方法,若是返回的結果不是一個原始值,再調用對象的valueOf()方法.無論那種狀況,若是最終的轉換結果仍然不是一個原始值,則拋出異常.
若是操做數的類型必須是一個數字,但該操做數的實際類型是:
Object:
該值首先被轉換成原始值,若是轉換的結果不是一個數字,則會進入下面的轉換分支.
String:
字符串類型的值會按照一般的JavaScript規則轉換成數字類型
Boolean:
若是值爲true,轉換爲1,不然轉換爲0
Null:
0
Undefined:
NaN
若是操做數的類型必須是一個字符串,但該操做數的實際類型是:
Object:
該值首先被轉換成原始值,若是轉換的結果不是一個字符串,則會進入下面的轉換分支.
Number:
數字直接轉爲字符串, 好比 」123″ or 」12.34″
Boolean:
轉爲」true」或」false」
Null:
「null」
Undefined:
「undefined」
若是操做數的類型必須是一個布爾值,但該操做數的實際類型是:
Object:
true
Number:
若是值爲0,則轉爲false,不然轉爲true (譯者注:NaN也會轉爲false)
String:
若是值爲一個空字符串」",則轉爲false,不然轉爲true
Null:
false
Undefined:
false
若是操做數的類型必須是一個對象值,但該操做數的實際類型是:
Number:
使用包裝對象類型Number來包裝原始值,new Number(value)
String:
使用包裝對象類型String來包裝原始值,new String(value)
Boolean:
使用包裝對象類型Boolean來包裝原始值,new Boolean(value)
Null:
拋出異常
Undefined:
拋出異常
如今全部的轉換規則已經很清晰了,讓咱們回到最初的例子中.
1
2
3
|
var
five = 5;
five.three = 3;
alert(five + five.three);
|
正如咱們前面提到的,第一行代碼建立了一個名爲five,類型爲Number的變量.
當用屬性訪問符做用在變量five上時,它的值會轉換爲Object類型.這種操做稱之爲「包裝」,而且依賴於Number構造函數,該構造函數會產生一個對象,而不是一個原始值.第二行代碼實際上等同於下面的代碼:
1
|
(
new
Number(five)).three=3;
|
正如你看到的,咱們並無將新生成的Number對象的引用保存到一個變量中.在該表達式運行事後,被添加three屬性的這個對象會被丟棄.而five變量的值沒有任何變化.
第三行代碼中的表達式five.three會再一次建立一個Number對象.這個新的對象並無three屬性,因此返回了特殊值undefined.結果等同於:
1
|
alert(5+undefined);
|
加法運算符會把兩邊的操做數所有轉換爲數字.在本例中,undefined會被轉換爲NaN,也就成了:
1
|
alert(5+NaN);
|
這也就解釋了爲何最後的彈出框中僅僅顯示了一個NaN.
(譯者注:還差最後一步隱式轉換,在進行alert()的時候,NaN會被自動轉換爲」NaN」)
評論:
jerone:
你這篇文章所講的內容只是JavaScript的一部分,確切的說只包含了ECMAScript.除了這些,JavaScript還包含了DOM,也就是說還有Node, Element, HTMLElement等更多的數據類型.
做者回復:
Node, Element 以及 HTMLElement 都不是數據類型,就像Array, Date 和 RegExp同樣,他們都屬於對象(Object)類型.
Marcus Pope:
我認爲應該指出正確的編寫方式,下面的代碼纔可以正常運行
1234var
five =
new
Number(5);
alert(five);
//5
five.three = 3;
alert(five + five.three);
//8
我還認爲最好應該用「number」來指代數字原始值,而用「Number」來指代數字類型的包裝對象,這樣才能減小讀者的困惑.這也是在JavaScript中使用typeof操做符來查看這些值的內部類屬性時顯示的字符串.(譯者注:這裏指的是typeof 5 === 「number」)
ACRESTAN:
是啊,這篇文章很讓人困惑,就是由於做者使用了大寫字母開頭的類型字符串來描述原始值…
好比這句 「the first line creates a variable called five whose type is Number」,這是不對的!由於你的代碼就證實了這一點.
metadings:
還有第七種數據類型,JavaScript中最重要的類型:函數(Function).在JavaScript中,使用函數能夠建立新的對象,因此原始值類型和函數類型仍是有區別的.
123456789var
Project =
function
() { };
// Project instanceof Function === true
// Project instanceof Object === true
// (typeof Project === 'function') === true
var
o =
new
Project();
// o instanceof Project === true
// o instanceof Object === true
// (typeof Project === 'object') === true
請仔細閱讀這個連接http://metadea.de/V/,看看我是怎麼寫出真正的JavaScript類函數的.(譯者注:還有一句沒翻譯,看不明白,覺的這我的在扯蛋.)
做者回復:
很顯然函數在JavaScript中很是重要,值得用單獨的文章來說解它,但函數不是另一種數據類型.函數只是一種特殊的對象.雖然特殊,但還是對象.
由許許多多不一樣的構造函數建立的對象們都繼承了同一個類型:Object.這很容易檢測到:若是Object(a) === a,則a是一個對象類型,而不是其餘原始值類型.
ulu:
這篇文章正好進一步證實了JavaScript不僅是一個最強大的語言,同時也是最使人困惑的語言.應該不惜一切代價避免使用它.總有一天,會有一個更人性化的語言集成在全部的主流瀏覽器中,我但願在我有生之年可以遇上.
做者回復:
當你手中拿着一把錘子時,全部事物看上去都像釘子.當你認爲JavaScript很讓人迷惑時,任何特性都能成爲你的證據.
Dave Chapman :
這種類型的編碼錯誤正是咱們爲何須要一個更好的可以在咱們碼字的同時,在運行代碼以前進行語法檢查的IDE的緣由.好比.在closure compiler中運行例子中的代碼會產生以下的警告信息:
「JSC_INEXISTENT_PROPERTY: Property three never defined on Number at line 4 character 13:
alert(five + five.three);」
(譯者注:closure compiler是谷歌的代碼壓縮器或者叫編譯器.https://developers.google.com/closure/compiler/)
Sponge Bob:
我推薦你看一下這個視頻: https://www.destroyallsoftware.com/talks/wat/
Enjoy
(譯者注:這個視頻主要吐槽了ruby和JavaScript的詭異用法,這裏有中文字幕版 http://v.ku6.com/show/nhlYYNrbd5d62ASt-aaDrA…html)
simonleung :
一個數字能夠是「object」類型的,也能夠是「number」類型的.
當用在條件語句中或者其餘須要轉換爲布爾值的地方,這兩種類型的數字會產生不一樣的結果,例如.
Number(0)會獲得true,由於Number(0)是一個對象,而0顯然會獲得false.
(譯者注:這裏他說錯了.Number做爲函數只是一個類型轉換函數,返回的仍然是原始值,只有用new Number(0),Number纔算是一個構造函數,返回的纔是對象)
另一個,在null上進行typeof操做,返回」object」,但它不是真正的對象,null是假值,會被轉換爲false.
英文原文:JavaScript: Types 編譯:@紫雲妃