數據類型
首先明確ECMAscript中的數據類型分為兩種贝或,基本類型(7鐘)和引用類型(1種)
基本類型:(又稱簡單數據類型)7種,未定義類型(Undefined)试溯,對空類型(Null)的畴,布爾類型(Boolean),數字類型(Number)节仿,字符串(String),符號類型(Symbol)掉蔬,BigInt廊宪;都是按值訪問的,即將一個基本類型的數據賦值給另外一個變量女轿,是將元數據拷貝一份賦值的箭启,兩變量之間互不影響。
引用類型:引用類型的值(對象)是應用類型的一個實例蛉迹,在ECMAScript中傅寡,應用類型是一種數據結構,用于將數據和功能綁定在一起。它也常被稱為類荐操,雖然這種稱呼并不妥當芜抒。引用類型有時候也被稱為對象定義,因為它描述的是一類對象所具有的屬性和方法托启。 除過對象類型都是引用類型宅倒,即保存在內存中的對象,按引用訪問屯耸,即將一個引用類型的地址賦值給另一個變量拐迁,這兩個變量的值是相同的相當于指針,都指向同一塊內存空間疗绣, 操作該變量等于操作該變量指向的內存空間的值唠亚,當其中一個變量改變時,原變量也會隨之改變持痰。如Object灶搜,Function,Date工窍,RegExp割卖,Array, Map患雏,Set........但是Object是引用變量的本質
小可耐們注意啦~~~ 引用類型與基本包裝類型的主要區(qū)別就是對象的生存期鹏溯。使用new操作符創(chuàng)建的引用類型的實例,在執(zhí)行流離開當前作用域之前都一直保存在內存中淹仑。而自動創(chuàng)建的基本包裝類型的對象丙挽,則只存在于一行代碼的執(zhí)行瞬間,然后立即被銷毀匀借。這意味著我們不能在運行時為基本包裝類型添加屬性和方法颜阐。
類型對比
基本類型主要是把值存儲在棧內存中;基礎類型賦值會重新創(chuàng)建一個基礎值;它們的值直接存儲在變量訪問的位置吓肋。這是因為這些原始類型占據的空間是固定的凳怨,所以可將他們存儲在較小的內存區(qū)域 – 棧中。這樣存儲便于迅速查尋變量的值是鬼。
引用類型把值存儲在堆內存中肤舞,堆內存的地址存儲在棧內存中;引用類型賦值只是把堆內存的地址賦值給新變量.也就是說均蜜,存儲在變量處的值是一個指針(point)李剖,指向存儲對象的內存地址。這是因為:引用值的大小會改變囤耳,所以不能把它放在棧中篙顺,否則會降低變量查尋的速度偶芍。相反,放在變量的椢堪玻空間中的值是該對象存儲在堆中的地址。地址的大小是固定的聪铺,所以把它存儲在棧中對變量性能無任何負面影響化焕。
堆和棧有啥區(qū)別?
堆:堆為隊列優(yōu)先铃剔,先進先出(FIFO)撒桨,使用二級緩存,生命周期與虛擬機的GC算法有關(并不是引用為空就立即被GC)键兜,調用速度相對較低凤类。
棧:棧為先進后出(FILO),使用一級緩存普气,被調用時通常處于存儲空間中谜疤,調用后被立即釋放。
變量類型判斷
1.?使用typeof檢測
格式: typeof? 變量名
返回值:‘number’现诀,‘string’夷磕,‘boolean’,‘undefined’仔沿,‘symbol’, ‘object’坐桩,只有這六種返回類型,剩下均被檢測為‘object’封锉。
注意:而且typeof null === 'object' (JS 設計初的bug)
總結:簡單绵跷,對基礎類型檢測性能好;
2. 使用instanceof檢測
格式:變量名? instanceof? 數據類型
判斷參照對象(引用類型)的prototype屬性所指向的對象書否在被行測對象的原型鏈上成福,比如?
class Person{
? ? constructor(name) {
? ? ? ? this.name = name;
? ? }
?}
let p? = new Person("張三")碾局;
按照描述就是Person的prototype屬性所指向的原型對象是否存在于p的原型鏈中。
這種判斷方式奴艾,undefined和null被檢測為object
總結:能檢測出引用類型擦俐;不能檢測出基本類型;
3. 使用constructor檢測
constructor本來是原型鏈上的屬性握侧,指向構造函數蚯瞧,但是根據實例對象尋找屬性的順序,若實例對象上沒有實例屬性或方法品擎,就去原型鏈上尋找埋合,因此,實例對象也是能夠使用constructor屬性的萄传。
除了undefined和null甚颂,其他類型的變量均能使用constructor判斷出類型蜜猾,只不過使用constructor是不保險的,因為constructor屬性是可以被修改的振诬,會導致檢測出的結果不正確蹭睡。比如
function f() { }
f.prototype = new Array();
let ff = new f();
console.log(ff.constructor==true);? //true
使用instanceof和constructor,被判斷的array必須是當前頁面聲明的赶么,比如肩豁,一個頁面(父頁面)有一個框架,框架中引用了一個頁面(子頁面)辫呻,在子頁面中生命了一個Array清钥,并將其賦值給父頁面的一個變量,這是判斷該變量放闺,Array == object.constructor;會返回false祟昭;
原因:
1、array屬于引用型數據怖侦,在傳遞過程中篡悟,僅僅是引用地址的傳遞。
2匾寝、instanceof操作符是假定只有一個全局執(zhí)行環(huán)境恰力,如果網頁中包含多個框架,就會存在兩個以上不同的全局執(zhí)行環(huán)境旗吁,從而存在兩個以上不同版本的Array構造函數踩萎。如果你從一個框架向另一個框架傳入一個數組,那么傳入的數組與在第二個框架中原生創(chuàng)建的數組分別具有各自不同的構造函數很钓。
????為了解決這個問題香府,可以使用ES5中新增的方法 Array.isArray() 方法,這個方法的目的是最終確定某個值到底是不是數組码倦,而不管它是在哪個全局執(zhí)行環(huán)境中創(chuàng)建的企孩。
總結:基本能檢測所有的類型(除了null和undefined);constructor易被修改,不可靠
4.使用Object.prototype.toString.call()檢測
ECMA對Object.prototype.toString的解釋:
Object.prototype.toString( )
When the toString method is called, the following steps are taken:
1. Get the [[Class]] property of this object. 獲取對象的類名(對象類型)
2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.? 然后將[object? 獲取的類名] 組合
3. Return Result? ?返回組合結果
這種方式解決了instanceof存在的跨頁面問題袁稽,也解決了屬性檢測方式所存在的問題勿璃,nice~~~~
總結:所有類型都能檢測;寫起來比較繁瑣推汽,性能不如 typeof 好补疑;
例子
下面定義了常見的變量類型
let num = 7;? ? ? ? ?let num2 = new Number(7);
let str = "hello";? ? ? let str2 = new String("hello");
let boo = true;? ? ? ?let boo2 = new Boolean(true);
let arr = [1, 2, 3, 4];
let json = { name: "dingdang", age:20};
let func = function() {console.log("this is function")};
let und = undefined;
let nul = null;
let date = new Date();
let reg = /^[a-zA-Z]{5,20}$/;
let error = new Error();
let map = new Map([ ['name', '張三'], ['title', 'Author']]);
let set = new Set(['red', 2, 'blue', 4]);
運行結果見下圖:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?~~~~~聽大神說寫博客可以成為小仙女~~~~~