33 個 js 核心概念(三):值類型與引用類型

值類型與引用類型

說點別的

這是《關於 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及封裝對象)便稱爲引用類型。框架

值類型與引用類型的區別

1. 可變性與不可變性

值類型的數據是不可變的。 這裏說的不可改變,是指值自己,一旦建立,便不可更改。什麼意思?舉個例子:函數

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 進行了更改,咱們能夠看到,更改是有效的。

2. 值的複製

值類型的複製是值自己的複製,引用類型的複製是值得引用的複製。 不一樣的複製方式會在複製後有不一樣的表現。

// 值類型的複製
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 的值天然也跟着改變了。

具體過程如圖所示:

應用

它們的概念理解起來很簡單,但不少時候應用到實際場景中,咱們就可能想不到這一層,會形成不少意外的問題,接下來咱們看一下。

1. =====

在進行 ===== 判斷時,前者會對等號兩邊的值進行強制類型轉換,這對判斷值類型的相等有所區別。可是對於引用類型,它們都只會判斷引用地址是否相同,而無論對象裏的屬性值是否相同。

好比:

// 值類型相等
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 === 4545 != '45',但 men_1 雖然和 men_2 的值相同,但他們並不相等,不管是 == 仍是 ===

那該如何按照咱們的想法比較呢?

能夠把它們轉化爲字符串進行比較,固然,這樣也不能保證徹底正確(好比對象中含有正則表達式),更嚴格的方法之後再討論。

function compare(a, b) {
  return JSON.stringify(a) == JSON.stringify(b);
}

2. 函數傳參

函數傳參時,是將傳入的參數拷貝到函數的參數參數變量上,所以,拷貝帶來的問題在函數傳參時仍舊存在。

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); // ??
原文地址: 阿木木的博客
相關文章
相關標籤/搜索