溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript原始值與包裝對象介紹

發(fā)布時間:2021-09-16 19:56:36 來源:億速云 閱讀:150 作者:chen 欄目:web開發(fā)

這篇文章主要介紹“JavaScript原始值與包裝對象介紹”,在日常操作中,相信很多人在JavaScript原始值與包裝對象介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JavaScript原始值與包裝對象介紹”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

前言

隨著 JavaScript 越來越流行,越來越多地開發(fā)者開始接觸并使用 JavaScript。

同時我也發(fā)現(xiàn),有不少開發(fā)者對于 JavaScript 最基本的原始值和包裝對象都沒有很清晰的理解。

那么本篇文章,就由渣皮來給大家詳細介紹一下它們。

話不多說,Let's go!

正文

原始類型 (Primitive types)

原始類型也被稱為“基本類型”。

目前在 JavaScript 中有以下幾種原始類型:

  • string(字符串)

  • number(數(shù)字)

  • boolean(布爾)

  • null(空)

  • undefined(未定義)

  • bigint(大整數(shù),ES6)

  • symbol(標志?ES6)

如下:

typeof 'chenpipi';  // "string" typeof 12345;       // "number" typeof true;        // "boolean" typeof null;        // "object" typeof undefined;   // "undefined" typeof 12345n;      // "bigint" typeof Symbol();    // "symbol"

特別注意

typeof null 雖然返回 "object",但是這不代表 null 就是對象,這其實是 JavaScript 的一個 Bug,且從  JavaScript 誕生以來便如此。

在 JavaScript 最初的實現(xiàn)中,JavaScript 中的值是由一個表示類型的標簽和實際數(shù)據(jù)值表示的。對象的類型標簽是 0。由于 null  代表的是空指針(大多數(shù)平臺下值為 0x00),因此,null 的類型標簽是 0,typeof null 也因此返回 "object"。

The history of “typeof null”:https://2ality.com/2013/10/typeof-null.html

原始值 (Primitive values)

原始值也就是原始類型的值(數(shù)據(jù))。

A primitive value is data that is not an object and has no methods.

原始值是一種沒有任何方法的非對象數(shù)據(jù)。

也就是說,string、number 和 boolean 等原始類型的值本身是沒有任何屬性和方法的。

這個時候嗅覺敏銳的小伙伴是不是已經(jīng)察覺到有什么不對勁了?

是孜然!我加了孜然!(手動狗頭并劃掉)

這里有一個非常有意思的點,但是在討論這個問題之前,先讓我們認識下包裝對象。

包裝對象 (Wrapper objects)

除了 null 和 undefined 外的原始類型都有其相應的包裝對象:

  • String(字符串)

  • Number(數(shù)字)

  • Boolean(布爾)

  • BigInt(大整數(shù),ES6)

  • Symbol(標志?ES6)

對象 (Object)

對象是引用類型。

首先,包裝對象本身是一個對象,也是函數(shù)。

String instanceof Object;   // true String instanceof Function; // true

構(gòu)造函數(shù) (Constructor)

實例 (Instance)

其中 String、Number 和 Boolean 均支持使用 new 運算符來創(chuàng)建對應的包裝對象實例。

例如 String 的聲明(節(jié)選):

interface StringConstructor {   new(value?: any): String;   (value?: any): string;   readonly prototype: String; } declare var String: StringConstructor;

使用 new 運算符得到的數(shù)據(jù)是對象(Object):

// 字符串 typeof 'pp';                      // "string" typeof new String('pp');          // "object" new String() instanceof Object;   // true // 數(shù)字 typeof 123;                       // "number" typeof new Number(123);           // "object" new Number() instanceof Object;   // true // 布爾 typeof true;                      // "boolean" typeof new Boolean(true);         // "object" new Boolean() instanceof Object;  // true

我們可以調(diào)用包裝對象實例的 valueOf() 函數(shù)來獲取其原始值:

// 字符串 let s = new String('pp'); s.valueOf();                // "pp" typeof s.valueOf();         // "string" // 數(shù)字 let n = new Number(123); n.valueOf();                // 123 typeof n.valueOf();         // "number" // 布爾 let b = new Boolean(true); b.valueOf();                // true typeof b.valueOf();         // "boolean"

“異類” (Attention)

而 BigInt 和 Symbol 都屬于“不完整的類”,不支持 new 運算符。

例如 BigInt 的聲明(節(jié)選):

