深入學習JavaScript數據類型

来源:https://www.cnblogs.com/xueyubao/archive/2020/07/10/13280474.html
-Advertisement-
Play Games

數據類型是我們學習JavaScript時最先接觸的東西,它是JavaScript中最基礎的知識,這些知識看似簡單,但實則有著許多初學者甚至是部分學習了多年JavaScript的老手所不瞭解的知識。 ...


數據類型是我們學習JavaScript時最先接觸的東西,它是JavaScript中最基礎的知識,這些知識看似簡單,但實則有著許多初學者甚至是部分學習了多年JavaScript的老手所不瞭解的知識。

數據類型

ECSMAScript標準中規定了7種數據類型,這7種數據類型又分為基本型和引用類型。

基本類型

  • Null:只包含一個值:null
  • Undefined:只包含一個值:undefined
  • Boolean:包含truefalse
  • Number:整數或浮點數,還有一些特殊值(-Infinity+InfinityNaN
  • String:字元串
  • Symbol:表示獨一無二的值(ES6加入)

ES10(ES2019)中新增了一種基本類型BigInt,可以用來表示超出number安全範圍的任意精度整數。

引用類型

  • Object對象:包含對象、數組、函數等。

基本類型和引用類型的區別

存放位置不同

記憶體空間被分為兩種:棧記憶體和堆記憶體。

棧記憶體

  • 存儲的值大小固定
  • 空間較小
  • 可以直接操作,效率高

堆記憶體

  • 存儲的值大小不確定,可以動態調整
  • 空間較大,運行效率低
  • 無法直接操作其內部,使用引用地址讀取

基本類型就屬於較為簡單的數據,且會被頻繁使用,因此通常存放在棧中。

var a = 10;
var b = 'hello';
var c = true;

基本類型存儲

引用類型則是同時保存在棧和堆當中:引用類型的實際值存儲在堆當中,同時它會在棧中存儲一個指向堆記憶體中的值的地址。

var a = 10;
var obj1 = { name: 'nihao' };
var obj2 = function () {
    // do something
}

引用類型存儲

基本類型具有不可變性

var name = 'hello';
name.toUpperCase(); // "HELLO"
console.log(name); // "hello"

由以上代碼我們會發現,如果不使用name變數本身去接收toUpperCase()的返回值,那麼name的值不會被改變。

由於棧中的記憶體空間大小固定,所以存儲在棧中的變數就是不可變的,但在使用JavaScript時我們會發現可以改變基本類型的值,例如:

var c = true;
c = false;
console.log(c); // false

這實際上是相當於在棧中開闢了一片新的空間用來存儲false這個值,然後用變數c指向這個值,並非改變原本的true

更改基本類型的值

引用類型就可以很輕易的改變了,它不需要使用變數本身(obj1)去再次接收新的值就可以改變,例如:

var obj1 = { name: 'nihao' };
obj1.name = 'nibuhao';
console.log(obj1); // { name: 'nibuhao' }

值比較和引用比較

對於基本類型,比較時會直接比較它們的值,相等返回true

var str1 = 'Hello';
var str2 = 'Hello';
console.log(str1 === str2); // true

對於引用類型,比較時會比較它們的引用地址,哪怕兩個變數具有同名屬性,且同名屬性的值相同,但是因為存儲位置不同,兩者仍然不相等

var obj1 = { name: 'obj' };
var obj2 = { name: 'obj' };
console.log(obj1 === obj2); // false

賦值

與上面的兩種比較類似,基本類型賦值時是直接將值給另一個變數,而引用類型則是將地址給另一個變數

var str1 = 'Hello';
var str2 = str1;
str2 = 'World';
console.log(str1); // "Hello"
//str1的值沒變
var obj1 = { name: 'obj1' };
var obj2 = obj1;
obj2.name = 'obj2';
console.log(obj1.name); // "obj2"
// obj1的值改變

null與undefined

  • null表示空值
  • undefined表示“缺少值”,即此處應該有值,但是還未定義
var a = null;
console.log(typeof a); // object
console.log(typeof b); // undefined

如果學過C#Java之類的靜態類型語言就會知道,直接使用未聲明的變數會直接報錯,而JavaScript是動態類型語言,成員除了存在空值外,還有可能根本就不存在(因為只有在運行時才會知道是否存在)。

Symbol類型

symbol變數需要使用Symbol()創建

var s = Symbol(); // 註意沒有new

Symbol()函數接受一個可選參數,用來描述即將創建的symbol變數,無論傳入的描述是否相同,最後生成的symbol一定是獨一無二的

var name1 = Symbol('Tom');
var name2 = Symbol('Tom');
console.log(name1 === name2); // false

如果一定要創建兩個一模一樣的symbol,需要使用Symbol.for()

var name1 = Symbol.for('Tom');
var name2 = Symbol.for('Tom');
console.log(name1 === name2); // true

Symbol類型可以用作對象屬性,使用該類型可以保證對象不會出現同名屬性

var obj = {
    [Symbol('name')]: 'Tom'
};

使用Symbol類型作為對象的屬性名時,是無法是用for ... inObject.getOwnPropertyNamesObject.keys()獲取到該屬性的,可以調用用來專門獲取Symbol的方法Object.getOwnPropertySymbols()來獲取

var obj = {
    [Symbol('name')]: 'Tom'
};
for (var key in obj) {
   console.log(key); // undefined
}
Object.getOwnPropertySymbols(obj); // [Symbol(name)]

數據類型轉換

圖片來源:https://juejin.im/post/5cec1bcff265da1b8f1aa08f#heading-23

寬鬆等號(==)的隱式轉換

使用==時,如果等號兩側的數據類型相同,那麼比較結果與===相同,否則會發生隱式轉換

NaN

NaN和任何類型比較都會返回false,包括他自己

NaN == NaN // false

Boolean類型與其他類型進行比較

只要Boolean類型參與比較,該Boolean類型的值都會被轉換為Number類型,1轉為true0轉為false

false == 0 // true
true == 1 // true
true == 2 // false

如果在使用if判斷時,我們使用數字作為判斷條件

var x = 10;
if (x) {
	// ...
}
if (x == true) {
    // ...
}

我們會發現,第一個判斷結果為true,而第二個的結果為false,這就是因為true被轉換為了1,判斷條件變為了x == 1

Number類型和String類型進行比較

這兩者進行比較時,String類型會被轉為Number類型,除了純數字字元串正常轉換為Number類型外,空字元串''轉為0,科學計數法(例如1e11)正常轉換,Infinity正常轉換,其他全部轉換為NaN

'' == 0 // true
'123' == 123 // true
'1e11' == 1e11 // true
Infinity == 'Infinity' // true
true == '1' // true
false == '0' // true

null與undefined

null == undefined結果為true外,其他任何類型和nullundefined比較都為false

基本類型與引用類型比較

ToPrimitive規則

首先我們要先瞭解ToPrimitive規則,即引用類型轉為基本類型

  • 當引用類型需要被轉為基本類型時,它會先查找對象的valueOf方法,如果該方法返回基本類型的值,則ToPrimitive的結果就是這個值
  • 如果valueOf不存在或者valueOf方法返回的不是基本類型,就會嘗試調用對象的toString方法,然後使用toString的返回值作為ToPrimitive的結果
  • valueOftoString都不存在,或者沒有返回基本類型,則拋出TypeError異常

對於不同的引用類型,該過程會有些許不同,比如Date會先調用toString

引用類型轉換為不同的基本類型也會有一些不同,比如:

  • 引用類型轉換為Number類型,先調用valueOf,再調用toString
  • 引用類型轉換為String類型,先調用toString,再調用valueOf

具體請參考ECMA標準

Number([]); // 0
Number([10]); // 10

var obj = {
    valueOf: () => { return 10; },
    toString: () => { return -10; }
};
Number(obj); // 10
String(obj); // -10

基本類型與引用類型比較

比較時,引用類型會依據ToPrimitive規則轉換為基本類型

var a = {};
var b = [1, 2, 3];

a == '[object Object]'; // true
a.toString(); // [object Object]
b == '1,2,3' // true
b.toString(); // "1,2,3"

判斷數據類型

typeof

typeof只能用來判斷以下幾個類型

typeof 'str';  // string
typeof 123;  // number
typeof true;  // boolean
typeof Symbol();  // symbol
typeof undefined;  // undefined
typeof function () {} // function

對於引用類型(數組、對象等)以及nulltypeof的返回值均為object

instanceof

instanceof可以判斷引用類型的具體類型

[] instanceof Array; // true
/1/ instanceof RegExp; // true
new Date() instanceof Date; // true

但是,instanceof同樣沒法判斷null

null instanceof null; // Uncaught TypeError: Right-hand side of 'instanceof' is not an object
null instanceof Object; // false

MDN中,instanceof被這樣描述:

instanceof 運算符用於檢測構造函數的 prototype 屬性是否出現在某個實例對象的原型鏈上。

也就是說instanceof設計的初衷並不是用來檢測數據類型的,因此很多類型它也無法判斷

Object.prototype.toString.call()

Object.prototype.toString.call()利用call來改變this的指向,可以讓該方法能夠獲取到任意變數的[[class]]屬性,通過該屬性可以判斷所有JavaScript的內置類型

Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(undefined); // [object Undefined]
Object.prototype.toString.call(123); // [object Number]
Object.prototype.toString.call(new Date()); // [object Date]
// ...

但是該方法並不能判斷自定義類型,而instanceof可以實現對自定義類型的判斷

function Person() {}
Object.prototype.toString.call(new Person()); // [object Object]
new Person() instanceof Person; // true

參考資料


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • SQL自學筆記 約束 1.0概念及分類 2.0非空約束 3.0 唯一約束 4.0 主鍵約束 自動增長 5.0 外鍵約束 級聯操作 多表關係 三種情況概述 資料庫的備份和還原 多表查詢 1.0 內連接查詢 隱式內連接 : 用where條件消除無用數據 顯示內連接 : 2.0 外連接查詢 3.0 子查詢 ...
  • 先給大家看一下大佬們對這本書的評價,免得說我“標題黨” 版本控制是管理數據變更的藝術,無論數據變更是來自同一個人,還是來自不同的人(一個團隊)。版本控制系統不但要忠實地記錄數據的每一次變更, 還要能夠幫助還原任何一-次歷史變更,以及實現團隊的協同工作等。Git就是版本控制系統中的佼佼者。 當開源軟體 ...
  • 同步部分數據有兩個思路: master只發送需要的; 優點:中繼日誌小;如果多從庫,只需要在主庫中統一控制 缺點:中途修改比較麻煩,不能控制同步的表 slave只接收想要的 優點:中途修改同步的表或庫方便;可以控制需要的表和庫 缺點:中繼日誌大;如果從庫比較多,需要一個一個配置; master端 b ...
  • 前幾天HBase出現了RIT告警,忽然發現發出告警的Region所屬的表並不是我創建出來的,於是就想看看這些表是怎麼來的。 一時也沒什麼頭緒,就先看看這些表是什麼時候創建出來的吧,然後再根據時間點看看有誰操作了資料庫。 那麼怎麼看表的創建時間呢?desc看一下,也沒有這個屬性啊。再細想呢,hbase ...
  • 告警 正在開會,突然釘釘告警聲響個不停,同時市場人員反饋客戶在投訴系統登不進了,報504錯誤。查看釘釘上的告警信息,幾台業務伺服器節點全部報CPU超過告警閾值,達100%。 趕緊從會上下來,SSH登錄伺服器,使用 top 命令查看,幾個Java進程CPU占用達到180%,190%,這幾個Java進程 ...
  • 為學習spark,虛擬機中開4台虛擬機安裝spark3.0.0底層hadoop集群已經安裝好,見ol7.7安裝部署4節點hadoop 3.2.1分散式集群學習環境首先,去http://spark.apache.org/downloads.html下載對應安裝包解壓[hadoop@master ~]$... ...
  • 1.Canvas概述 Canvas API(畫布)用於在網頁實時生成圖像,並且可以操作圖像內容,基本上它是一個可以用JavaScript操作的點陣圖(bitmap)。 要使用HTML5在瀏覽器視窗中繪製圖形,首先需要在HTML文檔中新建一個canvas網頁元素。一般方法如下: <canvas id=" ...
  • 項目搭建時間:2020-06-29 本章節:講述基於vue/cli, 項目的基礎搭建。 本主題講述了: 1、跨域配置 2、axios請求封裝 3、eslint配置 4、環境dev,test,pro(開發,測試,線上), run自動調用對應的介面(proxy多代理配置) vue+element-ui ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...