- 基本類型值(數(shù)值、布爾、字符串豆赏、null和undefined ):保存在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段。棧的特性就是里面的東西可以放進(jìn)去拿出來富稻。
var a = 1 //先聲明a掷邦,聲明的意義就是邏輯上在內(nèi)存里開辟一個(gè)棧區(qū)塊,身份是a椭赋,賦值a=1就是這個(gè)棧開始占用實(shí)體內(nèi)存了抚岗,寫入了代表1的編碼。
如果棧內(nèi)存里的數(shù)據(jù)很大很多哪怔,或者后續(xù)有新改動(dòng)宣蔚,會(huì)影響到其他棧內(nèi)存的,而且數(shù)據(jù)大的變量為了操作方便认境,科學(xué)胚委,才有了引用類型一說。
- 引用類型(對(duì)象叉信、數(shù)組亩冬、函數(shù)、正則):指保存在堆內(nèi)存中的對(duì)象茉盏,變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針執(zhí)行內(nèi)存中的另一個(gè)位置枢冤,由該位置保存對(duì)象鸠姨。
這句話意思有點(diǎn)別扭,分析清楚就行了——
引用類型變量想要呈現(xiàn)淹真,表達(dá)讶迁,達(dá)到的目的是:堆內(nèi)存中的內(nèi)容,而不是這個(gè)變量自己聲明后內(nèi)存里自身的內(nèi)容核蘸。
變量自身的內(nèi)容是指向堆內(nèi)存的指標(biāo)巍糯,類似于a鏈接,相當(dāng)于一個(gè)通道客扎。
不過跟console.log有些類似了祟峦,不光指向目標(biāo)堆內(nèi)存,還會(huì)運(yùn)行徙鱼。在邏輯上宅楞,變量自身內(nèi)容是通過它實(shí)體內(nèi)容——指標(biāo)指向的堆內(nèi)存的內(nèi)容针姿,這就是引用的真諦了。
我想要的是引用的內(nèi)容厌衙,變量本身是個(gè)傳送門距淫。
var a
var b
var obj
var obj2
a =1
b = 2
var obj = {
name : "ruoyu",
sex :'male',
age : 30,
friend: {
name : 'hello',
age : 100
}
}
var newObj = { }
b = a //原本a棧內(nèi)存1,b棧內(nèi)存2婶希,這個(gè)操作就是把a(bǔ)棧存的東西覆蓋到b棧里榕暇。
console.log(b) //輸出1
var obj2 = obj //obj2只是聲明了,本身只有object的屬性喻杈,沒有內(nèi)容的彤枢,這時(shí)候把obj的值賦過來,也就是把obj的實(shí)體內(nèi)容——那個(gè)指標(biāo)給復(fù)制了過來奕塑。但是堂污,這時(shí)候要明白,obj占了一個(gè)獨(dú)有的棧內(nèi)存龄砰,obj2也占了一個(gè)獨(dú)有的盟猖,雖然棧里面的內(nèi)容都相同,但不要混淆了换棚。
這時(shí)候進(jìn)行如下操作——
obj.name="jirengu" //輸出jirengu
再查看obj2
obj2 // name的屬性也變成jirengu了式镐。一個(gè)堆內(nèi)存的數(shù)據(jù)共享于所有指向它的變量,變化都是同步的固蚤。
對(duì)比而言娘汞,棧內(nèi)存是相互獨(dú)立的,比如剛才b=a了夕玩,我再操作——
a =3
b //輸出還是1你弦,互相獨(dú)立。
再看下一個(gè)例子:
var obj3 = {name :"hello"} //聲明燎孟,然后開辟一個(gè)堆內(nèi)存禽作,內(nèi)容是,揩页,旷偿,,爆侣,萍程,然后指向這個(gè)堆內(nèi)存。
var obj4 = { name:'hello'} //聲明兔仰,然后開辟一個(gè)堆內(nèi)存茫负,內(nèi)容是,乎赴,朽褪,置吓,,缔赠,然后指向這個(gè)堆內(nèi)存衍锚。
obj3 === obj4 //判斷完全等于,類型一樣嗤堰,堆內(nèi)容展示的也一樣哦戴质,貌似相等。但是兩者的棧內(nèi)存的指標(biāo)內(nèi)容是不一樣的踢匣,也就是說告匠,指向的堆內(nèi)存不是同一個(gè),跟上一個(gè)例子是互補(bǔ)的离唬。判斷的標(biāo)準(zhǔn)就是它們的數(shù)據(jù)類型和棧內(nèi)存的內(nèi)容后专。
這里的意思就是,只要聲明一個(gè)引用對(duì)象输莺,并賦予實(shí)體內(nèi)容戚哎,那這個(gè)時(shí)候,就會(huì)開辟一塊堆內(nèi)存嫂用,并生成一個(gè)新的指標(biāo)型凳。
再來一個(gè)題——
function sum() {
console.log('sum...')
} //聲明sum,聲明一個(gè)函數(shù),并創(chuàng)建它的堆內(nèi)存嘱函,并把指標(biāo)給sum的棧內(nèi)存甘畅。
var sum2 = sum //聲明sum2,并在它的棧內(nèi)存中輸入sum的棧內(nèi)存內(nèi)容往弓。
sum2( ) // 聲明函數(shù)sum2(),首先會(huì)立即執(zhí)行sum2本身疏唾,這個(gè)可以立刻執(zhí)行的函數(shù),前面講過了函似。輸出sum...
基本類型就是:一個(gè)堆內(nèi)存跟幾個(gè)變量產(chǎn)生關(guān)系的情況槐脏;
不同的變量跟不同的堆內(nèi)存產(chǎn)生關(guān)系的情況。
函數(shù)的參數(shù)傳遞——
function inc(n){
n++
} //聲明inc,并創(chuàng)建函數(shù)的堆內(nèi)存和指標(biāo)
var a = 10 // 聲明a缴淋,棧內(nèi)存代表10的碼
inc(a) //執(zhí)行函數(shù)准给,函數(shù)內(nèi)部沒有a,向函數(shù)上層找泄朴,找到了a=10,然后運(yùn)行函數(shù)重抖,這時(shí)候要明白了,a在這里的作用是什么祖灰?是賦值給n,函數(shù)的自變量是n,運(yùn)行的參與者是n钟沛。n自增得11,11是inc(a)的值。而a局扶,全局下a=10恨统。
console.log(a) // 輸出10
這里的意思就是函數(shù)參數(shù)的傳遞叁扫,從函數(shù)外部傳入到內(nèi)部的話,外部的參數(shù)僅僅是賦予了一個(gè)值畜埋,不會(huì)受函數(shù)執(zhí)行而影響自身的莫绣。
function incObj(obj){
obj.n++
} //這時(shí)候,函數(shù)內(nèi)所有的obj值都是指向{n : 10}這個(gè)堆 悠鞍。運(yùn)行是在堆內(nèi)存的數(shù)據(jù)上操作的对室,所以堆結(jié)果已經(jīng)變了,11咖祭。
var o ={n : 10} //找到o了掩宜,這時(shí)候要明白函數(shù)的obj是個(gè)臨時(shí)變量,它也有棧內(nèi)存么翰,這時(shí)候就是把o的棧的內(nèi)容復(fù)制過來牺汤,這時(shí)候obj就指向{n : 10}了。
incObj(o) //賦值obj=o浩嫌,找o,函數(shù)內(nèi)沒有檐迟,往上層
console.log(o) //o本身指標(biāo)是不變的,還是指向那個(gè)堆地址固该,但是堆的數(shù)據(jù)變化了锅减,所以輸出變成了11。
function squireArr(arr){
for(var i =0; i< arr.length; i++){
arr[i] = arr[i] * arr[i]
}
} //與上一個(gè)同樣的原理伐坏,在指向的數(shù)組數(shù)據(jù)上操作怔匣,最終數(shù)組本身也會(huì)變化。
var arr = [2,1,3,6] //把臨時(shí)變量arr指向 [2,1,3,6]
squireArr(arr)
console.log(arr) //[4,1,9,36]
下面這個(gè)就不一樣了:
function squireArr2(arr) {
var newArr = [ ]
for(var i =0; i< arr.length; i++){
newArr[i] = arr[i] * arr[i]
} //通過調(diào)用arr數(shù)組的值桦沉,也是在arr數(shù)組的數(shù)據(jù)上執(zhí)行的每瞒,但是執(zhí)行的結(jié)果是newArr[i] 而不是arr[i],也就是說執(zhí)行不改變arr數(shù)組纯露。
return newArr //創(chuàng)建了一個(gè)新數(shù)組剿骨,返回的結(jié)果也是這個(gè)新數(shù)組。
}
var arr2 =squireArr2( arr)
console.log(arr2)
squireArr2( arr)
對(duì)象的拷貝——
賦值只能讓類型埠褪,展示內(nèi)容還有指標(biāo)相同浓利,在邏輯運(yùn)行上,賦值的雙方還是共用一個(gè)堆內(nèi)存钞速,而且一個(gè)變量運(yùn)行改變了堆內(nèi)存數(shù)據(jù)贷掖,另一個(gè)變量也會(huì)受到影響的,想要的結(jié)果是什么渴语?相當(dāng)于克隆苹威,所有的內(nèi)涵都一樣,但是就是互相獨(dú)立存在的個(gè)體驾凶。
淺拷貝:
function shallowCopy(oldobj){
var newObj ={ } //聲明新的
for(var i in oldObj) { //for里的條件就是便利oldObj的每一個(gè)屬性
if(oldObj.hasOwnProperty(i)){
newObj[i] = oldObj [i]
} //只要oldObj的堆內(nèi)存的數(shù)據(jù)是自己獨(dú)有的就把值賦予給 newObj的對(duì)應(yīng)的參數(shù)牙甫,這只能把一些基本類型數(shù)值賦予過去掷酗,對(duì)于其中的引用類型數(shù)據(jù),只能賦值到一個(gè)指向標(biāo)窟哺,所以只能共用同一個(gè)出處的堆數(shù)據(jù)泻轰,而不是自己獨(dú)有的。所以是淺拷貝且轨。
}
return newObj
}
深拷貝:
function deepCopy(oldObj){
var newObj = { }
for(var key in oldObj){ //同樣是先遍歷所有屬性
if(typyof oldObj[key] === 'object') {
newObj[key] = deepCopy(oldObj[key]) //針對(duì)引用類型做了遞歸處理
}else {
newObj[key] = oldObj[key] //直接賦值
}
}
return newObj
}