跟小組裡一自稱小方方的賣萌90小青年聊天,IT男的壞習慣,聊著聊著就扯到技術上去了,小方方突然問
1、聲明一個數值類型的變數我看到三種,差異在哪:
var num = 123; //方式一
var num = Number(123);
var num = new Number(123);
2、方式一明明是數字字面量,為毛平常我們可以直接在上面呼叫各種方法,如下:
var num = 123;
console.log(num.toString());
我嘴角微微一笑:少年你還嫩了點,哪止三種,我知道的至少有五種! !
笑著笑著嘴角開始抽搐,額角開始冒出了冷汗:至少有五種,沒錯,但是。 。 。區別在哪。 。 。
懷著老菜鳥特有的矜持和驕傲,我不屑地說:這都不知道,自己查資料去。 。 。轉過身,開始翻ECMAS - 262(第五版)
一、五種宣告數值類型變數的方式
//方式一:最常見的方式,以數字字面量方式宣告
var num = 123;
//方式二:偶爾使用方式,大部分情況下是將字串轉成數字
var num = Number(123);
//方式三:很少使用,各神書,包括犀牛書,都將其列入不推薦方式
var num = new Number(123);
//方式四:神方式,目前還沒見過人使用
var num = new Object(123 );
//方式五:更離奇,更詭異
var num = Object(123);
可以看到,在上5種聲明方式種,方式一不用怎麼說了,平常都是這樣用的;方式三to 方式五屬於比較的使用,下文會分別說明:
1.五種聲明方式的差異?當你用顫巍巍的手指敲下代碼後,究竟發生了神馬?
2.方式一宣告的明明不是對象,但為什麼平常我們可以在上面呼叫方法,如toString等?
二、各種聲明方式之間的區別
方式一:var num = 123;
EC5說明:
A numeric literal stands for a value of the Number type. This value is determined in two steps: first, a mathematical value (MV) is derived from the literal; second, this mathematical value is rounded as described below
//.....個人摘要摘要:
1.解析變數的值,比如說取出整數部分、小數部分等,因為數字宣告方式還可以為num = .123,num = 123e4等形式
2.對解析出來的值取近似值,例如num = 123.33333333333333....,這個時候就要取近似值了,具體取近似則規則不展開
3.此種方式聲明的變量,只是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量,並不是個簡單的數字字面量物件(至於為何可以在上面呼叫toString等方法,後文講解)
方式二:var num = Number(123);
EC5說明:
15.7.1 The Number Constructor Called as a Function
When Number is called as a function rather than as a constructor, it performs a type conversion. 15.7.1.1 Number ( [ value ] )
Returns a Number value (nots) a value (not) turns a Number value)。 by ToNumber(value) if value was supplied, else returns 0.個人總結摘要:
1.這裡只是將Number當作一個普通的函數來調用,而不是構造方法,因此返回的不是對象,而是一個簡單的數值
2.本質與方式一相同;相對於方式一的區別在於,需要針對傳入參數的類型,執行不同的類型轉換過程,試圖將參數解析成對應的數值,具體規則如下:
方式三:var num = new Number(123);
EC5說明:
15.7.2 The Number Constructor
EC5說明:
15.7.2 The Number Constructor The [[Prototype]] internal property of the newdly coned object] prototype object, the one that is the initial value of Number.prototype (15.7.3.1).
The [[Class]] internal property of the newly constructed object is set to "Number".
The [[Primitiveive ]] internal property of the newly constructed object is set to ToNumber(value) if value was
supplied, else to 0.
The [[Extensible]] internal property of the newly constructed object s.總結摘要:
1.此處將Number作用構造方法調用,返回的是Number類型的對象,該對象能夠訪問Number的原型屬性以及方法;這樣說可能有些迷惑,後面會說到
程式碼如下:
var num = new Number(123);
var num = new Number(123);
cons.log( typeof num); //輸出:object console.log(Object.prototype.toString.call(num)); //輸出:[object Number]
3.傳回的Number型別物件內部的原始值( [[PrimitiveValue]]),為經過型別轉換後所得的數字值,具體轉換規則與方式二所提及的一致
方式四:var num = new Object(123);
EC5說明:
15.2.2 The Object Constructor
When Object is called as part of a new expression, it is a constructor that called as part of a new expression, it is a constructor that may create an object.
15.2.2.1 new Object ( [ value ] )
When the Object constructor is called with no arguments or with one argument value, the following steps are taken:Imm ue. supplied, then
a. If Type(value) is Object, then
1.If the value is a native ECMAScript object, do not create a new object but simply return value.
b. If Type(value) is String, return Tovalue). c. If Type(value) is Boolean, return ToObject(value).
d. If Type(value) is Number, return ToObject(value).
2.Assert: The argument value was not supplied or its type was Null or Undefined.
3.Let obj be a newly created native ECMAScript object.
4.Set the [[Prototype]] internal property of obj to the standard built-in Object prototype object 4. ).
5.Set the [[Class]] internal property of obj to "Object".
6.Set the [[Extensible]] internal property of obj to true.
7.Set all the internal methods of obj as specified in 8.12.
8.Return obj.
個人理解說明
:
上面new Object(param) 這種方式宣告變量,根據傳入參數具體類型的不同,得到的結果也會有區別,比如說資料型態。這裡面具體轉換的規則,可以忽略不計,我們只看我們目前關係的部分,即上面標紅色的文字,要點有: 1.傳遞了參數,且參數是一個數字,則創建並返回一個Number型的物件- 沒錯,其實等同於方式三2.此Number物件的值等於傳入的參數,內部的[[prototype]]屬性指向Number.prototype
方式五:var num = Object(123);
EC5說明:
15.2.1 The Object Constructor Called as a Function
When Object is called as a function rather than as a constructor, it performs a type conversion. 15.2.1.1 Object ( [ value ] )
When the Object function is called with no arguments or with one argument value, the following steps are taken:
1.If value is null, value is null and defun return a new Object object exactly as if the standard built-in Object constructor had been called with the same arguments (15.2.2.1).
2.Return ToObject(value).
:
1.當傳入的參數為空、undefined或null時,等同於new Object(param),param為用戶傳入的參數
2.否則,傳回一個對象,至於具體轉換成的物件類型,請參考下表;具體到上面的例子,本質等同於new Number(123):
3. 簡單測試用例
複製程式碼
程式碼如下: var num = Object(123); console.log(typeof num); //輸出:objectect console.log(Object.prototype.toString.call(num)); //輸出:[object Number]
三、var num = 123; 與var num = new Number( 123)
;
各位先賢哲們告誡我們最好用第一種方式,理由成分,擲地有聲:效率低,eval(num)的時候可能有意外的情況發生。 。 。巴拉巴拉
拋開上面的雜音,我們這裡要關注的是,為什麼下面的語句不會出錯:
複製代碼
程式碼如下: var num = 123; console.log(num.toString(num)); //輸出:'123',竟然沒出錯
不是說字面量方式聲明的只是普通的數值類型,不是物件嗎?但不是物件哪來的toString方法調用,這不科學!
好吧,查了下犀牛書,找到了答案:
當用戶通過字面量聲明一個變量,並在該變量上調用如toString等方法,JS腳本引擎會偷偷地創建該變數對應的包裝對象,並在該對像上調用對應的方法;當調用結束,則銷毀該對象;這個過程對於用戶來說是不可見的,因此不少初學者會有這方面的困惑。
好吧,我承認上面這段話並不是原文內容,只是個人對犀牛書對應段落的理解,為了顯得更加專業權威故意加了引用標識。 。 。上面舉的例子,可以簡單看作下面過程:
var num = 123;
var tmp = num;
num = new Number(num);
console.log(num.toString(num));
num = tmp;
(因為昨晚翻規範翻到快1點,實在睏的不行,就偷懶了,相信犀牛書不會坑我)
四、寫在後面 Javascript的變數聲明方式、類型判斷等,一直都覺得無力吐槽,上面的內容對於初學者來說,無異於毀三觀;即使對於像本人這樣已經跟Javascript廝守了兩年多的老菜鳥,常常也被弄得稀里糊塗
簡單總結一下:
1.方式一、方式二本質相同
2.方式三、方式四、方式五本質相同
最後的最後:
文中範例如有錯漏,請指出;如覺得文章對您有用,可點選「推薦」 :)