interface BigIntConstructor {   (value?: any): bigint;   readonly prototype: BigInt; } declare var BigInt: BigIntConstructor;

可以看到 BigInt 的聲明中沒有 new 運算符相關(guān)函數(shù)。

普通函數(shù) (Function)

包裝對象也可以作為普通函數(shù)來使用。

其中 String()、Number() 和 Boolean() 函數(shù)都可以用來對任意類型的數(shù)據(jù)進行顯式類型轉(zhuǎn)換。

另外 Object() 函數(shù)也可用于顯式類型轉(zhuǎn)換,但本文不再展開。

String

示例代碼:

typeof String();    // "string" String();           // "" String('pp');       // "pp" String(123);        // "123" String(true);       // "true" String(false);      // "false" String(null);       // "null" String(undefined);  // "undefined" String([]);         // "" String({});         // "[object Object]"

小貼士 1

當我們使用 String() 函數(shù)來轉(zhuǎn)換對象時,JavaScript 會先訪問對象上的 toString()  函數(shù),如果沒有實現(xiàn),則會順著原型鏈向上查找。

舉個栗子:執(zhí)行 String({ toString() { return 'pp'; } }) 返回的結(jié)果是 "pp",并非 "[object  Object]"。

所以 String() 函數(shù)并不能夠用來判斷一個值是否為對象(會翻車)。

小貼士 2

常用的判斷對象的方式為 Object.prototype.toString({}) === '[object Object]'。

舉個栗子:執(zhí)行 Object.prototype.toString({ toString() { return 'pp'; } }) 返回的是  "[object Object]"。

Number

示例代碼:

typeof Number();    // "number" Number();           // 0 Number('');         // 0 Number('pp');       // NaN Number(123);        // 123 Number(true);       // 1 Number(false);      // 0 Number(null);       // 0 Number(undefined);  // NaN Number([]);         // 0 Number({});         // NaN

小貼士

對于 Number() 函數(shù)來說,可能最實用的轉(zhuǎn)換就是將 true 和 false 轉(zhuǎn)換為 1 和 0 吧。

Boolean

示例代碼:

typeof Boolean();   // "boolean" Boolean();          // false Boolean('');        // false Boolean('pp');      // true Boolean(0);         // false Boolean(1);         // true Boolean(null);      // false Boolean(undefined); // false Boolean([]);        // true Boolean({});        // true

小貼士

某些情況下,我們會在數(shù)據(jù)中使用 0 和 1 來表示真假狀態(tài),此時就可以使用 Boolean() 進行狀態(tài)的判斷。

BigInt

BigInt() 函數(shù)用于將整數(shù)轉(zhuǎn)換為大整數(shù)。

該函數(shù)接受一個整數(shù)作為參數(shù),傳入?yún)?shù)若為浮點數(shù)或任何非數(shù)字類型數(shù)據(jù)都會報錯。

示例代碼:

BigInt(123);        // 123n BigInt(123n);       // 123n typeof 123n;        // "bigint" typeof BigInt(123); // "bigint"

BigInt & Number

需要注意的是,BigInt 和 Number 是不嚴格相等(寬松相等)的。

示例代碼:

123n === 123; // false 123n == 123;  // true

Symbol

Symbol() 函數(shù)用于創(chuàng)建一個 symbol 類型的值。

該函數(shù)接受一個字符串作為描述符(參數(shù)),如果傳入其他類型的值則會被轉(zhuǎn)換為字符串(除了 undefined)。

注意,每一個 symbol 值都是獨一無二的,即使它們的描述符都是一樣的。

且 symbol 類型的數(shù)據(jù)只能通過 Symbol() 函數(shù)來創(chuàng)建。

示例代碼:

// 后面的返回值是 Devtools 模擬出來的,并非實際值 Symbol('pp');                   // Symbol(pp) Symbol(123);                    // Symbol(123) Symbol(null);                   // Symbol(null) Symbol({});                     // Symbol([object Object])  // 類型 typeof Symbol('pp');            // "symbol" Symbol('pp') === Symbol('pp');  // false  // 描述符 Symbol('pp').description;       // "pp" Symbol(123).description;        // "123" Symbol({}).description;         // "[object Object]" Symbol().description;           // undefined Symbol(undefined).description;  // undefined

原始值不是對象 (Primitive not Object)

有意思的來了~

沒有屬性和方法 (No properties, no functions)

本文前面有提到:「原始值是一種沒有任何方法的非對象數(shù)據(jù)?!?/p>

我們都知道對象(Object)上可以有屬性和方法。

