在回答園子問題的時候發現了很多新東西,寫下來分享一下 ==javascript
下面的圖就是此篇的概覽,另外文章的解釋不包括ES6新增的Symbol,話說這貨有包裝類型,可是不能new...html
基於JS是面向對象的,因此咱們稱呼function爲「方法」,等同於「函數」。java
1.Number與Number Object ——原始類型與包裝類型(primitive VS wrapper object)git
ECMAScript定義了7種數據類型:6種原始類型(ES6新增Symbol)以及Object。原始類型(primitive)不是對象,包裝類型對象(wrapper object)屬於Object的範疇,除了null和undefined原始類型都有對應的包裝類型,咱們不談Symbol(分明是不夠理解 ==):github
● String
for the string primitive.web
● Number
for the number primitive.算法
● Boolean
for the boolean primitive.express
● Symbol
for the symbol primitive.編程
原始類型不是對象而且沒有方法,爲何"test".length怎麼可使用,不是原始類型沒有方法嗎?這裏有個機制:http://es5.github.io/#x10.4.3(step 3 的ToObject是核心),下文會提到,瞭解更多傳送門 -> Does javascript autobox?瀏覽器
2.類型檢測
JS檢測數據類型的方式有不少,這裏主要說三種:typeof、instanceof、Object.prototype.toString。
[1].typeof:主要用於原始類型的檢測,可檢測原始類型、方法/函數、對象,遵循(出於兼容考慮,直到ES6調用 typeof null 仍然返回object):
類型 | 結構 |
---|---|
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
String | "string" |
Symbol (ECMAScript 6 新增) | "symbol" |
宿主對象(JS環境提供的,好比瀏覽器) | Implementation-dependent |
函數對象 (implements [[Call]] in ECMA-262 terms) | "function" |
任何其餘對象 | "object" |
[2].instanceof:主要用於檢測自定義對象,用來判斷某個構造方法/構造函數(右側)的prototype屬性所指向的對象是否存在於另一個要檢測對象(左側)的原型鏈上。額外補點說明:1.跨Frame/多窗口間不要用instanceof檢測類型(能夠用[3].Object.prototype.toString);2.instanceof的結果不是一成不變的,它可能會受到徹底重寫prototype的影響:
1 function Func(){} 2 3 var f1 = new Func(); 4 console.log('---------- f1 ---------------'); 5 console.log(f1 instanceof Func); 6 console.log(f1.__proto__); 7 console.log(f1.constructor); 8 9 console.log('----- Func原型被重寫後的f1 -----'); 10 Func.prototype = {}; 11 12 console.log(f1 instanceof Func); 13 console.log(f1.__proto__); // 重寫prototype不影響已建立對象,對象的[[prototype]]在函數對象構造時已經肯定 -> http://es5.github.io/#x13.2.2 14 console.log(f1.constructor); 15 16 17 console.log('---------- f2 ---------------'); 18 19 var f2 = new Func(); 20 console.log(f2 instanceof Func); 21 console.log(f2.__proto__); 22 console.log(f2.constructor); 23 24 console.warn('因此咱們應當避免徹底重寫,推薦在prototype上擴展');
[3].Object.prototype.toString.apply() / Object.prototype.toString.call():
ES5對Object.prototype.toString的描述對照中文以下:
15.2.4.2 Object.prototype.toString ( )
在toString方法被調用時,會執行下面的操做步驟:
- 若是this的值爲undefined,則返回
"[object Undefined]"
.- 若是this的值爲null,則返回
"[object Null]"
.- 讓O成爲調用ToObject(this)的結果.
- 讓class成爲O的內部屬性[[Class]]的值.
- 返回三個字符串"[object ", class, 以及 "]"鏈接後的新字符串
.
注意上面step 3 ToObject,因此不要試圖用方法[3]判斷原始類型,no zuo no die ( why you try )。
幾種類型判斷的使用場景,試試看:
1 var primitive_number = 1; 2 var numberObj = new Number(1); 3 4 console.log(typeof primitive_number); // typeof適用於原始類型,primitive_number是原始類型number 5 console.log(typeof numberObj); // numberObj是object類型 6 7 8 console.log(primitive_number instanceof Object); 9 console.log(numberObj instanceof Object); // instanceof適用於對象類型/自定義對象類型 10 11 console.log(primitive_number instanceof Number); 12 console.log(numberObj instanceof Number); // instanceof適用於對象類型/自定義對象類型 13 14 console.log(Object.prototype.toString.apply(primitive_number)); // 問題出現了,此方法不要對原始類型調用 15 console.log(Object.prototype.toString.apply(numberObj));
3.構造函數不僅用來建立對象
對各類包裝類型對象(wrapper object)來講,不一樣的方式(是否使用new操做符)調用構造方法將會返回不一樣的結果。
在ES5 Constructor Properties of the Global Object(構造器(類)屬性的全局對象,好比Object、Function、Array、String、Boolean、Number、Date、RegExp、Error... )的規範中,每一小節都有專門描述兩種方式調用構造函數的返回結果:
● The Xxx Constructor Called as a Function [未使用new操做符]
(像調用普通函數同樣調用構造函數:會執行類型轉換並返回ToXxx(value)後的值)
● The Xxx Constructor [使用new操做符]
(當使用new 構造函數方式調用:實例化新建立的對象)
拿Number Objects來舉個栗子:
15.7 Number Objects
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 (not a Number object) computed by ToNumber(value) if value was supplied, else returns +0.
15.7.2 The Number Constructor
When
Number
is called as part of anew
expression it is a constructor: it initialises the newly created object.
Boolean、String的描述也是相似的,對Number、Boolean、String來講:在調用他們的構造函數時,使用了new操做符將會返回對象(不出意外),不然執行相應的類型轉換後返回結果。類型轉換是什麼?就是規範中提到的ToBoolean(value)、ToNumber(value)、ToString(value),值得注意的是,這些ToXxx方法的返回結果都是原始類型。
對應規範,咱們看看Number(value) 與 new Number(value)分別作了什麼:
Number(value):
new Number(value):
Number.prototype(The Number prototype object is itself a Number object (its [[Class]] is "Number") whose value is +0.);
Number
;如今咱們能夠確定的說:Number(value)返回Number原始類型,new Number(value)返回對象。
4.偷樑換柱? →_→ 都是ToObject乾的!
運行下面代碼,看看你在瀏覽器控制檯看到了什麼:
1 var obj = Object(3); 2 console.log(obj instanceof Number); 3 console.log(obj.__proto__); 4 console.log(Object.prototype.toString.apply(obj));
欸,發生了什麼?看看Object(value)幹了些啥:
15.2 Object Objects # Ⓣ Ⓡ
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.當以方法形式而不是構造函數形式(沒用new操做符)調用Object時,會執行類型轉換。
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:調用Object函數時當無參或者參數個數爲1時:
If value is null, undefined or not supplied, create and 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). 若是value是未提供或者是null、undefined,用相同參數建立一個標準的內建Object。
Return ToObject(value).
15.2.2 The Object Constructor # Ⓣ
When
Object
is called as part of anew
expression, it is a constructor that may create an object.當以new 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:調用Object函數時當無參或者參數個數爲1時:
If value is supplied, then 若是提供了value參數
If Type(value) is Object, then 若是參數是object類型
If the value is a native ECMAScript object, do not create a new object but simply return value. 若是參數是本地對象,返回原對象。
If the value is a host object, then actions are taken and a result is returned in an implementation-dependent manner that may depend on the host object. 若是參數是宿主對象,返回結果依賴於宿主對象。
Asset: The argument value was not supplied or its type was Null or Undefined.
Let obj be a newly created native ECMAScript object.
Set the [[Prototype]] internal property of obj t to the standard built-in Object prototype object (15.2.4).
Set the [[Class]] internal property of obj to
"Object"
.Set the [[Extensible]] internal property of obj to true.
Set the all the internal methods of obj as specified in 8.12
Return obj.
Object(3)和new Object(3)的返回結果是同樣的,來看new Object(3):咱們提供了參數3所以進入step 1,Type(3)返回Number類型,所以執行ToObject(3)。ToObject依照下表返回結果,因此咱們拿到了一個Number Object:
5.捆綁在相等性判斷上的類型比較
ES2015/ES6定義了四種相等性判斷算法: Abstract Equality Comparison(==
)、Strict Equality Comparison (===,嚴格相等
)、SameValueZero(零值相等)、SameValue(同值相等)。兩等號判斷在比較時進行類型轉換,三等號判斷不會轉換類型,零值相等認爲+0和-0相等,同值相等用於JS引擎內部、相似三等號判斷、區別在於對部分數值類型(NaN、+0、-0)比較處理方式不一樣。
JS提供了三種值(相等)比較運算符:loose equality(==
)、strict equality(===,嚴格相等
)、Object.is
(ES6新增);
關於JS的相等性判斷,MDN已經描述的很清楚了(仍是中文版)~ JavaScript 中的相等性判斷
在各類比較方式中都大量用到了一個東西:Type(x),這貨是幹嗎的?其實就是typeof x(Within this specification, the notation 「Type(x)」 is used as shorthand for 「the type of x」 where 「type」 refers to the ECMAScript language and specification types defined in this clause.),也就是用來檢測數據類型的(7種數據類型=6種原始類型+Object)。
來看看ES5規範是如何描述兩等號比較的算法部分的:
11.9.3 The Abstract Equality Comparison Algorithm # Ⓣ
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
If Type(x) is the same as Type(y), then
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.Return false.
再來看看三等號比較的算法部分:
11.9.6 The Strict Equality Comparison Algorithm # Ⓣ
The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
尼瑪,這就是在不停的拿類型比較啊有木有。從這也能看出來爲何推薦使用嚴格相等(===
),它沒有隱式轉換而且判斷步驟少得多。
這裏也體現了非嚴格相等(==
)用了兩種形式的類型轉換:
有了規範的說明,咱們就能夠這麼解釋兩個object類型的變量用兩等號比較爲何返回false:類型相同,進入step 1 -> 若是是Undefined、Null,返回true -> 不是Number、String、Boolean(object怎麼多是原始類型),繼續 -> 是同一個對象的引用?返回true;不然,只能返回false了。若是使用三等號判斷,直接到了step 7...
6.回到問題
● Number(3) 與 new Number(3)
1.依據上面兩等號比較的算法部分,上面剛解釋new Number(3)==3,而Number(3)將返回number原始類型的3,由於因此...new Number(3) == Number(3)
2.依據上面三等號比較的算法部分,第一步就返回false了(一個是原始類型,另外一個是object).... 因此new Number(3) !== Number(3)
● Object(3) 與 Object(3)
1.兩等號判斷,好吧,Object(3) => new Number(3),緣由見上文ToObject。兩個object類型的變量用兩等號比較爲何返回false。(見上問)
2.若是使用三等號判斷,直接到了step 7。(見上)
● new Number(3) 與 Object(3)
Object(3) => new Number(3),解釋同上。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
參考:
[1].ES5規範:http://es5.github.io/
[2].ES5規範官網:http://www.ecma-international.org/ecma-262/5.1/
[4].JavaScript的相等性判斷:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness
[5].JavaScript:Object.prototype.toString方法的原理:http://www.cnblogs.com/ziyunfei/archive/2012/11/05/2754156.html
[6].JavaScript面向對象編程(5)重寫prototype形成的混亂:http://blog.csdn.net/zhengwei223/article/details/41785881
[7].重寫prototype原型後哪些東西改變了:http://www.cnblogs.com/web-coding/p/4723381.html