最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

js實(shí)現(xiàn)JSON.stringify的方法實(shí)例代碼

 更新時(shí)間:2026年03月06日 08:15:39   作者:zhengzhengwang  
在大廠的前端面試過(guò)程中,JSON.Stringify常常被問(wèn)到,那么能夠熟練的運(yùn)用,掌握就必不可少,下面這篇文章主要介紹了js實(shí)現(xiàn)JSON.stringify的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

實(shí)現(xiàn)一個(gè)自定義的 JSON.stringify 函數(shù),并詳細(xì)解釋其實(shí)現(xiàn)原理和邊界情況處理。

1. 基礎(chǔ)版本實(shí)現(xiàn)

function myJSONStringify(data) {
    // 處理基本類型
    if (typeof data === 'string') {
        return `"${data}"`;
    }
    
    if (typeof data === 'number' || typeof data === 'boolean') {
        return String(data);
    }
    
    if (data === null) {
        return 'null';
    }
    
    if (data === undefined || typeof data === 'function' || typeof data === 'symbol') {
        return undefined; // 這些類型在對(duì)象中會(huì)被忽略,在數(shù)組中會(huì)轉(zhuǎn)為null
    }
    
    // 處理數(shù)組
    if (Array.isArray(data)) {
        const arrValues = data.map(item => {
            const value = myJSONStringify(item);
            return value === undefined ? 'null' : value;
        });
        return `[${arrValues.join(',')}]`;
    }
    
    // 處理普通對(duì)象
    if (typeof data === 'object') {
        // 處理循環(huán)引用
        if (hasCircularReference(data)) {
            throw new TypeError('Converting circular structure to JSON');
        }
        
        const keys = Object.keys(data);
        const objValues = keys.map(key => {
            const value = myJSONStringify(data[key]);
            // 忽略值為 undefined、函數(shù)、symbol 的屬性
            if (value === undefined) {
                return null;
            }
            return `"${key}":${value}`;
        }).filter(item => item !== null);
        
        return `{${objValues.join(',')}}`;
    }
}

2. 完整的增強(qiáng)版本

class JSONStringify {
    constructor() {
        this.cache = new Set(); // 用于檢測(cè)循環(huán)引用
    }
    
    stringify(data) {
        this.cache.clear();
        return this._stringify(data);
    }
    
    _stringify(data) {
        // 處理基本類型
        if (typeof data === 'string') {
            return this._escapeString(data);
        }
        
        if (typeof data === 'number') {
            // 處理特殊數(shù)值
            if (Number.isNaN(data) || !Number.isFinite(data)) {
                return 'null';
            }
            return String(data);
        }
        
        if (typeof data === 'boolean') {
            return String(data);
        }
        
        if (data === null) {
            return 'null';
        }
        
        if (data === undefined || typeof data === 'function' || typeof data === 'symbol') {
            return undefined;
        }
        
        // 處理 BigInt (JSON.stringify 會(huì)報(bào)錯(cuò))
        if (typeof data === 'bigint') {
            throw new TypeError('Do not know how to serialize a BigInt');
        }
        
        // 檢查循環(huán)引用
        if (this.cache.has(data)) {
            throw new TypeError('Converting circular structure to JSON');
        }
        this.cache.add(data);
        
        // 處理 Date 對(duì)象
        if (data instanceof Date) {
            return `"${data.toISOString()}"`;
        }
        
        // 處理 RegExp 對(duì)象
        if (data instanceof RegExp) {
            return '{}';
        }
        
        // 處理數(shù)組
        if (Array.isArray(data)) {
            const result = this._stringifyArray(data);
            this.cache.delete(data);
            return result;
        }
        
        // 處理普通對(duì)象
        if (typeof data === 'object') {
            const result = this._stringifyObject(data);
            this.cache.delete(data);
            return result;
        }
    }
    
    _stringifyArray(arr) {
        const values = arr.map((item, index) => {
            // 處理數(shù)組中的空位
            if (index in arr) {
                const value = this._stringify(item);
                return value === undefined ? 'null' : value;
            }
            return 'null'; // 數(shù)組空位轉(zhuǎn)為 null
        });
        
        return `[${values.join(',')}]`;
    }
    