但是字符串不是對象,所以你不能給字符串增加屬性。

做個小實驗:

let a = 'chenpipi'; console.log(a.length);  // 8 // 嘗試增加新的屬性 a.name = '吳彥祖'; console.log(a.name);    // undefined // 嘗試修改已有的屬性 typeof a.slice;         // "function" a.slice = null; typeof a.slice;         // "function"

渣皮小劇場

此時一位頭鐵的小伙伴使用了反駁技能。

渣皮你別在這忽悠人了,我平時寫 Bug 哦不寫代碼的時候明明可以調(diào)用到字符串、數(shù)字和布爾值上的方法!

比如下面這段代碼,能夠正常執(zhí)行并得到符合預期的結(jié)果:

// 字符串 let s = 'chenpipi'; s.toUpperCase();      // "CHENPIPI" 'ChenPiPi'.slice(4);  // "PiPi" // 數(shù)字 let n = 123; n.toString();         // "123" (123.45).toFixed(2);  // "123.5" // 布爾值 let b = true; b.toString();         // "true" false.toString();     // "false"

無用小知識

有沒有發(fā)現(xiàn),數(shù)字的字面量后面不能直接調(diào)用函數(shù)?例如執(zhí)行 123.toString() 會報 SyntaxError(語法錯誤)。

這是因為數(shù)字(浮點數(shù))本身會用到小數(shù)點 .,而調(diào)用函數(shù)也需要用小數(shù)點,這時就出現(xiàn)了歧義(字符串和布爾值就沒有這種煩惱)。

對于這種情況,我們可以使用括號 () 將數(shù)字包裹起來,如 (123).toString();或者使用兩個連續(xù)的小數(shù)點 .. 來調(diào)用函數(shù),如  123..toString()。

 奇了怪了

那么既然字符串不是對象,那么為什么字符串會有屬性和方法呢?

轉(zhuǎn)念一想,數(shù)字就是數(shù)字,數(shù)字身上怎么會有方法呢?

這確實不符合邏輯,但是這又與實際相矛盾。

咋回事呢???

替身使者 (I can't translate this)

答案揭曉~

 暗中操作

以字符串(string)為例,當我們在代碼中讀取字符串的屬性或者方法時, JavaScript 會靜默地執(zhí)行下面的操作:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 將字符串通過 new String() 的方式來創(chuàng)建一個臨時的包裝對象實例;

  3. 通過創(chuàng)建的對象來執(zhí)行我們的代碼邏輯(讀取屬性或執(zhí)行函數(shù));

  4. 臨時對象不再使用,可以被銷毀。

如下面的栗子:

let a = 'chenpipi'; console.log(a);   // "chenpipi" // ------------------------------ let b1 = a.length; console.log(b1);  // 8 // 上面的代碼相當于: let b2 = (new String(a)).length; console.log(b2);  // 8 // ------------------------------ let c1 = a.toUpperCase(); console.log(c1);  // "CHENPIPI" // 上面的代碼相當于: let c2 = (new String(a)).toUpperCase(); console.log(c2);  // "CHENPIPI"

數(shù)字(number)和布爾值(boolean)同理,但數(shù)字通過 new Number() 來創(chuàng)建臨時對象,而布爾值則通過 new Boolean()  來創(chuàng)建。

除了上面的例子,最有力的證明,就是他們的構(gòu)造函數(shù):

'chenpipi'.constructor === String;  // true (12345).constructor === Number;     // true true.constructor === Boolean;       // true

這一切都是 JavaScript 在暗中完成的,且過程中產(chǎn)生的臨時對象都是一次性的(用完就丟)。

原來如此

蕪湖,這么一來就說得通了!

這也就能解釋為什么我們能夠訪問字符串上的屬性和方法,卻不能增加或修改屬性。

那是因為我們實際操作的目標其實是 JavaScript 創(chuàng)建的臨時對象,而并非字符串本身!

所以我們的增加或修改操作實際上是生效了的,只不過是在臨時對象上生效了!

就像這樣:

// 代碼中: let a = 'chenpipi'; a.name = '吳彥祖'; console.log(a.name);  // undefined  // 相當于: let a = 'chenpipi'; (new String(a)).name = '吳彥祖'; console.log(a.name);  // undefined  // 相當于: let a = 'chenpipi'; let temp = new String(a); temp.name = '吳彥祖'; console.log(a.name);  // undefined

到此,關(guān)于“JavaScript原始值與包裝對象介紹”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI