You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSON.stringify与replacer异常行为:不同谓词为何结果不同?

问题分析:JSON.stringify替换函数的行为差异

问题场景

以下代码中,两次调用仅谓词函数不同,但第一个调用输出不符合预期,第二个却正常工作,需要解释原因。

原始代码

'use strict'; 

function stringify(value,p) {
    function replacer(k,v) {
        if (!Array.isArray(v))
            return p(k) ? v : undefined;
        return v
    }
    return JSON.stringify(value,replacer);
}

console.log(stringify([{ city: 'Milano', air_quality: 'red', temperature: 10 }, { air_quality: 'yellow', 'temperature': 20, 'sea_conditions': 3, city: 'Genova' }], k => k.match(/^[a-z]+$/)));
console.log(stringify([{ city: 'Milano', air_quality: 'red', temperature: 10 }, { air_quality: 'yellow', 'temperature': 20, 'sea_conditions': 3, city: 'Genova' }], k => k.length < 5));

预期输出

[{"city":"Milano","temperature":10},{"temperature":20,"city":"Genova"}]
[{"city":"Milano"},{"city":"Genova"}]

实际输出

[null,null]
[{"city":"Milano"},{"city":"Genova"}]

可行的替换函数

已知使用以下replacer可得到预期结果:

function replacer(k,v){
    if (typeof v === 'object' && !Array.isArray(v)) {
        let result = {}
        for (let idx in v) {
            if(p(idx)) {
                result[idx] = v[idx]
            }
        }
        return result
    }
    return v
}

原因解析

问题根源在于JSON.stringify替换函数的执行逻辑和第一版replacer的处理逻辑不匹配:

  1. 替换函数的调用时机:JSON.stringify会递归遍历数据结构,处理数组中的对象时,会先调用一次replacer——此时参数k是该对象在数组中的索引(如"0"、"1"),v是对象本身;之后才会遍历对象的每个属性,此时k是属性名(如"city"),v是属性值。

  2. 第一个谓词的致命问题:第一个谓词k => k.match(/^[a-z]+$/)要求k全为小写字母,但数组索引是数字字符串,完全不满足匹配条件。replacer处理对象本身时直接返回undefined,而JSON.stringify遇到返回undefined的情况,会把当前值(整个对象)从结果中剔除,数组元素因此变成null。

  3. 第二个谓词正常工作的原因:第二个谓词k => k.length <5对数组索引"0"、"1"来说,长度为1,满足条件,所以replacer返回对象本身,后续会继续遍历对象属性。处理属性时,k是属性名,比如"city"长度4符合要求被保留,"air_quality"长度11不符合被剔除,最终结果正确。

  4. 正确replacer的逻辑优势:你后来写的replacer遇到非数组对象时,直接遍历对象自身属性,对每个属性名应用谓词并构建新对象返回。这跳过了对对象父级键(数组索引)的判断,直接处理内部属性,自然不会出现整个对象被剔除的问题。

内容的提问来源于stack exchange,提问作者1.1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 13:17:39