    _stringifyObject(obj) {
        const keys = Object.keys(obj);
        const pairs = [];
        
        for (const key of keys) {
            // 處理 Symbol 鍵(JSON.stringify 會(huì)忽略 Symbol 鍵)
            if (typeof key === 'symbol') {
                continue;
            }
            
            const value = this._stringify(obj[key]);
            
            // 忽略值為 undefined、function、symbol 的屬性
            if (value !== undefined) {
                pairs.push(`"${this._escapeString(key)}":${value}`);
            }
        }
        
        // 處理 toJSON 方法
        if (obj.toJSON && typeof obj.toJSON === 'function') {
            const jsonValue = obj.toJSON();
            if (jsonValue !== undefined) {
                return this._stringify(jsonValue);
            }
        }
        
        return `{${pairs.join(',')}}`;
    }
    
    _escapeString(str) {
        // 處理特殊字符
        const escapeMap = {
            '"': '\\"',
            '\\': '\\\\',
            '\b': '\\b',
            '\f': '\\f',
            '\n': '\\n',
            '\r': '\\r',
            '\t': '\\t'
        };
        
        return str.replace(/["\\\b\f\n\r\t]/g, match => escapeMap[match]);
    }
}

// 循環(huán)引用檢測(cè)函數(shù)
function hasCircularReference(obj, seen = new Set()) {
    if (obj === null || typeof obj !== 'object') {
        return false;
    }
    
    if (seen.has(obj)) {
        return true;
    }
    
    seen.add(obj);
    
    if (Array.isArray(obj)) {
        for (const item of obj) {
            if (hasCircularReference(item, seen)) {
                return true;
            }
        }
    } else {
        for (const key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (hasCircularReference(obj[key], seen)) {
                    return true;
                }
            }
        }
    }
    
    seen.delete(obj);
    return false;
}

3. 處理 replacer 參數(shù)

function myJSONStringifyWithReplacer(data, replacer, space) {
    const jsonStringify = new JSONStringify();
    
    // 處理 replacer 參數(shù)
    if (replacer) {
        if (typeof replacer === 'function') {
            return _stringifyWithFunctionReplacer(data, replacer, space);
        } else if (Array.isArray(replacer)) {
            return _stringifyWithArrayReplacer(data, replacer, space);
        }
    }
    
    // 處理 space 參數(shù)
    const result = jsonStringify.stringify(data);
    if (space !== undefined) {
        return _formatWithSpace(result, space);
    }
    
    return result;
}

function _stringifyWithFunctionReplacer(data, replacer, space) {
    const seen = new Set();
    
    function stringify(value, key) {
        // 處理循環(huán)引用
        if (value !== null && typeof value === 'object') {
            if (seen.has(value)) {
                throw new TypeError('Converting circular structure to JSON');
            }
            seen.add(value);
        }
        
        // 應(yīng)用 replacer 函數(shù)
        const replacedValue = replacer.call(data, key, value);
        
        let result;
        if (typeof replacedValue === 'string') {
            result = `"${replacedValue}"`;
        } else if (typeof replacedValue === 'number' || typeof replacedValue === 'boolean') {
            result = String(replacedValue);
        } else if (replacedValue === null) {
            result = 'null';
        } else if (Array.isArray(replacedValue)) {
            result = '[' + replacedValue.map((item, index) => 
                stringify(item, String(index))).join(',') + ']';
        } else if (typeof replacedValue === 'object') {
            const keys = Object.keys(replacedValue);
            const pairs = keys.map(k => {
                const val = stringify(replacedValue[k], k);
                return `"${k}":${val}`;
            });
            result = '{' + pairs.join(',') + '}';
        } else {
            result = undefined;
        }
        
        if (value !== null && typeof value === 'object') {
            seen.delete(value);
        }
        
        return result;
    }
    
    return stringify(data, '');
}

function _stringifyWithArrayReplacer(data, replacer, space) {
    const replacerSet = new Set(replacer);
    
    function filterObject(obj) {
        if (Array.isArray(obj)) {
            return obj.map(item => 
                item !== null && typeof item === 'object' ? filterObject(item) : item
            );
        }
        
        if (obj !== null && typeof obj === 'object') {
            const filtered = {};
            for (const key in obj) {
                if (replacerSet.has(key)) {
                    filtered[key] = obj[key];
                }
            }
            return filtered;
        }
        
        return obj;
    }
    
    const filteredData = filterObject(data);
    const jsonStringify = new JSONStringify();
    const result = jsonStringify.stringify(filteredData);
    
    if (space !== undefined) {
        return _formatWithSpace(result, space);
    }
    
    return result;
}

4. 處理 space 參數(shù)(格式化)

function _formatWithSpace(jsonStr, space) {
    if (space === 0) return jsonStr;
    
    let indentLevel = 0;
    let formatted = '';
    let inString = false;
    
    // 確定縮進(jìn)字符串
    const indentStr = typeof space === 'number' 
        ? ' '.repeat(Math.min(space, 10))
        : space.slice(0, 10);
    
    for (let i = 0; i < jsonStr.length; i++) {
        const char = jsonStr[i];
        
        if (char === '"' && jsonStr[i - 1] !== '\\') {
            inString = !inString;
            formatted += char;
            continue;
        }
        
        if (inString) {
            formatted += char;
            continue;
        }
        
        switch (char) {
            case '{':
            case '[':
                formatted += char + '\n' + indentStr.repeat(++indentLevel);
                break;
                
            case '}':
            case ']':
                formatted += '\n' + indentStr.repeat(--indentLevel) + char;
                break;
                
            case ',':
                formatted += ',\n' + indentStr.repeat(indentLevel);
                break;
                
            case ':':
                formatted += ': ';
                break;
                
            default:
                formatted += char;
        }
    }
    
    return formatted;
}

5. 使用示例

// 測(cè)試數(shù)據(jù)
const testData = {
    name: "張三",
    age: 25,
    isStudent: true,
    hobbies: ["讀書", "游泳", null],
    address: {
        city: "北京",
        district: "朝陽(yáng)區(qū)"
    },
    birthday: new Date('2000-01-01'),
    empty: null,
    undef: undefined,      // 會(huì)被忽略
    func: function() {},   // 會(huì)被忽略
    [Symbol('id')]: 123    // 會(huì)被忽略
};

// 創(chuàng)建循環(huán)引用
testData.self = testData;

// 測(cè)試
try {
    console.log("普通對(duì)象:", myJSONStringify(testData));
} catch (e) {
    console.log("循環(huán)引用錯(cuò)誤:", e.message);
}

// 移除循環(huán)引用后測(cè)試
delete testData.self;

console.log("普通對(duì)象:", myJSONStringify(testData));
console.log("原生 JSON.stringify:", JSON.stringify(testData));

// 測(cè)試 replacer 函數(shù)
const jsonWithReplacer = myJSONStringifyWithReplacer(
    testData,
    (key, value) => {
        if (key === 'password') return undefined;
        if (typeof value === 'string') return value.toUpperCase();
        return value;
    }
);
console.log("帶 replacer:", jsonWithReplacer);

// 測(cè)試格式化輸出
console.log("格式化輸出:", myJSONStringifyWithReplacer(testData, null, 2));

6. 特性對(duì)比

特性原生 JSON.stringify我們的實(shí)現(xiàn)
基本類型轉(zhuǎn)換??
數(shù)組處理??
對(duì)象處理??
循環(huán)引用檢測(cè)??
Date 對(duì)象??
RegExp 對(duì)象{}{}
toJSON 方法??
replacer 函數(shù)??
replacer 數(shù)組??
space 格式化??
Symbol 鍵忽略忽略
undefined 值忽略/轉(zhuǎn)為 null忽略/轉(zhuǎn)為 null
BigInt報(bào)錯(cuò)報(bào)錯(cuò)

這個(gè)實(shí)現(xiàn)涵蓋了 JSON.stringify 的主要特性,包括:

