今天被問到一個(gè)關(guān)于js判斷對象的問題,先稍稍做個(gè)總結(jié)
檢測對象的方法
1.typeof操作符
typeof操作符對Function、String、Number、Undefined等類型的判斷毫無壓力,但是對Array對象就不起作用了.
因此總結(jié)為:typeof除了array和null判斷為object外,其它均可判斷。測試示例代碼如下:
console.log(typeof alert)/function
console.log(typeof 2)//number
console.log(typeof "2")//string
console.log(typeof demo)//undefined
const arr =["1","2","3"];
console.log(typeof arr)//object
console.log(typeof null)
2.instanceof操作符
這個(gè)操作符和JavaScript中面向?qū)ο笥悬c(diǎn)關(guān)系,了解這個(gè)就先得了解JavaScript中的面向?qū)ο?。因?yàn)檫@個(gè)操作符是檢測對象的原型鏈?zhǔn)欠裰赶驑?gòu)造函數(shù)的prototype對象的。
const arr = [1,2,3];
console.log(arr instanceof Array)
3.對象的constructor屬性
除了instanceof,每個(gè)對象還有constructor的屬性,利用它似乎也能進(jìn)行Array的判斷。
var arr = [1,2,3,1];
alert(arr.constructor === Array); // true
檢測數(shù)組類型方法
1.Object.prototype.toString
Object.prototype.toString的行為:首先,取得對象的一個(gè)內(nèi)部屬性[[Class]],然后依據(jù)這個(gè)屬性,返回一個(gè)類似于"[object Array]"的字符串作為結(jié)果(看過ECMA標(biāo)準(zhǔn)的應(yīng)該都知道,[[]]用來表示語言內(nèi)部用到的、外部不可直接訪問的屬性,稱為“內(nèi)部屬性”)。利用這 個(gè)方法,再配合call,我們可以取得任何對象的內(nèi)部屬性[[Class]],然后把類型檢測轉(zhuǎn)化為字符串比較,以達(dá)到我們的目的。
function isArrayFn (o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
var arr = [1,2,3,1];
alert(isArrayFn(arr));// true
2.Array.isArray()
ECMAScript5將Array.isArray()正式引入JavaScript,目的就是準(zhǔn)確地檢測一個(gè)值是否為數(shù)組。IE9+、 Firefox 4+、Safari 5+、Opera 10.5+和Chrome都實(shí)現(xiàn)了這個(gè)方法。但是在IE8之前的版本是不支持的。
基本數(shù)據(jù)類型與引用數(shù)據(jù)類型的區(qū)別
我們都知道,JS的基本數(shù)據(jù)類型有:String、Boolean、Symbol、Number、Null、Undefined。引用數(shù)據(jù)類型有:Object、Array、Function。
那么基本數(shù)據(jù)類型與引用數(shù)據(jù)類型有什么區(qū)別呢?
基本數(shù)據(jù)類型是按值訪問的,因?yàn)榭梢灾苯颖4孀兞恐械膶?shí)際值,舉個(gè)例子:
var a = 10;
var b = a;
b = 20;
console.log(a); // 10值
上面,b獲取的是a值得一份拷貝,雖然,兩個(gè)變量的值相等,但是兩個(gè)變量保存了兩個(gè)不同的基本數(shù)據(jù)類型值。
b只是保存了a復(fù)制的一個(gè)副本。所以,b的改變,對a沒有影響。
這里就需要引出一個(gè)棧與堆的概念,根據(jù)aliya跟我說的,可能不那么明確,大意是說:【棧是基本數(shù)據(jù)類型保存的地方,它的內(nèi)存是由系統(tǒng)來管理的,而堆是由程序員來管理這些內(nèi)存的】;
回到上面那段代碼的例子。引用一個(gè)圖來演示這種基本數(shù)據(jù)類型賦值的過程。
基本數(shù)據(jù)類型賦值-六個(gè)周.png
javascript的引用數(shù)據(jù)類型是保存在堆內(nèi)存中的對象。 與其他語言的不同是,你不可以直接訪問堆內(nèi)存空間中的位置和操作堆內(nèi)存空間。只能操作對象在棧內(nèi)存中的引用地址。
所以,引用類型數(shù)據(jù)在棧內(nèi)存中保存的實(shí)際上是對象在堆內(nèi)存中的引用地址。通過這個(gè)引用地址可以快速查找到保存中堆內(nèi)存中的對象。
繼續(xù)看例子:
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了
說明這兩個(gè)引用數(shù)據(jù)類型指向了同一個(gè)堆內(nèi)存對象。obj1賦值給onj2,實(shí)際上這個(gè)堆內(nèi)存對象在棧內(nèi)存的引用地址復(fù)制了一份給了obj2,
但是實(shí)際上他們共同指向了同一個(gè)堆內(nèi)存對象。實(shí)際上改變的是堆內(nèi)存對象。
下面我們來演示這個(gè)引用數(shù)據(jù)類型賦值過程:
引用數(shù)據(jù)類型賦值--六個(gè)周.png
然后,從網(wǎng)上找了一個(gè)比較好的總結(jié):
a 聲明變量時(shí)不同的內(nèi)存分配:
1)原始值:存儲(chǔ)在棧(stack)中的簡單數(shù)據(jù)段,也就是說,它們的值直接存儲(chǔ)在變量訪問的位置。
這是因?yàn)檫@些原始類型占據(jù)的空間是固定的,所以可將他們存儲(chǔ)在較小的內(nèi)存區(qū)域 – 棧中。這樣存儲(chǔ)便于迅速查尋變量的值。
2)引用值:存儲(chǔ)在堆(heap)中的對象,也就是說,存儲(chǔ)在變量處的值是一個(gè)指針(point),指向存儲(chǔ)對象的內(nèi)存地址。
這是因?yàn)椋阂弥档拇笮?huì)改變,所以不能把它放在棧中,否則會(huì)降低變量查尋的速度。相反,放在變量的??臻g中的值是該對象存儲(chǔ)在堆中的地址。
地址的大小是固定的,所以把它存儲(chǔ)在棧中對變量性能無任何負(fù)面影響。
b 不同的內(nèi)存分配機(jī)制也帶來了不同的訪問機(jī)制
1)在javascript中是不允許直接訪問保存在堆內(nèi)存中的對象的,所以在訪問一個(gè)對象時(shí),首先得到的是這個(gè)對象在堆內(nèi)存中的地址,然后再按照這個(gè)地址去獲得這個(gè)對象中的值,這就是傳說中的按引用訪問。
2)而原始類型的值則是可以直接訪問到的。
c 復(fù)制變量時(shí)的不同
1)原始值:在將一個(gè)保存著原始值的變量復(fù)制給另一個(gè)變量時(shí),會(huì)將原始值的副本賦值給新變量,此后這兩個(gè)變量是完全獨(dú)立的,他們只是擁有相同的value而已。
2)引用值:在將一個(gè)保存著對象內(nèi)存地址的變量復(fù)制給另一個(gè)變量時(shí),會(huì)把這個(gè)內(nèi)存地址賦值給新變量,也就是說這兩個(gè)變量都指向了堆內(nèi)存中的同一個(gè)對象,他們中任何一個(gè)作出的改變都會(huì)反映在另一個(gè)身上。這里要理解的一點(diǎn)就是,復(fù)制對象時(shí)并不會(huì)在堆內(nèi)存中新生成一個(gè)一模一樣的對象,只是多了一個(gè)保存指向這個(gè)對象指針的變量罷了)。多了一個(gè)指針
d 參數(shù)傳遞的不同(把實(shí)參復(fù)制給形參的過程)
首先我們應(yīng)該明確一點(diǎn):ECMAScript中所有函數(shù)的參數(shù)都是按值來傳遞的。
但是為什么涉及到原始類型與引用類型的值時(shí)仍然有區(qū)別呢?還不就是因?yàn)閮?nèi)存分配時(shí)的差別。
1)原始值:只是把變量里的值傳遞給參數(shù),之后參數(shù)和這個(gè)變量互不影響。
2)引用值:對象變量它里面的值是這個(gè)對象在堆內(nèi)存中的內(nèi)存地址,這一點(diǎn)你要時(shí)刻銘記在心!
因此它傳遞的值也就是這個(gè)內(nèi)存地址,這也就是為什么函數(shù)內(nèi)部對這個(gè)參數(shù)的修改會(huì)體現(xiàn)在外部的原因了,因?yàn)樗鼈兌贾赶蛲粋€(gè)對象。
在對這個(gè)總結(jié)有一個(gè)清晰的認(rèn)識后,有兩個(gè)demo,供大家稍稍練習(xí)。
demo1
var test1 =1;
var test2 =test1;
test2 =4;
console.log(test1);
demo2
var demo1 =new Object();
demo1.name="lyl";
var demo2 = demo1;
demo2.name="lmz";
console.log(demo1.name);
demo3(其實(shí)跟demo2一個(gè)意思)
var demo1 =new Object();
demo1.name="lyl";
var demo2 = demo1;
demo2.name="lmz";
demo1.name="woca";
console.log(demo2.name);
demo4
var demo1 =new Object();
demo1.name="lyl";
var demo2 = new Object();
demo2 = demo1
console.log(demo2 == demo1)
demo5
var demo1 =new Object();
demo1.name="lyl";
var demo2 = new Object();
demo2 = demo1
demo2.name="lmz";
console.log(demo1.name)
答案附上:
demo1: 1
demo2: lmz
demo3: woca
demo4: true
demo5: lmz
如有疑問請?zhí)砑游业奈⑿盘枺?8231133236。歡迎交流!
更多內(nèi)容,請?jiān)L問的我的個(gè)人博客:https://www.liugezhou.online.
您也可以關(guān)注我的個(gè)人公眾號:【Dangerous Wakaka】


