一左腔、JS的基本數(shù)據(jù)類(lèi)型
- 基本數(shù)據(jù)類(lèi)型:String,Boolean捅儒,Number液样,Undefined,Null巧还;
- 引用數(shù)據(jù)類(lèi)型:Object(Array鞭莽,Date,RegExp狞悲,F(xiàn)unction)撮抓;
- 基本數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型的區(qū)別:
1、保存位置不同:基本數(shù)據(jù)類(lèi)型保存在棧內(nèi)存中摇锋,引用數(shù)據(jù)類(lèi)型保存在堆內(nèi)存中丹拯,然后在棧內(nèi)存中保存了一個(gè)對(duì)堆內(nèi)存中實(shí)際對(duì)象的引用,即數(shù)據(jù)在堆內(nèi)存中的地址荸恕,JS對(duì)引用數(shù)據(jù)類(lèi)型的操作都是操作對(duì)象的引用而不是實(shí)際的對(duì)象乖酬,例如復(fù)制的實(shí)質(zhì)是復(fù)制了地址,因而它們指向了同一個(gè)堆內(nèi)存對(duì)象融求;
為什么基本數(shù)據(jù)類(lèi)型保存在棧中咬像,而引用數(shù)據(jù)類(lèi)型保存在堆中?
1)堆比棧大生宛,棧比堆速度快县昂;
2)基本數(shù)據(jù)類(lèi)型比較穩(wěn)定,而且相對(duì)來(lái)說(shuō)占用的內(nèi)存邢菥恕倒彰;
3)引用數(shù)據(jù)類(lèi)型大小是動(dòng)態(tài)的,而且是無(wú)限的莱睁,引用值的大小會(huì)改變待讳,不能把它放在棧中,否則會(huì)降低變量查找的速度仰剿,因此放在變量棿吹空間的值是該對(duì)象存儲(chǔ)在堆中的地址,地址的大小是固定的南吮,所以把它存儲(chǔ)在棧中對(duì)變量性能無(wú)任何負(fù)面影響琳彩;
4)堆內(nèi)存是無(wú)序存儲(chǔ),可以根據(jù)引用直接獲取汁针;
按引用訪問(wèn):js不允許直接訪問(wèn)保存在堆內(nèi)存中的對(duì)象术辐,所以在訪問(wèn)一個(gè)對(duì)象時(shí),首先得到的是這個(gè)對(duì)象在堆內(nèi)存中的地址施无,然后再按照這個(gè)地址去獲得這個(gè)對(duì)象中的值辉词;
2、使用typeof
可以返回基本數(shù)據(jù)類(lèi)型猾骡,但是NULL類(lèi)型會(huì)返回object瑞躺,因此null值表示一個(gè)空對(duì)象指針;引用數(shù)據(jù)類(lèi)型使用typeof會(huì)返回object兴想,此時(shí)需要使用instanceof
來(lái)檢測(cè)
typeof 1 //number
typeof new Number(1) //object
1 instanceof Number //false
new Number(1) instanceof Number //true
其中1是基本數(shù)據(jù)類(lèi)型幢哨,不是引用數(shù)據(jù)類(lèi)型,因此instanceof
總為false
通過(guò)new Number(1)
包裝以后成為引用數(shù)據(jù)類(lèi)型嫂便,可以判斷為Number
3捞镰、引用數(shù)據(jù)類(lèi)型 (注意,例如new Boolean(false)和false是不===的,但是經(jīng)過(guò)JSON轉(zhuǎn)換后,丟失了constructor,變?yōu)槠胀ǖ膄alse)
- ES6新增數(shù)據(jù)類(lèi)型:Map,Set毙替,Generator岸售,Symbol
- 本地對(duì)象:ECMA-262 把本地對(duì)象(native object)定義為“獨(dú)立于宿主環(huán)境的 ECMAScript 實(shí)現(xiàn)提供的對(duì)象”,即本地對(duì)象就是 ECMA-262 定義的類(lèi)(引用類(lèi)型)厂画;
- 宿主對(duì)象:宿主”就是我們網(wǎng)頁(yè)的運(yùn)行環(huán)境凸丸,即“操作系統(tǒng)”和“瀏覽器”,所有非本地對(duì)象都是宿主對(duì)象(host object)袱院,即由 ECMAScript 實(shí)現(xiàn)的宿主環(huán)境提供的對(duì)象屎慢,所有的BOM和DOM對(duì)象都是宿主對(duì)象,因?yàn)槠鋵?duì)于不同的“宿主”環(huán)境所展示的內(nèi)容不同忽洛,即ECMAScript官方未定義的對(duì)象都屬于宿主對(duì)象腻惠,因?yàn)槠湮炊x的對(duì)象大多數(shù)是自己通過(guò)ECMAScript程序創(chuàng)建的對(duì)象;
- JS內(nèi)置對(duì)象:是指JS語(yǔ)言自帶的一些對(duì)象欲虚,供開(kāi)發(fā)者使用妖枚,這些對(duì)象提供了一些常用的或是最基本而必要的功能;
1苍在、Arguments:函數(shù)參數(shù)集合;
2荠商、Array對(duì)象:length,instanceof,isArray(),toString()返回字符串,valueOf()返回?cái)?shù)組的值,join()可以將數(shù)組轉(zhuǎn)為字符串,push(),pop(),shift(),unshift(),reverse(),sort(),
slice(),splice(),indexOf(),lastIndexOf(),迭every(),filter(),forEach(),map(),some(),
歸并方法reduce(),reduceRight()寂恬;
3、Boolean:布爾對(duì)象莱没;
4初肉、Error:異常對(duì)象;
5饰躲、Number:數(shù)值對(duì)象牙咏;
6臼隔、String對(duì)象:length,charAt()返回指定位置的字符,concat(),slice(),subString(),
subStr(),indexOf(),lastIndexOf(),trim(),toLowerCase(),toUpperCase(),split(),
text.match(),text.splice();
7妄壶、Date對(duì)象:toUTCstring(),getTime()摔握;
8、RegExp對(duì)象:test()丁寄;
9氨淌、Function對(duì)象:arguments,this,apply(this,arguments),call(this,num1,num2);
10伊磺、Math對(duì)象:min(),max(),ceil(),floor(),round(),random()盛正;
11、Global對(duì)象:encodeURI,encodeURIComponent屑埋,parseInt(),eval()豪筝;
12、Object對(duì)象:prototype,constructor摘能; - 基本包裝類(lèi)型:Boolean,Number,String
為了便于操作“基本類(lèi)型值”续崖,JS 提供了 三個(gè) 特殊的引用類(lèi)型:Boolean、Number徊哑、String袜刷。這些類(lèi)型和其他引用類(lèi)型相似,但同時(shí) 也具備與各自基本類(lèi)型相應(yīng)的特殊行為莺丑。實(shí)際上:每當(dāng)讀取一個(gè)基本類(lèi)型值的時(shí)候著蟹, “后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類(lèi)型的對(duì)象”,從而能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù)梢莽。
當(dāng)通過(guò)直接賦值方式創(chuàng)建時(shí),具有基本類(lèi)型的性質(zhì),無(wú)法動(dòng)態(tài)添加屬性和方法萧豆。
當(dāng)通過(guò)New修飾符創(chuàng)建時(shí),屬于引用類(lèi)型,可以動(dòng)態(tài)添加屬性和方法昏名。
二涮雷、賦值、淺拷貝與深拷貝
賦值
賦的其實(shí)是該對(duì)象的在棧中的地址轻局,而不是堆中的數(shù)據(jù)洪鸭。也就是兩個(gè)對(duì)象指向的是同一個(gè)存儲(chǔ)空間,兩個(gè)對(duì)象是完全聯(lián)動(dòng)的仑扑。
淺拷貝
按位拷貝對(duì)象览爵,它會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝镇饮。如果屬性是基本類(lèi)型蜓竹,拷貝的就是基本類(lèi)型的值;如果屬性是內(nèi)存地址(引用類(lèi)型),拷貝的就是內(nèi)存地址 俱济,因此如果其中一個(gè)對(duì)象改變了這個(gè)地址嘶是,就會(huì)影響到另一個(gè)對(duì)象。
Object.assign()
和數(shù)組的slice()
蛛碌、concat()
僅對(duì)基本類(lèi)型數(shù)據(jù)進(jìn)行了深拷貝擴(kuò)展運(yùn)算符
let bar = {...baz};
- 遍歷賦值
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
深拷貝
創(chuàng)造一個(gè)一模一樣的對(duì)象聂喇,新對(duì)象跟原對(duì)象不共享內(nèi)存,修改不會(huì)互相影響左医。
-
JSON.parse(JSON.stringify())
可以部分實(shí)現(xiàn)深拷貝,但會(huì)失去constructor,凡是undefined授帕、function、symbol浮梢、Map, Set, RegExp, Date, ArrayBuffer 等內(nèi)置類(lèi)型在進(jìn)行序列化時(shí)會(huì)丟失,Boolean跛十、Number、String等基本包裝類(lèi)型會(huì)變成普通的基本數(shù)據(jù)類(lèi)型秕硝。此外不能處理多重嵌套芥映。
let a = {};
let b = {a};
a.b = b;
let copy = JSON.parse(JSON.stringify(a));//報(bào)錯(cuò)
- 采用函數(shù)庫(kù)lodash提供的
_.cloneDeep
進(jìn)行深拷貝
var obj2 = _.cloneDeep(obj1);
- 采用jquery提供的
$.extend
進(jìn)行深拷貝
var obj2 = $.extend(true, {}, obj1);
- 利用
MessageChannel
發(fā)送并接收消息,作為復(fù)制結(jié)果。缺點(diǎn)是該操作為異步,且依然不支持function远豺。
function structuralClone(obj) {
return new Promise(resolve =>{
const {port1, port2} = new MessageChannel();
//兩個(gè)port可以互相通過(guò)onmessage ,監(jiān)聽(tīng)到對(duì)方postMessage的內(nèi)容
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
})
}
const obj = /* ... */;
structuralClone(obj).then(res=>{
console.log(res);
})
- 利用history api中的
history.state
傳遞并接收數(shù)據(jù),作為復(fù)制結(jié)果奈偏。該方法是同步的,但有些瀏覽器對(duì)調(diào)用頻率有限制。 - 遍歷對(duì)象躯护、數(shù)組直到都是基本數(shù)據(jù)類(lèi)型惊来,然后再進(jìn)行復(fù)制
// 定義檢測(cè)數(shù)據(jù)類(lèi)型的功能函數(shù)
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
// 實(shí)現(xiàn)深度克隆---對(duì)象/數(shù)組
function clone(target) {
// 判斷拷貝的數(shù)據(jù)類(lèi)型
// 初始化變量result 成為最終克隆的數(shù)據(jù)
let result, targetType = checkedType(target)
if (targetType === 'object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
// 遍歷目標(biāo)數(shù)據(jù)
for (let i in target) {
// 獲取遍歷數(shù)據(jù)結(jié)構(gòu)的每一項(xiàng)值。
let value = target[i]
// 判斷目標(biāo)結(jié)構(gòu)里的每一值是否存在對(duì)象/數(shù)組
if (checkedType(value) === 'Object' ||
checkedType(value) === 'Array') { //對(duì)象/數(shù)組里嵌套了對(duì)象/數(shù)組
// 繼續(xù)遍歷獲取到value值
result[i] = clone(value)
} else {
// 獲取到value值是基本的數(shù)據(jù)類(lèi)型或者是函數(shù)棺滞。
result[i] = value;
}
}
return result
}
// 定義檢測(cè)數(shù)據(jù)類(lèi)型的功能函數(shù)
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
// 實(shí)現(xiàn)深度克隆---對(duì)象/數(shù)組
function clone(target) {
// 判斷拷貝的數(shù)據(jù)類(lèi)型
// 初始化變量result 成為最終克隆的數(shù)據(jù)
let result, targetType = checkedType(target)
if (targetType === 'object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
// 遍歷目標(biāo)數(shù)據(jù)
for (let i in target) {
// 獲取遍歷數(shù)據(jù)結(jié)構(gòu)的每一項(xiàng)值裁蚁。
let value = target[i]
// 判斷目標(biāo)結(jié)構(gòu)里的每一值是否存在對(duì)象/數(shù)組
if (checkedType(value) === 'Object' ||
checkedType(value) === 'Array') {
// 對(duì)象/數(shù)組里嵌套了對(duì)象/數(shù)組
// 繼續(xù)遍歷獲取到value值
result[i] = clone(value)
} else {
// 獲取到value值是基本的數(shù)據(jù)類(lèi)型或者是函數(shù)。
result[i] = value;
}
}
return result
}