摘要:拆封想要等到封裝對象中基本類型值,我們可以使用方法獲取。值類型轉換上面兩種方式,第一種我們稱為顯示強制類型轉換第二種稱之為隱式強制類型轉換。介紹強制與隱式類型轉換時,我們需要掌握對字符串數字和布爾類型的轉換規則。
認識封裝對象前面兩章介紹了幾大數據類型以及值類型,接下來的這個知識點,我覺得它對于javascript程序員來說是很重要的,
在開始之前,我們先看一個例子,以便之后更輕松的理解封裝對象的概念。
"tick".toUpperCase //function toUpperCase() String.prototype.toUpperCase //function toUpperCase() "tick".toUpperCase === String.prototype.toUpperCase //true // 這里使用恒等比較判斷 常量的方法是否和Sting構造函數中的方法為同一個.
我們先來閱讀以下幾條知識點,以免對下文做出更好的理解。
通過直接量的方式訪問方法或屬性,這種值我們稱之為常量方式 例如上面的第一行代碼。
在JavaScript中對象類型包括:對象,數組,函數這三種子類型,我們通常有兩種術語,引用類型 復合值,引用類型值在做恒等比較時比較的是他們內存指向,即是否引用同一個值.
javascript對象是一種復合值,它是屬性或已命名值的集合,通過.符號來讀取屬性值。
內部屬性通過上面的代碼我們可以看到,在使用常量方式訪問某個方法時,依然會返回其數據類型對應的內置構造函數方法,上面的第三點已經說了,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 其實我們的想法很好,但實際證明這并不是一個好辦法,因為瀏覽器已經為.length這樣常見情況做了性能優化,直接使用封裝對象來提前優化代碼反而會降低執行效率。 一般情況下,我們不需要直接使用封裝對象,最好是讓JavaScript引擎自動選擇什么時候應該使用封裝對象,換句話說,就是應該優先考慮使用"abc"和42這樣的原始類型值,而非new String(‘abc’)和new Number(42) 看如下代碼,思考它們的執行結果: 此處t為undefined,第三行是通過新的原始對象訪問其.len屬性,這并不是上次添加的.len,上次的已經被銷毀,當前是一個新的封裝對象. 說了這么多的理論與例子,不如我們從頭到尾來整理一下,通過基礎類型值訪問屬性過程中,到底發生了什么。 我們就以它為例: 想要等到封裝對象中基本類型值,我們可以使用valueOf方法獲取。 javascipt 在需要用到封裝對象中基本類型值時,會發生自動轉換,即隱式強制類型轉換 javascript原始值(undefined null 字符串 數字 布爾)是不可修改的,而對象是可以被引用和修改的.講值類型那章時我們說過JavaScript變量沒有所謂的類型而言,衡量類型的是值,即值類型,在原始值上,我們無法更改,任何方法都無法更改一個原始值,這對于數字本身就說不通,怎么更改數字本身呢?但是對于字符串來說,看似有點說得通因為它像是通過字符組成的數組,我們可以期望通過指定的索引來修改其字符元素,但javascript并不允許這么做。字符串方法看上去返回了修改后的值,其實返回的是一個新字符串,與之前的沒有任何關系. 封裝對象與類型轉換有很大關聯,我們只有弄懂封裝對象的概念,才能更好的理解類型轉換,還有之后的相等比較與恒等比較。 上面兩種方式,第一種我們稱為顯示強制類型轉換.第二種稱之為隱式強制類型轉換。類型轉換總是返回基本類型值,不會返回對象類型, 第一個,num.toString()時,把num常量通過內部[[class]]生成臨時的封裝對象,再調用對象toString方法,返回轉換完成的字符串. 第二個,由于+運算符的其中一個操作數是字符串,所以是字符串拼接操作,結果是數字123被轉換成“123”。 介紹強制與隱式類型轉換時,我們需要掌握對字符串數字和布爾類型的轉換規則。
toString
var test = "abc";
test.len = 123;
var t = test.len;
var s = "hello world";
var world = s.toUpperCase();
首先javascript會講字符串值通過new String(s)的方式轉換為封裝對象,這個對象繼承了來自字符串構造函數的所有方法(這些操作都從第二行訪問方法時開始發生),當前s已經變成了一個封裝對象,接下來在封裝對象中查找需要的方法或屬性,找到了之后做出相應的操作.一旦引用結束,這個新創建的對象就會銷毀。這時候s.toUpperCase已經運行了該方法,隨即銷毀封裝對象。 var ss = new String("123");
ss.valueOf() //"123"
var t = new String("123");
t+""; "123"
不可變的原始值和可變的對象引用
值類型轉換
var num = 123;
//1
num.toString(); // "123"
//2
num + ""; //"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” //}"
在編輯代碼時,由于編輯器原因,引號的格式很不好把握,所以大家在復制代碼運行時可能會出錯,需檢查引號是否為中文格式.
ToNumber
有時候我們需要將非數字類型當做數字來使用,比如說數字運算
其中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
ToBoolean
關于布爾值,我們存在許多誤解和困惑,需要我們特別注意.
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,{} 都是真值。大家可以用一點時間去控制臺上練習。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88248.html
摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們在每天的編寫代碼過程中,無時無刻不在應用著值類型轉換,但是很多時候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉換的內部轉換規則,最近通過閱讀你...
摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們在每天的編寫代碼過程中,無時無刻不在應用著值類型轉換,但是很多時候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉換的內部轉換規則,最近通過閱讀你...
摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們在每天的編寫代碼過程中,無時無刻不在應用著值類型轉換,但是很多時候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉換的內部轉換規則,最近通過閱讀你...
摘要:相對于顯式使用,隱式轉換則更加簡潔。隱式轉換為布爾值將其他類型值隱式轉換為布爾值是我們最常用的一種轉換。在以下場景中,都是進行判斷,而只要傳入的值不是布爾值,都會通過隱式類型轉換轉為布爾值。原文地址阿木木的博客與隱式鴨子類型轉換 showImg(https://segmentfault.com/img/remote/1460000017309581); 前言 說實話,JavaScrip...
閱讀 1371·2023-04-25 16:45
閱讀 1917·2021-11-17 09:33
閱讀 2306·2021-09-27 14:04
閱讀 915·2019-08-30 15:44
閱讀 2633·2019-08-30 14:24
閱讀 3411·2019-08-30 13:59
閱讀 1691·2019-08-29 17:00
閱讀 887·2019-08-29 15:33