前面兩章介紹了幾大數據類型以及值類型,接下來的這個知識點,我以爲它對於javascript程序員來講是很重要的,javascript
在開始以前,咱們先看一個例子,以便以後更輕鬆的理解封裝對象的概念。java
"tick".toUpperCase //function toUpperCase() String.prototype.toUpperCase //function toUpperCase() "tick".toUpperCase === String.prototype.toUpperCase //true // 這裏使用恆等比較判斷 常量的方法是否和Sting構造函數中的方法爲同一個.
咱們先來閱讀如下幾條知識點,以避免對下文作出更好的理解。程序員
經過直接量的方式訪問方法或屬性,這種值咱們稱之爲常量方式
例如上面的第一行代碼。es6
在JavaScript中對象類型包括:對象,數組,函數
這三種子類型,咱們一般有兩種術語,引用類型 複合值
,引用類型值在作恆等
比較時比較的是他們內存指向
,便是否引用同一個值.web
javascript對象是一種複合值,它是屬性或已命名值的集合,經過.
符號來讀取屬性值。json
經過上面的代碼咱們能夠看到,在使用常量方式訪問某個方法時,依然會返回其
數據類型對應的內置構造函數方法
,上面的第三點已經說了,javascript經過.
操做符來訪問屬性或方法,但是常量
真的是對象嗎?它在訪問屬性的過程當中底發生了什麼?別急,跟隨個人腳步,下面我會不遺餘力把我知道的,個人觀點通通都說出來.數組
在JavaScript中全部複合類型
(如:對象,數組,函數)都包含一個內部屬性[[calss]]
,此屬性能夠看做是一個內部分類。它並非傳統面向對象上的類,因爲是內部屬性,因此咱們沒法直接訪問,不過,能夠轉換爲字符串來查看.瀏覽器
Object.prototype.toString.call([1,2,3]) // '[Object Array]' Object.prototype.toString.call(/^[1,2]$/) // '[Object RegExp]'
這裏補充一點,咱們也能夠經過此種方式去判斷一個對象是否爲數組。安全
咱們看到每一個不一樣的常量類型
中的[[class]],都對應着它們相應的內部構造函數
,也就是對象的內部[[Class]]屬性和建立該對象的內建原生構造函數相對應,但有些特例
.性能優化
//一說特例,我估計就有人想到javascript中比較蛋疼的兩個類型 Object.prototype.toString.call(null) // '[Object Null]' Object.prototype.toString.call(undefined) // '[Object Undefined]'
除了null和undefined,其餘都是javascript的內置構造函數。這裏再次說一個小細節,Infinity
和NaN
它們返回什麼呢?我想不用說你們也能夠猜到了,它們都屬於Number類型.
Object.prototype.toString.call(42) // '[Object Number]' Object.prototype.toString.call("42") // '[Object String]' Object.prototype.toString.call(true) // '[Object Boolean]'
上面的例子除了null和undefined,它們都有各自的構造類,這些類是javascript內置的.
在平常開發中,咱們一般不直接使用內置的構造類,而是直接經過常量訪問.
var arr = new String("1234") arr // {0:"1",1:"2",2:"3",3:"4"}
經過構造函數實例出來的常量變成了對象,其實就是手動建立其封裝對象,封裝對象上存在對應的數據類型方法。咱們在使用常量的方式直接訪問屬性和方法時,javascript會自動爲你包裝一個封裝對象,至關於上面咱們手動包裝在操做屬性或方法完成以後JavaScript也會釋放當前封裝對象
說到這裏,咱們可能會想到一個問題,若是須要常常用到這些字符串的屬性和方法,好比在for循環當中使用i<a.length,那麼一開始建立一個封裝對象也許更爲方便,這樣JavaScript引擎就不用每次都自動建立和自動釋放循環執行這些操做了。
其實咱們的想法很好,但實際證實這並非一個好辦法,由於瀏覽器已經爲.length這樣常見狀況作了性能優化,直接使用封裝對象來提早優化
代碼反而會下降執行效率
。
通常狀況下,咱們不須要直接使用封裝對象,最好是讓JavaScript引擎自動選擇何時應該使用封裝對象,換句話說,就是應該優先考慮使用'abc'和42這樣的原始類型值,而非new String(‘abc’)和new Number(42)
看以下代碼,思考它們的執行結果:
var test = 'abc'; test.len = 123; var t = test.len;
此處t爲undefined
,第三行是經過新的原始對象訪問其.len
屬性,這並非上次添加的.len
,上次的已經被銷燬,當前是一個新的封裝對象.
說了這麼多的理論與例子,不如咱們從頭至尾來整理一下,經過基礎類型值訪問屬性過程當中,到底發生了什麼。
var s = 'hello world'; var world = s.toUpperCase();
咱們就以它爲例:
首先javascript會講字符串值經過new String(s)的方式轉換爲封裝對象
,這個對象繼承了來自字符串構造函數的全部方法(這些操做都從第二行訪問方法時開始發生),當前s已經變成了一個封裝對象
,接下來在封裝對象中查找須要的方法或屬性,找到了以後作出相應的操做.一旦引用結束,這個新建立的對象就會銷燬。這時候s.toUpperCase已經運行了該方法,隨即銷燬封裝對象。
想要等到封裝對象中基本類型值,咱們可使用valueOf方法獲取。
var ss = new String("123"); ss.valueOf() //"123"
javascipt 在須要用到封裝對象中基本類型值時,會發生自動轉換,即隱式強制類型轉換
var t = new String("123"); t+""; "123"
javascript原始值(undefined null 字符串 數字 布爾)是不可修改的
,而對象是能夠被引用和修改的
.講值類型那章時咱們說過JavaScript變量沒有所謂的類型而言,衡量類型的是值,即值類型
,在原始值上,咱們沒法更改,任何方法都沒法更改一個原始值,這對於數字自己就說不通,怎麼更改數字自己呢?可是對於字符串來講,看似有點說得通
由於它像是經過字符組成的數組,咱們能夠指望經過指定的索引來修改其字符元素,但javascript並不容許這麼作。字符串方法看上去返回了修改後的值,其實返回的是一個新字符串,與以前的沒有任何關係.
封裝對象與類型轉換有很大關聯,咱們只有弄懂封裝對象的概念,才能更好的理解類型轉換,還有以後的相等比較與恆等比較。
var num = 123; //1 num.toString(); // "123" //2 num + ""; //"123"
上面兩種方式,第一種咱們稱爲顯示強制類型轉換
.第二種稱之爲隱式強制類型轉換
。類型轉換老是返回基本類型值
,不會返回對象類型,
第一個,num.toString()時,把num常量經過內部[[class]]生成臨時的封裝對象,再調用對象toString方法,返回轉換完成的字符串.
第二個,因爲+運算符的其中一個操做數是字符串,因此是字符串拼接操做,結果是數字123被轉換成「123」。
介紹強制與隱式類型轉換時,咱們須要掌握對字符串數字和布爾類型的轉換規則。
基本類型的轉換規則爲,undefined -> 「undefined」, null->"null",true->"true",數字則使用通用規則,若是有極大或極小的值則使用指數形式.
var num = 1.37 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 num.toString() //"1.37e+21"
普通對象除非自定義,不然它會返回對象內部的[[Class]]屬性.
var obj = {}; obj.toString() //"[object Object]"
數組的toStirng有些特殊,它是經過","鏈接的字符串.
var arr = [1,2,3,4]; arr.toString(); // "1,2,3,4"
這裏捎帶講一下json字符串化.
JSON.stringify在將JSON對象序列化爲字符串時也使用了toString方法,但須要注意的是JSON.stringify並不是嚴格意義上的強制類型轉換,只是涉及toString的相關規則.
var num = 123; var str = 「123」; JSON.stringify(num) //「123」 JSON.stringify(str) // 「」123」」 //兩個引號
全部安全的JSON值均可以使用JSON.stringify序列化,那麼, 何爲不安全的值?例如: undefined,function,Symbol(es6新增),若是JSON中出現這些值,序列化時不能把它們識別,就把他們變成了null。
JSON.stringify([1,undefined,function(){}]) //"[1,null,null]"
若是對象定義了toJSON方法,會先調用此方法,而後用它的返回值來進行序列化。
var obj = {name:"Jack"} obj.toJSON = function(){ return {name:」Join"} } JSON.stringify(obj) // 「{「name」:」Join"}"
在序列化以前,會先調用對象的toJSON方法,以它的返回值來進行序列化.默認對象是沒有此屬性的,若是有須要能夠手動添加。
toJSON返回的不是一個通過JSON字符串化後的值,它應該是一個適當
的值,也就是沒有通過任何處理的值.固然,它應該被返回一個能夠被JSON化的值.
var ob = { val : [1,2,3], toJSON : function(){ return this.val.slice(2) } } var obj = { val : [1,2,3], toJSON: function(){ return this.val.slice(1).join() } } JSON.stringify(ob) //「[2,3]" JSON.stringify(obj) //「」2,3」」 雙引號
以上咱們講JSON字符串化徹底是toString捎帶出來的,它和toString很類似,可是卻還有些不一樣。既然上面已經講了些,咱們不妨再來看看它的幾個參數.
不少開發者在使用JSON字符串化時候,只使用了第一個參數,其實它是有三個參數的。
咱們先來看第一個參數和第二參數.
var obj = { a:42, b:」42", c:[1,2,3] } JSON.stringify(obj,function(k,v){ if(k !== "c" ) return v })
第一個參數不用多介紹了吧,主要是第二個參數,它有兩個參數,和map的參數正好相反,也有filter方法的那點意思,在JSON字符串化中指定哪些屬性應該被處理.
等等,這裏有個小細節,以上第二個回調參數實際上比我預想的多執行了一次,假設以上爲例,三個屬性,它第一次爲undefined,第二次纔是屬性a。這是爲何呢?由於它在處理時,obj也計入其中了。
第三個參數是縮進的字符,若是它是一個數字,就表明縮進多少空格符。若是是字符串,則固定以它爲縮進符號。
var obj = { a:42, b:」42」, c:[1,2,3] } JSON.stringify(obj,function(k,v){ if(k !==「c」) return v },」---") //"{ //----"a": 42, //----"b": "42」 //}"
在編輯代碼時,因爲編輯器緣由,引號的格式很很差把握,因此你們在複製代碼運行時可能會出錯,需檢查引號是否爲中文格式.
有時候咱們須要將非數字類型當作數字來使用,好比說數字運算
其中true轉1,false轉換爲,null轉換爲0,undefined轉換爲NaN
toNumber時如不能轉換爲數字類型就會返回NaN,它對以0開頭的數字並非以16進制來處理,而是10進制
var str = 「123」; str - 0; //123 Number(str) //123
字符串轉爲number很簡單,這裏不作介紹。讓咱們來看一下複合類型是如何轉換爲Number類型的
.
認真讀下面這句話:
爲了將值轉化爲基本類型值,抽象操做ToPrimite(參見ES5規範9.1節)會首先(經過內部操做DefaultValue)檢查該值是否具備valueOf()方法,若是有就返回基本類型值,並使用該值進行強制類型轉換
,若是沒有就使用toString()的返回值來進行強制轉換.`若是valueOf()和toString()均不返回基本類型值,則會產生TypeError錯誤
var obj = { valueOf:function(){ return "42" } } var obj_1 = { toString:function(){ return "42" } } var arr = [1,2,3] arr.toString = function(){ return this.join(「") } //「123" Number(obj) //42 Number(obj_1) //42 Number(arr) // 123
關於布爾值,咱們存在許多誤解和困惑,須要咱們特別注意.
javascript中有兩個關鍵詞true和false,分別表明布爾類型中的真和假,咱們常誤認覺得數值1和0分別等同於true和false,在有些語言中多是這樣,但在javascript中布爾值和數字時不同的,雖然咱們能夠將1強制類型轉換爲true,將0強制轉換爲false,反之亦然,但他們並非一回事.
咱們能夠把他們分爲兩類
(1) 能夠被強制轉換爲false的值
(2) 其餘(被強制類型轉換爲true的值)
假值
JavaScript規範具體定義了一小撮能夠被強制類型轉換爲false的值。
如下是一些假值:
undefined
null
false
+0 -0 和 NaN
「」
假值的布爾強制類型轉換結果爲false.
雖然javascript規範沒有明確指出除了假值之外都是真值,但咱們能夠暫時理解爲假值之外的值都是真值
。
假值對象不是假值
var bool = new Boolean(false); var number = new Number(0); var string = new String(「0」);
這些都是假值封裝後的對象
,讓咱們來用複合條件來判斷一下.
var a = new Boolean( bool && number && string ); a //true
咱們都知道web端的javascript依賴兩個環境,javascript語言引擎,與宿主環境,宿主環境包括 DOM BOM,咱們爲何說起它們呢?
由於document裏面有一個類數組對象它會被轉換爲false,它包含了頁面中全部的元素。
var dom = document.all; Boolean( dom ) //false
真值
var a = 「false」 var b = 「0」 var c = 「‘'" Boolean( a && b && c ) // true
上例的字符串看似假值,但全部字符串都是真值,不過」」除外,由於它是假值列表中的惟一字符串.
真值列表能夠無限長,沒法一一列舉,因此咱們以假值做爲參考。
真值有不少,能夠無限延長,[],function,{} 都是真值。你們能夠用一點時間去控制檯上練習。