最近本身迴歸基礎看了下javascript的相關知識點,想着看都看了,寫出來記錄下足跡也是一件好事,遂記錄~javascript
在javascript
中有兩種類型,一種是基本數據類型,一種是引用類型。java
基本數據類型,也稱爲簡單數據類型,在ES5
中有如下五種:Undefined、Null、Boolean、Number和String
,在ES6
中新增了一種簡單的數據類型Symbol
。git
Undefined類型只有一個值undefined
。在進行相關變量定義的時候,未賦值的狀況下,默認是賦值爲undefined
了。可是也是有些特殊的狀況下會報錯的。狀況我大體羅列下:es6
# 狀況1⃣️:變量聲明瞭,可是沒有賦值
var message;
console.log(message); // undefined
# 狀況2⃣️:變量聲明並賦值了,可是在console運行以後
console.log(message); // undefined
var message = 'find a frontend job in Canton!';
# 狀況3⃣️:變量沒聲明,報引用報錯
// var message;
console.log(message); // Uncaught ReferenceError: message is not defined
# 狀況4⃣️:不經過var聲明,直接寫變量,報引用錯誤
message; // 不等價 var message;
console.log(message); // Uncaught ReferenceError: message is not defined
# 狀況5⃣️:不經過var聲明,直接寫變量賦值
message = 'find a frontend job in Canton!'; // 默認在message前添加了var
console.log(message); // find a frontend job in Canton!
# 狀況6⃣️:不經過var聲明,直接寫賦值,可是在console運行以後,報引用錯誤
console.log(message);
message = 'find a frontend job in Canton!'; // 至關於沒message變量
複製代碼
上面羅列的是ES5
中經過var
聲明的狀況。也許你會對狀況2⃣️產生疑惑:我都給message
賦值了啊,可是打印出undefined
,這就有點尷尬了?github
由於在js中執行上下文分爲兩個階段,第一個階段是建立階段
,第二個階段纔是執行階段
。api
上面狀況2⃣️的執行狀況以下:bash
1. 建立階段:frontend
executionContextObj = {
scopeChain: { ... },
variableObject: {
message: undefined
},
this: { ... }
}
複製代碼
2. 執行階段:函數
executionContextObj = {
scopeChain: { ... },
variableObject: {
message: 'find a frontend job in Canton!'
},
this: { ... }
}
複製代碼
詳細的解析能夠看下我以前翻譯的一篇文章JS的執行上下文和環境棧是什麼?。ui
上面講到的是var
,咱們引入ES6
的let 和 const
來演示下:
# 狀況7⃣️:let聲明變量賦值
let message;
console.log(message); // undefined
# 狀況8⃣️:let聲明變量可是不賦值,在console運行以後
console.log(message); // Uncaught ReferenceError: Cannot access 'message' before initialization
let message = 'find a frontend job in Canton!';
# 狀況9⃣️:const聲明變量可是不賦值,報語法錯誤
const message;
console.log(message); // Uncaught SyntaxError: Missing initializer in const declaration
複製代碼
let和const
改變了var
命令會發生變量提高的現象,即變量能夠在聲明以前使用,值爲undefined
。它們改變了這種奇怪的現象,聲明的變量必定要在聲明以後使用,不然報錯。
固然還有其餘聲明變量的方法,好比function
命令等,這裏不一一列舉,只是探討下undefined
的值而已~
Null
類型的值是null
。從邏輯角度來看,null
值表示一個空對象指針。
若是定義的變量準備在未來用來保存對象,那麼最好就是將變量初始化爲null
,而不是其餘的數據值。這樣,只要直接檢查null
值就能夠知道相應的變量是否已經保存了一個對象的引用。以下面的例子:
if(car != null) {
// 對car對象執行某些操做
}
複製代碼
undefined
值是派生自null
值的。雖然二者在==
比較時候是相等的,以下:
console.log(null == undefined); // true
複製代碼
當變量不肯定類型的時候,能夠不用爲變量賦值,也就是默認賦值undefined
了。可是若是你知道你的變量要保存對象可是尚未真正保存對象的時候就要賦值null
了。
Boolean
類型在平常生活中使用頻繁了,其值是true
和false
,對應咱們口頭的是
和否
。
將布爾值的true
和false
轉換爲數值的話,能夠用非0
和0
數字表示。
console.log( 1 == true); // true
console.log( 0 == false); // true
複製代碼
若是是恆等的比較方式===
,那數字表示法是要涼涼的~
Number
類型有二進制表示法,八進制表示法,十六進制表示法和十進制表示法。這裏只討論十進制表示法
,由於在日常的開發中,用到十進制的狀況居多😂
這個類型用來表示整數值和浮點數值(即帶小數點的值)。
整數值的基本操做非常簡單,並且沒啥bug好說,除非不在Number.MIN_VALUE
和Number.MAX_VALUE
範圍內。帶小數點的仍是要留意下的,好比:
let a = 13.04;
let b = 2.5;
console.log(a + b); // 15.54
console.log(a * b); // 32.599999999999994
console.log(a - b); // 10.54
複製代碼
咦咦,真是讓人尷尬😅,怎麼上面代碼中兩個浮點數相乘會出現那麼多位的數字啊,不是等於32.6
嗎?
因此在進行浮點數的運算的時候仍是得慎重點,先轉換成整數計算,以後再切換回去浮點數,好比上面的a * b
能夠考慮寫成(a * 100 * (b * 10))/1000
。
當你要判斷一個值是不是數值,可使用isNaN
來表示,其返回一個布爾值,以下:
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false
console.log(isNaN('10'); // false , '10'會被轉化爲10
console.log('blue'); // true , 不能轉化爲數值
console.log(true); // false, 可被轉化爲數值1
複製代碼
還有將非數值轉化爲數值的三個方法:Number()、parseInt()和parseFloat()
。見名思義:
**Number()是將傳入的內容轉換爲數字(整數)或NaN
。可是在轉換字符串的時候比較複雜,通常用parseInt()**居多。**parseFloat()**就是轉化成浮點數的方法啦。
String
類型也就是字符串類型啦。
字符串類型包含一些特殊的字符字面量,也叫轉義序列,用來表示非打印字符串。好比換行符\n
啦。
在實際的開發中,咱們須要將數字類型或對象類型轉換成字符串類型,那麼咱們能夠直接使用toString()
方法進行操做啦。好吧,這api的東西你們都會用,就不說了😂
Symbol
類型是ES6
引入的新類型,爲了防止對象中屬性名衝突的問題。
Symbol
值經過Symbol
函數生成。這就是說,對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的Symbol
類型。凡是屬性名屬於Symbol
類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突。
具體的看下阮一峯的es6入門中Symbol部分。
上面說到的是6種基本的數據類型,還有一種是引用類型。
引用類型:當複製保存對象的某個變量時,操做的是對象的引用,可是在爲對象添加屬性時,操做的是實際的對象。引用類型值指那些可能有多個值構成的對象。
引用類型有這幾種:Object、Array、RegExp、Date、Function、特殊的基本包裝類型(String、Number、Boolean)以及單體內置對象(Global、Math)。
基本包裝類型
這個有點好玩,咦?上面的基本數據類型都有String、Number和Boolean
啦,怎麼這裏還有這些。是的,上面的基本類型是經過基本包裝類型來建立的。以下:
var s1 = 'find a frontend job in Canton';
var s2 = s1.substring(2);
複製代碼
上面的代碼實際進行了下面的步驟:
(1)建立String類型的一個實例;
(2)在實例中調用指定的方法;
(3)銷燬這個實例。
上面的三個步驟轉化爲代碼以下:
var s1 = new String('find a frontend job in Canton');
var s2 = s1.substring(2);
s1 = null;
複製代碼
(正規)的引用類型和基本包裝類型的主要區別就是對象的生存期。使用new
操做符建立的引用類型的實例,在執行流離開當前做用域以前都一直保存在內存中。而自動建立的基本包裝類型的對象,則只存在於下一行代碼的執行瞬間,而後當即被銷燬。這意味着咱們不能在運行時爲基本類型值添加屬性和方法。來看下下面的例子:
var s1 = 'find a frontend job in Canton';
s1.name = 'jia ming';
console.log(s1.name); // undefined
複製代碼
只能經過基本包裝類的原型來添加了,好比改寫toString
方法:
var s1 = 'find a frontend job in Canton';
String.prototype.toString = function() {
console.log('my name is jia ming');
}
console.log(s1.toString()); // my name is jia ming
複製代碼
嗯~苦口婆心介紹了javascript
的數據類型,那麼下面纔是重頭戲。咱們在實際的開發中,如何識別不一樣的數據類型呢?
數據類型有上面的7種類型,其中基本類型是Undefined、Null、Boolean、Number、String和Symbol
,還有一種引用類型。引用類型又包含比較多種的對象,好比Object
、Array
等。
咱們首先想到的是經過typeof
來判斷,直接上代碼來試下吧:
let symbol = Symbol('jia ming');
let str = 'find a frontend job in Canton!';
let flag = true;
let height = 99;
let job;
let obj = null;
console.log(typeof symbol); // symbol
console.log(typeof str); // string
console.log(typeof flag); // boolean
console.log(typeof height); // number
console.log(typeof job); // undefined
console.log(typeof obj); // object
複製代碼
嗯~很ok啦,對基本的數據類型都能判斷到啦,這個null
獲得的結果是object
,你能夠當成特殊狀況來處理啦 -- 無中生有,一輩子萬物嘛。
咱們再來看下引用類型打印出來的是什麼東東😊
let person = {
name: 'jia ming',
info: 'find a frontend job in Canton!',
};
let arr = ['jia ming', 'find a frontend job in Canton!'];
let reg = new RegExp('jia ming', 'g');
let date = new Date();
let fn = () => {
return 'find a frontend job in Canton!';
}
let math = Math.min(2, 4, 8);
console.log(typeof person); // object
console.log(typeof arr); // object
console.log(typeof reg); // object
console.log(typeof date); // object
console.log(typeof fn); // function
console.log(typeof math); // number
複製代碼
咦咦~着實讓人尷尬啊,這個爲啥那麼多object啊,個人當心髒😔。咱們只是簡單經過typeof
校驗比較尷尬啊,咱們換個思路,咱們來結合call
改變下上下文對象,改寫一個方法進行判斷,以下:
let person = {
name: 'jia ming',
info: 'find a frontend job in Canton!',
};
let arr = ['jia ming', 'find a frontend job in Canton!'];
let reg = new RegExp('jia ming', 'g');
let date = new Date();
function handleType(obj, type) {
if(typeof obj === 'object') {
return Object.prototype.toString.call(obj) === `[object ${type}]`;
}
return false;
}
console.log(handleType(person, 'Object')); // true
console.log(handleType(arr, 'Array')); // true
console.log(handleType(reg, 'RegExp')); // true
console.log(handleType(date, 'Date')); // true
複製代碼
美滋滋,能夠實現區別判斷的哈。但是上面的基本類型中null也是object
啊,而後是Math類型的typeof也是number
啊,這個你能夠本身作下處理啦。這裏就不考慮了~
《JavaScript高級程序設計》