JavaScript中有其中內置類型javascript
typeof null === "object"; //true typeof undefined === "undefined"; //true typeof true === "boolean"; //true typeof 42 === "number"; //true typeof "42" === "string"; //true typeof {life: 42} === "object"; //true typeof Symbol() === "symbol"; //true
以上除了null類型以外,其餘的六種類型均有同名的字符串值與之對應,而且null是基本類型中惟一的一個假值類型,typeof
對他的返回值是object
除了上述的內置類型,還有一種狀況java
typeof function a(){} === 'function'; //true
如此看來,function(函數)也是javascript中的一個內置類型,可是經過instanceof
這個屬性能夠發現,實際上它是object的一個子類型,具體來講,能夠把函數看成可調用對象,他是一個內部屬性[[call]], 該屬性使其能夠被調用,既然是對象,那函數也有本身的屬性,函數對象的length屬性是其聲明的參數的個數數組
function a(b, c){} a.length; //2
在javascript中,變量可能包含兩種不一樣數據類型的值,基本類型值和引用類型值。
基本類型值指的是簡單的數據段: 老是經過值複製的方式來賦值/傳遞,包括null,undefined,字符串,數字,布爾和ES6中的symbol
引用類型值指那些可能有多個值構成的對象(包括數組和封裝對象和函數),則老是經過引用複製的方式來賦值/傳遞
值複製:從一個變量像另外一個變量複製基本類型的值,會在變量對象上建立一個新值,而後將該值複製到爲新變量分配的位置上,此後這兩個變量能夠參與任何操做不會有相互影響。函數
var a = 2; var b = a; //b是a的值的一個副本 b++ a; //2 b; //3
引用複製: 從一個變量像另外一個變量複製引用類型的值時,一樣將會存儲在變量對象中的值複製一份放到新分配的空間裏中。不一樣的是,這個值的複本其實是一個指針,而這個指針指向存儲在堆中的一個對象。,兩個變量實際上將引用同一個對象,其中改變其中一個變量,就會改變另外一個變量工具
var c = [1,2,3]; var d = c; d.push(4); c; //[1,2,3,4] d; //[1,2,3,4]
並且因爲引用指向的是值自己而非變量,因此一個引用沒法更改另外一個引用的指向prototype
var a = [1,2,3] var b = a; a; //[1,2,3] b; //[1,2,3] b = [4,5,6] //b指向值[4,5,6] a; //[1,2,3] b; //[4,5,6]
b = [4,5,6]並不影響a指向值[1,2,3],除非b不是指向數組的引用,而是指向函數a的指針,但在javascript中不存在這樣的狀況
函數傳參: 在javascript中全部函數的參數都是按值傳遞的,也就是說,把函數外部的值複製給函數內部的參數。即在向參數傳遞基本類型的值時,被傳遞的值會被複制給一個局部變量,在向參數傳遞引用類型的值時,會將這個值在內存中的地址複製給一個局部變量。指針
function foo(x){ x.push(4); x; //[1,2,3,4]; x = [4,5,6]; x.push(7); x; //[4,5,6,7] } var a = [1,2,3]; foo(a); a; // 是[1,2,3,4]而不是[4,5,6,7];
咱們在向函數傳參的時候,其實是把引用a的複本賦值給x了,而a仍指向[1,2,3]。code
字符串和數組很類似,都有length屬性以及indexOf()和concat()方法,在javascript中字符串是不可變的,字符串的成員函數不會改變其原始值,而是建立並返回一個新的字符串。對象
var a = foo; var b = a.toUpperCase(); a === b //false a; //"foo"; b; //"FOO"
許多數組函數用來處理字符串很方便,雖然字符串沒有這些函數,但能夠經過借用數組的非變動方法來處理字符串;ip
var a = foo; a.join; //undefined a.map; //undefined var b = Array.prototype.join.call(a, '-'); var c = Array.prototype.map.call(a, function(v){ return v.toUpperCase() + "."; }).join(""); b; //"f-o-o" c; //"F.O.O"
例如常見的字符串反轉問題
var a = "foo"; var b = Array.prototype.reverse.call(a); b; //"oof"; //也能夠是 var c = a.split("").resverse().join(""); c; //"oof"
上述方法對於包含複雜字符(Unicode, 星號, 多字節字符等)的字符串不適用,須要特殊的庫來實現
javascript只有一種數值類型: number(數字), 包括整數和帶小數的十進制數,javascript中沒有真正意義上的整數,javascript中的整數就是沒有小數的十進制數,因此42.0
等同於整數42
。 而數字類型常見的問題就是
0.1 + 0.2 === 0.3 //false
這是由於二進制浮點數中的0.1和0.2並非十分精確,他們相加的結果並不是恰好等於0.3,而是一個比較接近的數字,因此判斷結果爲false。
對於這種狀況,最多見的方法是設置一個偏差範圍值,從ES6開始,該值定義在Number.EPSILON中咱們能夠直接拿來用。
if(!Number.EPSILON){ Number.EPSILON = Math.pow(2, -52); } function foo(n1, n2){ return Math.abs(n1 - n2) < Number.EPSILON } var a = 0.1 + 0.2 var b = 0.3 foo(a, b); //true
1.不是數字的數字
若是數學運算的操做數不是數字類型(或者沒法解析常規的十進制或十六進制數字),就沒法返回一個有效的數字,這種狀況下返回值爲NaN。例如
var a = 2 / "foo"; //NaN typeof a === "number"; // true
NaN是一個警惕值,用於指出數字類型中的錯誤狀況,即執行數學運算沒有成功,這是失敗後返回的結果。他是一個特殊值,她和自身不相等
var a = 2 / "foo" a === NaN; //false
咱們能夠用內建的全局工具函數isNaN(..)來判斷一個值是不是NaN,可是這種方法有嚴重缺陷
var a = 2 / "foo"; var b = foo; window.isNaN(a); //true; window.isNaN(b); //true;
對於這種現象,ES6開始使用工具函數Number.isNaN(..)
if(!Number.isNaN){ Number.isNaN = function(n){ return n !== n; } } var a = 2 / "foo"; var b = foo; Number.isNaN(a); //true Number.isNaN(b); //false
2.無窮數
在javascript中1 / 0 和 - 1 / 0
這種操做會返回Infinity
或者-Infinity
javascript使用有限數字表示法,因此javascript的運算結果容易溢出,此時結果爲Infinity
或者-Infinity
。
3.零值
javascript中有一個常規的0
,還有一個-0
var a = 0 / -3; // -0 var b = 0 * -3; // -0
對-0
進行字符串化會返回0
var a = 0 / -3; a.toString(); //"0"; a + ""; //"0"
將其從字符串轉換成數字,獲得的結果是正確的
+ "-0"; //"0" Number("-0"); //"0"
javascript中有兩個關鍵詞true和false,表明真和假,其餘數據類型的值能夠強制轉換爲布爾值。在javascript中假值有這些:undefined
,null
,false
,+0, -0和NaN
,""
。除了這些值以外其餘是真值。