這是《關於 JavaScript 你必需要知道的 33 個概念 》系列的第三篇文章,今天稍微給你們介紹下這個系列。前端
現在前端的發展突飛猛進,不少人(包括我)都是追逐着一些流行的框架學習,但每每是浮於表面,知其然而不知其因此然。當我認真的想要搞懂 react、redux 實現原理時,才發現,JavaScript 的基礎知識是如此重要。react
一直以來,本身對於 JavaScript 的理解都散亂無章,這就形成不少知識當時看事後感受明白了,過一段時間用到的時候卻仍舊一臉懵逼。所以,我決定整理這樣一個系列,加深本身對 JavaScript 的理解,造成知識體系,以達到融會貫通。git
這個計劃會寫 33 篇文章,會包括 JavaScript 中的基礎概念如「數據類型」、「表達式和語句」、「做用域」等,以及如「閉包」、「this」、「promise」等有些理解難度的知識點。github
首先聲明我不是什麼大佬,對於不少知識也是一邊鑽研一邊寫,因此若是有不一樣的見解,懇請你們指正,我會及時更新文章的不足之處!正則表達式
接下來,咱們言歸正傳。redux
在上一篇文章(數據類型)中咱們知道 JavaScript 的數據類型分爲基本數據類型和對象數據類型。它們的區別之一就是在計算機中的存儲方式不一樣:基本類型數據是將變量名及值存儲在變量對象中,而引用類型的數據是將變量名和地址存儲在變量對象中,真正的值是存儲在堆內存中。promise
再次將那張圖放過來:閉包
其中,基本類型(number,string,boolean,undefined,null),便稱爲值類型,而對象類型(object,function,array及封裝對象)便稱爲引用類型。框架
值類型的數據是不可變的。 這裏說的不可改變,是指值自己,一旦建立,便不可更改。什麼意思?舉個例子:函數
let a = 34; a = 43;
咱們先聲明一個變量 a 並賦值爲 34,此時,在變量對象中 34 就已經存放在固定位置,後邊將 a 的值改成 43,看起來好像是將 34 改變成了 43, 其實否則,咱們只是又在變量對象中存入了 43,原來的 34,仍舊原封未動的存在那裏,等待着被內存回收。以下圖所示:
<div align="center">
<img src="http://upload-images.jianshu....;/>
</div>
引用類型值是能夠改變的。 引用類型的值是將變量名稱和引用地址存儲在變量對象中,而值是在堆內存中,咱們能夠隨時更改它自己的值。
let b = { m: 1, n: 'emmm' } b.m = 4; b; // {m: 4,n: 'emmm'}
在上例中,咱們聲明 b 是一個引用類型值,接着,咱們對 b 進行了更改,咱們能夠看到,更改是有效的。
值類型的複製是值自己的複製,引用類型的複製是值得引用的複製。 不一樣的複製方式會在複製後有不一樣的表現。
// 值類型的複製 var a = 45; var b = a; console.log(b); // 45 b = "someword"; console.log(b) // "someword" console.log(a); // 45 // 引用類型的複製 var someone= { age: 14, weight: 134, sex: 'man' }; var anthor = someone; console.log(anthor); // {age: 14, weight: 134, sex: "man"} anthor.age = 16; console.log(anthor); // {age: 16, weight: 134, sex: "man"} console.log(someone); // {age: 16, weight: 134, sex: "man"}
從上面的代碼中能夠看到,變量 b 複製變量 a 的以後進行了更改,b 的值改變了,而 a 的值沒變;變量 anthor 複製的是 someone 的引用,anthor 更改了引用指向的那個對象的值,someone 的值天然也跟着改變了。
具體過程如圖所示:
它們的概念理解起來很簡單,但不少時候應用到實際場景中,咱們就可能想不到這一層,會形成不少意外的問題,接下來咱們看一下。
==
與 ===
在進行 ==
及 ===
判斷時,前者會對等號兩邊的值進行強制類型轉換,這對判斷值類型的相等有所區別。可是對於引用類型,它們都只會判斷引用地址是否相同,而無論對象裏的屬性值是否相同。
好比:
// 值類型相等 let a = 45; let b = 45; console.log(a == b); // true b = '45'; console.log(a == b); // true console.log(a === b); // false // 引用類型相等 let men_1 = { age: 23, sex: 'man', }; let men_2 = { age: 23, sex: 'man', }; let men_3 = men_1; console.log(men_1 == men_2); // false console.log(men_1 === men_2); // false console.log(men_1 == men_3); // true console.log(men_1 === men_3); // true
從上面咱們能夠看到:45 === 45
但 45 != '45'
,但 men_1 雖然和 men_2 的值相同,但他們並不相等,不管是 ==
仍是 ===
。
那該如何按照咱們的想法比較呢?
能夠把它們轉化爲字符串進行比較,固然,這樣也不能保證徹底正確(好比對象中含有正則表達式),更嚴格的方法之後再討論。
function compare(a, b) { return JSON.stringify(a) == JSON.stringify(b); }
函數傳參時,是將傳入的參數拷貝到函數的參數參數變量上,所以,拷貝帶來的問題在函數傳參時仍舊存在。
function foo(a,b) { var d = a; d = 'string'; var e = b; e.name = 'xiaohong'; } var exmp_1 = 3; var exmp_2 = { name: 'xiaohua' }; foo(exmp_1,exmp_2); console.log(exmp_1); // 3 console.log(exmp_2); // {name: "xiaohong"}
如上所示,值類型傳入後再函數內的修改不會污染外部的變量,而引用類型的變量因爲複製的是引用,在函數內部的改動會影響到外部的變量。
如果想要避免這種狀況,則須要在接受參數時進行深拷貝。
function foo(people) { const newPeople = JSON.parse(JSON.stringify(people)); newPeople.firstName = 'wang'; } var Liu = { firstName: 'liu' } foo(Liu); console.log(Liu); // {firstName: "liu"}
到此,關於值類型與引用類型的介紹就結束了,留一道題給你們,你們能夠藉此看一看對本文的理解。
function create(person) { var personA = person; personA.name = 'David'; var personB = { name: 'saay', age: 13 }; return personB; } var Jone = { name: 'Join', age: 25 } var Wang = create(Jone); console.log(Jone) ;// ?? console.log(Wang); // ??
原文地址: 阿木木的博客