丁香狠狠色婷婷久久综合_精品国际久久久久999波多野_国产成人综合久久免费导航_国产欧美另类久久久精品不卡

細節決定成敗,聊聊JS的類型(上)

今天我們來講講JavaScript的內容,在這個部分,我首先想跟你聊一聊類型

今天我們來講講 JavaScript 的內容,在這個部分,我首先想跟你聊一聊類型。


(資料圖片)

JavaScript 類型對每個前端程序員來說,幾乎都是最為熟悉的概念了。但是你真的很了解它們嗎?我們不妨來看看下面的幾個問題。

為什么有的編程規范要求用 void 0 代替 undefined?

字符串有最大長度嗎?0.1 + 0.2 不是等于 0.3 么?為什么 JavaScript 里不是這樣的?

ES6 新加入的 Symbol 是個什么東西?

為什么給對象添加的方法能用在基本類型上?

如果你答起來還有些猶豫的地方,這就說明你對這部分知識點,還是有些遺漏之處的。沒關系,今天我來幫你一一補上。

我在前面提到過,我們的 JavaScript 模塊會從運行時、文法和執行過程三個角度去剖析 JS 的知識體系,本篇我們就從運行時的角度去看 JavaScript 的類型系統。

運行時類型是代碼實際執行過程中我們用到的類型。所有的類型數據都會屬于 7 個類型之一。從變量、參數、返回值到表達式中間結果,任何 JavaScript 代碼運行過程中產生的數據,都具有運行時類型。

類型

JavaScript 語言的每一個值都屬于某一種數據類型。JavaScript 語言規定了 7 種語言類型。語言類型廣泛用于變量、函數參數、表達式、函數返回值等場合。根據最新的語言標準,這 7 種語言類型是:

Undefined;

Null;

Boolean;

String;

Number;

Symbol;

Object。

除了 ES6 中新加入的 Symbol 類型,剩下 6 種類型都是我們日常開發中的老朋友了,但是,要想回答文章一開始的問題,我們需要重新認識一下這些老朋友,下面我們就來從簡單到復雜,重新學習一下這些類型。

Undefined、Null

我們的第一個問題,為什么有的編程規范要求用 void 0 代替 undefined?現在我們就分別來看一下。

Undefined 類型表示未定義,它的類型只有一個值,就是 undefined。任何變量在賦值前是 Undefined 類型、值為 undefined,一般我們可以用全局變量 undefined(就是名為 undefined 的這個變量)來表達這個值,或者 void 運算來把任意一個表達式變成 undefined 值。

但是呢,因為 JavaScript 的代碼 undefined 是一個變量,而并非是一個關鍵字,這是 JavaScript 語言公認的設計失誤之一,所以,我們為了避免無意中被篡改,我建議使用 void 0 來獲取 undefined 值。

Undefined 跟 Null 有一定的表意差別,Null 表示的是:“定義了但是為空”。所以,在實際編程時,我們一般不會把變量賦值為 undefined,這樣可以保證所有值為 undefined 的變量,都是從未賦值的自然狀態。

Null 類型也只有一個值,就是 null,它的語義表示空值,與 undefined 不同,null 是 JavaScript 關鍵字,所以在任何代碼中,你都可以放心用 null 關鍵字來獲取 null 值。

Boolean

Boolean 類型有兩個值, true 和 false,它用于表示邏輯意義上的真和假,同樣有關鍵字 true 和 false 來表示兩個值。這個類型很簡單,我就不做過多介紹了。

String

我們來看看字符串是否有最大長度。

String 用于表示文本數據。String 有最大長度是 2^53 - 1,這在一般開發中都是夠用的,但是有趣的是,這個所謂最大長度,并不完全是你理解中的字符數。

因為 String 的意義并非“字符串”,而是字符串的 UTF16 編碼,我們字符串的操作 charAt、charCodeAt、length 等方法針對的都是 UTF16 編碼。所以,字符串的最大長度,實際上是受字符串的編碼長度影響的。

Note:現行的字符集國際標準,字符是以 Unicode 的方式表示的,每一個 Unicode 的碼點表示一個字符,理論上,Unicode 的范圍是無限的。UTF 是 Unicode 的編碼方式,規定了碼點在計算機中的表示方法,常見的有 UTF16 和 UTF8。 Unicode 的碼點通常用 U+??? 來表示,其中 ??? 是十六進制的碼點值。 0-65536(U+0000 - U+FFFF)的碼點被稱為基本字符區域(BMP)。

JavaScript 中的字符串是永遠無法變更的,一旦字符串構造出來,無法用任何方式改變字符串的內容,所以字符串具有值類型的特征。

JavaScript 字符串把每個 UTF16 單元當作一個字符來處理,所以處理非 BMP(超出 U+0000 - U+FFFF 范圍)的字符時,你應該格外小心。

JavaScript 這個設計繼承自 Java,最新標準中是這樣解釋的,這樣設計是為了“性能和盡可能實現起來簡單”。因為現實中很少用到 BMP 之外的字符。

Number

下面,我們來說說 Number 類型。Number 類型表示我們通常意義上的“數字”。這個數字大致對應數學中的有理數,當然,在計算機中,我們有一定的精度限制。

JavaScript 中的 Number 類型有 18437736874454810627(即 264-253+3) 個值。

JavaScript 中的 Number 類型基本符合 IEEE 754-2008 規定的雙精度浮點數規則,但是 JavaScript 為了表達幾個額外的語言場景(比如不讓除以 0 出錯,而引入了無窮大的概念),規定了幾個例外情況:

