js便簽筆記(10) - 分享:json2.js源碼解讀筆記
1. 如何理解“json”
首先應(yīng)該意識(shí)到,json是一種數(shù)據(jù)轉(zhuǎn)換格式,既然是個(gè)“格式”,就是個(gè)抽象的東西。它不是js對(duì)象,也不是字符串,它只是一種格式,一種規(guī)定而已。
這個(gè)格式規(guī)定了如何將js對(duì)象轉(zhuǎn)換成字符串、以及轉(zhuǎn)換成怎樣的字符串——序列化 —— JSON.stringify 接口;
以及如何將一個(gè)有效字符串轉(zhuǎn)換成js對(duì)象——反序列化—— JSON.parse 接口;
2. 關(guān)于作者
json作者是 道格拉斯.克勞福德 ,是一位js大牛,寫過一本《javascript語言精粹》,相信不少朋友都看過。短短200頁書,果然寫出了“精粹”。
3. 瀏覽器支持
W3C已經(jīng)將json接口定義到標(biāo)準(zhǔn)中,目前主流瀏覽器也都默認(rèn)支持json接口。但是還有不少IE6用戶,可得小心。我曾經(jīng)遇到過這樣的bug。
4. valueOf() 的用法
var n1 = 10;
var n2 = new Number(10);
console.log(typeof n1); //number
console.log(typeof n2); //object
console.log(typeof n2.valueOf()); //number
如上代碼,通過valueOf()方法,可以將一個(gè)(Number/String/Boolean)對(duì)象,轉(zhuǎn)換成其對(duì)應(yīng)的基本類型。
在json.stringify方法中,如果遇到一個(gè)屬性值的類型是object時(shí),首先要排除 new Number/String/Boolean(...) 這三種情況,它就是通過valueOf來操作的。
5. 對(duì)特殊字符的處理
json.js源碼中考慮了一些無意義的unicode字符,并且對(duì)他們進(jìn)行了自定義的處理。相關(guān)的正則表達(dá)式如下:
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
這兩個(gè)正則表達(dá)式,分別用在stringify和parse方法中。可以用圖形形象表達(dá)這兩個(gè)正則的內(nèi)容,如下圖:


因此,解讀json.js源碼,還必須了解unicode字符集的基礎(chǔ)知識(shí)。
6. 在遇到Date類型或者Number類型時(shí),都不要忘記用 isFinite()來驗(yàn)證有效性。
7. JSON.parse() 對(duì)傳入字符串的驗(yàn)證
大家用JSON.parse(),而不直接用eval()的原因,就是因?yàn)榍罢呤前踩D(zhuǎn)換。那么這里的“安全”是通過什么來保障的呢?
源碼中通過四步驗(yàn)證來保證。下面是這四步驗(yàn)證,以及我寫的注釋:
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we // 01. 將反斜線格式變?yōu)椤癅”,如把'\\n'變?yōu)?@'
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we // 02. 將簡(jiǎn)單值替換為“]”
// replace all simple value tokens with ']' characters. Third, we delete all // 03. 將“: [”、“, [”替換為空字符串
// open brackets that follow a colon or comma or that begin the text. Finally, // 04. 看剩下的字符串是否只是 whitespace or ']' or ',' or ':' or '{' or '}'
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. // 如果是這樣,那么text就可以安全的被執(zhí)行eval()函數(shù)
if (/^[\],:{}\s]*$/ //只包含 whitespace or ']' or ',' or ':' or '{' or '}'
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') // 例如:'\\n'->'@','\\u4e00'-> '@',而'\n','\u4e00'則不變
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') // 將 "abc"、true、false、null、數(shù)字,替換成“]”
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {...}
8. JSON.stringify(value, replacer, space) 第二個(gè)參數(shù)可以傳偽數(shù)組
大家可能知道第二個(gè)參數(shù)replacer可以傳入function或者Array,但是它也可以傳如一個(gè)偽數(shù)組,模擬傳入Array的情況。偽數(shù)組要這樣寫:
{
0 : 'a',
1 : 'b',
2 : 'x',
length : 3
}
不過注意!瀏覽器中自帶的JSON接口,不一定支持,例如chrome中就不識(shí)別。所以這里要謹(jǐn)慎使用。安全期間還是用標(biāo)準(zhǔn)的Array好一些。
9. 兩個(gè)JS基礎(chǔ)知識(shí)
第一,value 是數(shù)組時(shí),注意 Object.prototype.toString.apply(value) 和 value.toString() 的區(qū)別;
第二,在 for ... in 循環(huán)中,要判斷 Object.prototype.hasOwnProperty.call(value, k)
不解釋,看不明白的需要去翻書。
--------------------------------------------------------------------------
json2.js源碼解讀教程
PetShop4.0源碼解讀
---------------------------------------------------------------------------
10. 總結(jié)
以上是我在解讀json2.js源碼過程中做的一點(diǎn)隨意的筆記,列出來跟大家分享。

浙公網(wǎng)安備 33010602011771號(hào)