數據類型劃分 javascript
javascript中定義了6中基本數據類型(原始值類型),和一種複雜數據類型(引用類型),所謂複雜類型,其本質是由無序的名值對(key:value)組成的。 java
基本數據類型:程序員
複雜數據類型es6
原始值引用值 數組
上面提到了原始值和引用類型,可能有些人對於引用類型很熟悉,可是原始值卻很陌生實際上,在ECMAScript中,變量能夠存放兩種類型的值,即原始值和引用值。瀏覽器
原始值(primitive value)數據結構
原始值是固定而簡單的值,是存放在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。
引用值(reference value)函數
引用值則是比較大的對象,存放在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(pointer),指向存儲對象的內存處。全部引用類型都集成自Object。
之因此說原始值是固定的,緣由是當咱們對原始值進行一些操做時結果返回的都是一個新的副本,可是對引用值操做時可能更改原值。測試
var str = 'asdfghjkl'; var obj = {name:1,age:2}; var str2 = str; var obj2 = obj; str2 = 'lkjhgfdsa'; obj2.name= 3; console.log(str,str2,obj,obj2) //asdfghjkl lkjhgfdsa {name: 3, age: 2} {name: 3, age: 2} obj == obj2 //true
經過以上代碼能夠明確看出字符串是按值傳遞的,在賦值時會新建存儲空間,將str 和 str2 存放在不一樣的內存空間內,對象是按引用傳遞的,obj = obj2時沒有新建堆內存空間,而是在棧內存中存放標識符和值的引用地址,引用地址與obj的棧值相同,指向堆內存中的存儲空間。spa
同時能夠看到obj == obj2 返回true,這是爲何?
var obj3 = {name:3,age:2} obj == obj3 //false
obj3 與 obj 的屬性和屬性值是同樣的,可是 obj == obj3 卻返回false, obj == obj2 返回true, 這說明引用類型在判斷相等的時候比較的是指針,即指向對內存的地址。
提到原始值 引用值 內存地址等詞,就不得不提數據的存儲空間
堆棧
以前說到基本類型存儲在棧內存中,複雜類型存儲在堆內存中,那麼什麼是棧,什麼是堆?
這裏說的堆和棧並非一種數據結構,而是指存儲空間,JVM內存劃分爲:寄存器,本地方法區,方法區,堆內存,棧內存,咱們說的堆棧就是這裏的堆內存 和 棧內存。
棧區(stack)
由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。
堆區(heap)
通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。
堆棧區別
1.棧內存存儲的是局部變量而堆內存存儲的是實體;
2.棧內存的更新速度要快於堆內存,由於局部變量的生命週期很短;
3.棧內存存放的變量生命週期一旦結束就會被釋放,而堆內存存放的實體會被垃圾回收機制不定時的回收,前提是沒有任何引用。
關於堆和棧的內存空間,這裏只是簡單提起,強調指內存空間並不是數據結構。
不一樣數據類型的存儲區別
var a = undefined; var b = null; var c = 'asdfg'; var d = 123; var e = true; var f = [1,2]; var g = {name:1,age:2}; var h = g;
下圖解釋不一樣每一種類型的存儲方式
上圖體現出每種數據類型在內存中的存儲方式:
數據類型的判斷有多種方式,下面簡單介紹
typeof
typeof 用於檢測數據的類型,返回值有
var u ,a = 'asdf',b = 1,c = true,d = {},e = null,f = function(){} typeof a; // string typeof b; //number typeof c; //boolean typeof u; //undefined typeof d; //object typeof e; //object typeof f; //function typeof a == 'string' //true typeof a == String //false
以上代碼能夠看出
instanceof
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
因爲js可在多個frame之間交互,可是每一個frame有本身的全局環境,因此不一樣frame和窗口之間Array是不一樣的,因此沒法用 a 環境下的數組去判斷是不是 b 環境下的Array對象的實例
var a = 'asdffgg'; var b = 1; var c = new String('aaaa'); var arr = [1,2]; var date = new Date(); a instanceof String //false 思考:爲何是false? b instanceof Number //false c instanceof Number //true 思考:a 和 c 一樣是字符串結果卻不同 arr instanceof Array //true arr instanceof Object //true 思考:爲何 Array 和 Object都是true? date instanceof Date //true date instanceof Object //true typeof a //string 字面量的形式 返回基本類型 string typeof c //object new 一個String的實例 返回複雜類型 object
經過以上的代碼段體現出如下特色和弊端:
數組便是Array的實例,又是Object的實例的緣由詳解:
因爲對象之間存在繼承關係,因此instanceof 可以判斷出 [ ].__proto__ 指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最終 Object.prototype.__proto__ 指向了null,標誌着原型鏈的結束。這裏關於原型鏈的知識點不細說
因此沒法判斷實例對象具體是Object的哪種類型。
constructor
constructor 屬性返回對建立此對象的構造函數的引用。
當定義一個函數Fn的時候,JS引擎會爲其添加一個原型prototype,併爲原型添加一個constructor屬性,將其指向Fn的引用
實例f的constructor是指向其構造函數Fn的,因此經過constructor咱們能夠判斷其構造函數是誰,從而間接的判斷對象的具體類型
可是因爲constructor在實現繼承的時候能夠被更改,實質更改是因爲子類繼承父類的時候可能重寫了子類的原型prototype,所以使子類的prototype上的constructor發生變化,所以類型判斷可能不許確
undefined 和 null沒有constructor屬性
toString
Object.prototype.toString 方法能夠返回對象的內部屬性[[Class]],格式爲[object,Xxxx],其中Xxxx爲具體的類型
Object.prototype.toString.call('') //"[object String]" Object.prototype.toString.call([1]) //"[object Array]" Object.prototype.toString.call(new Date) //"[object Date]"
爲何不調用對象的toString方法,而是經過call調用Object.prototype.toString?
'11'.toString() //"11" [1,2].toString() //"1,2" new Date().toString() //"Fri Jun 22 2018 14:44:52 GMT+0800 (CST)"
能夠看到字符串輸出的是自己,數組輸出的是「,」連接的數組字符串,時間類型輸出的時間字符串,都不是內部屬性[[Class]],緣由是實例的構造函數重寫了toString方法,因此要吊用Object對象的原型傷的toString方法。
轉數值類型
顯示轉換:Number() parseInt() parseFloat()
向Number 轉換規則 ToNumber
var a = {a:1} Number(11) //11 Number('123') //123 Number(true) //1 Number(null) //0 Number(undefined) //NaN Number('') //0 Number(a) //NaN a.valueOf返回 {a:1},a.toString 返回 '[object,Object]',字符串轉數值 返回NaN
parseInt parseFloat 這裏不細說
隱式轉換:操做符
轉String類型
顯示轉換 toString() String()
toString:返回相應的字符串表現,
向字符串轉換規則 ToString
var a = {a:1};var b = 11;var c = '11'; var e = '[1,3]';var d = true a.toString() //'[object,Object]' b.toString() //'11' c.toString() //'11' d.toString() //'true' e.toString() //'1,3'
隱式轉換同+操做符數值轉化
轉Boolean類型
顯示轉換:Boolean()
向Boolean轉換規則:
數字0,''空字符串,null,undefined,NaN轉爲false,其他轉爲true
隱式轉換操做符 if
什麼是隱式轉換?
隱式轉換與執行環境和操做符相關,當前操做指望某種值的時候,就會發生隱式轉換,實際上面提到的具體規則點就是隱式轉換的過程。
本地對象:不依賴於宿主環境的對象
Object Array Date Function RegExp String Boolean Number
單體內置對象:由ECMAScript實現提供的,不依賴於宿主環境的對象,這些對象在ECMAScript程序執行前就已經存在了
Global(全部不屬於其餘任何對象的屬性和方法都屬於Global,全局變量,方法),Math,一些數學公式和計算方法
宿主對象:由ECMAScript實現的宿主環境提供的對象,能夠理解爲:瀏覽器提供的對象。全部的BOM和DOM都是宿主對象 , Window
javascript 高級程序設計
堆和棧的概念和區別
全面解析js中的數據類型與類型轉換