  • 基本類型轉(zhuǎn)換

  • 對(duì)象和數(shù)組的遞歸處理

  • 循環(huán)引用檢測(cè)

  • 特殊類型處理(Date、RegExp)

  • replacer 參數(shù)支持

  • space 格式化支持

總結(jié) 

到此這篇關(guān)于js實(shí)現(xiàn)JSON.stringify的文章就介紹到這了,更多相關(guān)js實(shí)現(xiàn)JSON.stringify內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • webpack配置文件外置的兩種實(shí)現(xiàn)方式

    webpack配置文件外置的兩種實(shí)現(xiàn)方式

    webpack配置環(huán)境變量文件,是根據(jù)打包命令尋找對(duì)應(yīng)的環(huán)境變量文件,從而獲取接口地址,本文就來(lái)介紹一下webpack配置文件外置的兩種實(shí)現(xiàn)方式,感興趣的可以了解一下
    2023-12-12
  • 七個(gè)很有意思的PHP函數(shù)

    七個(gè)很有意思的PHP函數(shù)

    這篇文章主要介紹了七個(gè)很有意思的PHP函數(shù),這些函數(shù)鮮為人知,但很實(shí)用,需要的朋友可以參考下
    2014-05-05
  • JS簡(jiǎn)單驗(yàn)證上傳文件類型的方法