NaN,占用了 9007199254740990,這原本是符合 IEEE 規則的數字;

Infinity,無窮大;

-Infinity,負無窮大。

另外,值得注意的是,JavaScript 中有 +0 和 -0,在加法類運算中它們沒有區別,但是除法的場合則需要特別留意區分,“忘記檢測除以 -0,而得到負無窮大”的情況經常會導致錯誤,而區分 +0 和 -0 的方式,正是檢測 1/x 是 Infinity 還是 -Infinity。

根據雙精度浮點數的定義,Number 類型中有效的整數范圍是 -0x1fffffffffffff 至 0x1fffffffffffff,所以 Number 無法精確表示此范圍外的整數。

同樣根據浮點數的定義,非整數的 Number 類型無法用(= 也不行) 來比較,一段著名的代碼,這也正是我們第三題的問題,為什么在 JavaScript 中,0.1+0.2 不能 =0.3:

1console.log(0.1+0.2==0.3);

這里輸出的結果是 false,說明兩邊不相等的,這是浮點運算的特點,也是很多同學疑惑的來源,浮點數運算的精度問題導致等式左右的結果并不是嚴格相等,而是相差了個微小的值。所以實際上,這里錯誤的不是結論,而是比較的方法,正確的比較方法是使用 JavaScript 提供的最小精度值:

console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);

檢查等式左右兩邊差的絕對值是否小于最小精度,才是正確的比較浮點數的方法。這段代碼結果就是 true 了。

Symbol

Symbol 是 ES6 中引入的新類型,它是一切非字符串的對象 key 的集合,在 ES6 規范中,整個對象系統被用 Symbol 重塑。

在后面的文章中,我會詳細敘述 Symbol 跟對象系統。這里我們只介紹 Symbol 類型本身:它有哪些部分,它表示什么意思,以及如何創建 Symbol 類型。

Symbol 可以具有字符串類型的描述,但是即使描述相同,Symbol 也不相等。

我們創建 Symbol 的方式是使用全局的 Symbol 函數。例如:

var mySymbol = Symbol("my symbol");

一些標準中提到的 Symbol,可以在全局的 Symbol 函數的屬性中找到。例如,我們可以使用 Symbol.iterator 來自定義 for…of 在對象上的行為:

var o = new Objecto[Symbol.iterator] = function() {    var v = 0    return {    next: function() {        return { value: v++, done: v > 10 }        }    }};for(var v of o)console.log(v); // 0 1 2 3 ... 9

代碼中我們定義了 iterator 之后,用 for(var v of o) 就可以調用這個函數,然后我們可以根據函數的行為,產生一個 for…of 的行為。

這里我們給對象 o 添加了 Symbol.iterator 屬性,并且按照迭代器的要求定義了一個 0 到 10 的迭代器,之后我們就可以在 for of 中愉快地使用這個 o 對象啦。

這些標準中被稱為“眾所周知”的 Symbol,也構成了語言的一類接口形式。它們允許編寫與語言結合更緊密的 API。

Object

Object 是 JavaScript 中最復雜的類型,也是 JavaScript 的核心機制之一。Object 表示對象的意思,它是一切有形和無形物體的總稱。

下面我們來看一看,為什么給對象添加的方法能用在基本類型上?

在 JavaScript 中,對象的定義是“屬性的集合”。屬性分為數據屬性和訪問器屬性,二者都是 key-value 結構,key 可以是字符串或者 Symbol 類型。

關于對象的機制,后面會有單獨的一篇來講述,這里我重點從類型的角度來介紹對象類型。提到對象,我們必須要提到一個概念:類。

因為 C++ 和 Java 的成功,在這兩門語言中,每個類都是一個類型,二者幾乎等同,以至于很多人常常會把 JavaScript 的“類”與類型混淆。

事實上,JavaScript 中的“類”僅僅是運行時對象的一個私有屬性,而 JavaScript 中是無法自定義類型的。

JavaScript 中的幾個基本類型,都在對象類型中有一個“親戚”。它們是:

Number;

String;

Boolean;

Symbol。

所以,我們必須認識到 3 與 new Number(3) 是完全不同的值,它們一個是 Number 類型, 一個是對象類型。

Number、String 和 Boolean,三個構造器是兩用的,當跟 new 搭配時,它們產生對象,當直接調用時,它們表示強制類型轉換。

Symbol 函數比較特殊,直接用 new 調用它會拋出錯誤,但它仍然是 Symbol 對象的構造器。JavaScript 語言設計上試圖模糊對象和基本類型之間的關系,我們日常代碼可以把對象的方法在基本類型上使用,比如:

console.log("abc".charAt(0)); //a

甚至我們在原型上添加方法,都可以應用于基本類型,比如以下代碼,在 Symbol 原型上添加了 hello 方法,在任何 Symbol 類型變量都可以調用。

Symbol.prototype.hello = () => console.log("hello");var a = Symbol("a");console.log(typeof a); //symbol,a并非對象a.hello(); //hello,有效
1234Symbol.prototype.hello=()=>console.log("hello");vara=Symbol("a");console.log(typeofa);//symbol,a并非對象a.hello();//hello,有效

所以我們文章開頭的問題,答案就是. 運算符提供了裝箱操作,它會根據基礎類型構造一個臨時對象,使得我們能在基礎類型上調用對應對象的方法。

?

更多精彩內容請點:開發者網站代碼查看

?

關鍵詞:
責任編輯:hn1007