    JS簡(jiǎn)單驗(yàn)證上傳文件類型的方法

    這篇文章主要介紹了JS簡(jiǎn)單驗(yàn)證上傳文件類型的方法,涉及javascript文件遍歷及字符串截取、匹配等相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • CSS中position屬性之fixed實(shí)現(xiàn)div居中

    CSS中position屬性之fixed實(shí)現(xiàn)div居中

    這篇文章主要介紹了CSS中position屬性之fixed實(shí)現(xiàn)div居中的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • JS右下角廣告窗口代碼(可收縮、展開及關(guān)閉)

    JS右下角廣告窗口代碼(可收縮、展開及關(guān)閉)

    這篇文章主要介紹了JS右下角廣告窗口代碼,具有浮動(dòng)顯示、可收縮、展開及關(guān)閉等功能,涉及javascript針對(duì)頁(yè)面元素屬性操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • 關(guān)于uniApp editor微信滑動(dòng)問(wèn)題

    關(guān)于uniApp editor微信滑動(dòng)問(wèn)題

    這篇文章主要介紹了關(guān)于uniApp editor微信滑動(dòng)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • JavaScript插件的開發(fā)、使用與優(yōu)化技巧

    JavaScript插件的開發(fā)、使用與優(yōu)化技巧

    “JS插件”是指使用JavaScript編寫的網(wǎng)頁(yè)增強(qiáng)組件,用于添加特定功能如表單驗(yàn)證、圖片輪播等,本文可能探討了JS插件的開發(fā)、使用和優(yōu)化技巧,并涉及了內(nèi)部實(shí)現(xiàn)和閱讀源碼的學(xué)習(xí)方法
    2025-08-08
  • 阻止移動(dòng)端touchmove與scroll事件沖突技巧

    阻止移動(dòng)端touchmove與scroll事件沖突技巧

    這篇文章主要為大家介紹了阻止移動(dòng)端touchmove與scroll事件沖突技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • JS腳本根據(jù)手機(jī)瀏覽器類型跳轉(zhuǎn)WAP手機(jī)網(wǎng)站(兩種方式)

    JS腳本根據(jù)手機(jī)瀏覽器類型跳轉(zhuǎn)WAP手機(jī)網(wǎng)站(兩種方式)

    隨著移動(dòng)互聯(lián)網(wǎng)的不斷普及,企業(yè)的網(wǎng)絡(luò)宣傳不僅只局限在PC端,還要在移動(dòng)端發(fā)展。我們?cè)谧约旱木W(wǎng)站做了WAP手機(jī)完整之后,如果有用戶通過(guò)手機(jī)訪問(wèn)我們的企業(yè)頂級(jí)域名網(wǎng)站,就要判斷跳轉(zhuǎn)到專為的WAP網(wǎng)站,下面小編給大家整理有關(guān)手機(jī)瀏覽器跳轉(zhuǎn)WAP手機(jī)網(wǎng)站的相關(guān)內(nèi)容
    2015-08-08
  • js在Firefox與IE中對(duì)DOM對(duì)像的引用的比較

    js在Firefox與IE中對(duì)DOM對(duì)像的引用的比較

    直接用ID屬性進(jìn)行引用 直接用NAME屬性進(jìn)行引用 使用getElementById(),getElementsByName(),getElementsByTagName()進(jìn)行引用
    2009-06-06

最新評(píng)論

安阳市| 连江县| 正镶白旗| 克山县| 莆田市| 武夷山市| 上饶市| 邢台市| 根河市| 仁化县| 日土县| 高阳县| 曲靖市| 鸡东县| 织金县| 南通市| 忻城县| 乌苏市| 新巴尔虎右旗| 新巴尔虎左旗| 台安县| 晴隆县| 安陆市| 辉县市| 布尔津县| 长岭县| 金阳县| 南川市| 襄垣县| 漳平市| 本溪市| 当阳市| 宁德市| 五河县| 迁西县| 陆川县| 鸡东县| 如皋市| 昌邑市| 沽源县| 通渭县|