jQuery批量选择拼接JSON的正确姿势

页面多选数据提交,原始代码手动拼 JSON 字符串容易出错、引号转义乱、特殊字符炸。正确做法是用对象数组 + JSON.stringify(),自动处理转义。现代框架用数组的 map() 更简洁,jQuery 的 each 也能改成 map。

很多项目都有"批量操作"的需求,比如多选一批用户然后删除、或者多选一批文章然后发布。前端需要收集这些选中的数据然后发给后端。怎么做最简洁不出错?

常见的错误做法

错误做法一:手动拼 JSON 字符串

// ❌ 非常容易出错
let selectedIds = [];
$('input[name="user_id"]:checked').each(function() {
    selectedIds.push(this.value);
});

let jsonString = '{';
jsonString += '"ids": [';
for (let i = 0; i < selectedIds.length; i++) {
    if (i > 0) jsonString += ',';
    jsonString += '"' + selectedIds[i] + '"';  // 如果 id 包含引号呢?
}
jsonString += ']';
jsonString += '}';

console.log(jsonString);  // 可能是 {"ids": ["1","2","3"]}

$.ajax({
    url: '/api/users/delete',
    type: 'POST',
    data: jsonString,
    contentType: 'application/json'
});

这样有几个问题:

  1. 代码冗长且难读:一眼看不出逻辑
  2. 字符转义容易出错:如果 id 包含特殊字符('、"、\n 等),直接拼接会破坏 JSON
  3. 维护困难:改结构时要改好多地方

错误做法二:字符串拼接加转义

// ❌ 试图解决转义问题,但更复杂
let jsonString = '{"ids": [';
for (let i = 0; i < selectedIds.length; i++) {
    if (i > 0) jsonString += ',';
    // 手动转义引号
    let escapedId = selectedIds[i].replace(/\\/g, '\\\\').replace(/"/g, '\\\"');
    jsonString += '"' + escapedId + '"';
}
jsonString += ']}';

这样转义逻辑容易写错,比如上面的转义就不完整(还要处理换行符等)。

正确做法:对象数组 + JSON.stringify()

JavaScript 有内置的 JSON.stringify(),自动处理所有转义问题。

// ✅ 正确做法
let selectedIds = [];
$('input[name="user_id"]:checked').each(function() {
    selectedIds.push(this.value);
});

// 构造对象
let data = {
    ids: selectedIds
};

// 用 JSON.stringify 转换
let jsonString = JSON.stringify(data);
console.log(jsonString);  // {"ids":["1","2","3"]}

// 发送
$.ajax({
    url: '/api/users/delete',
    type: 'POST',
    data: jsonString,
    contentType: 'application/json'
});

JSON.stringify() 会自动处理:

  • 引号转义:" → \"
  • 反斜杠转义:\ → \\
  • 换行符转义:\n → \\n
  • 其他特殊字符(制表符、换行、null 等)

测试一下:

// 包含特殊字符的 ID
let data = {
    ids: ['user\'s id', 'user"quote', 'line\nbreak']
};

let jsonString = JSON.stringify(data);
console.log(jsonString);
// {"ids":["user's id","user\"quote","line\nbreak"]}
// 看起来很规整,JavaScript 会正确处理转义

收集多选数据的最佳实践

场景一:简单的 ID 列表

<label><input type="checkbox" name="user_id" value="1" /> User 1</label>
<label><input type="checkbox" name="user_id" value="2" /> User 2</label>
<label><input type="checkbox" name="user_id" value="3" /> User 3</label>
<button id="delete-btn">删除选中</button>
$('#delete-btn').click(function() {
    let ids = $('input[name="user_id"]:checked').map(function() {
        return this.value;  // 提取 value
    }).get();  // 转换成数组
  
    let data = { ids: ids };
  
    $.ajax({
        url: '/api/users/delete',
        type: 'POST',
        data: JSON.stringify(data),
        contentType: 'application/json',
        success: function(response) {
            console.log('删除成功', response);
        },
        error: function(error) {
            console.error('删除失败', error);
        }
    });
});

注意这里用了 .map() 而不是 .each(),因为 map() 会返回一个数组,更简洁。

场景二:复杂对象列表

有时候需要提交多个字段的数据,不只是 ID。

<table>
    <tbody>
        <tr>
            <td><input type="checkbox" name="items" value="1" data-name="Product A" data-price="100" /></td>
            <td>Product A</td>
            <td>100</td>
        </tr>
        <tr>
            <td><input type="checkbox" name="items" value="2" data-name="Product B" data-price="200" /></td>
            <td>Product B</td>
            <td>200</td>
        </tr>
    </tbody>
</table>
<button id="submit-btn">提交</button>
$('#submit-btn').click(function() {
    let items = $('input[name="items"]:checked').map(function() {
        // 返回对象,包含多个字段
        return {
            id: this.value,
            name: $(this).data('name'),
            price: $(this).data('price')
        };
    }).get();
  
    let data = { items: items };
    console.log(JSON.stringify(data));
    // {"items":[{"id":"1","name":"Product A","price":"100"},{"id":"2","name":"Product B","price":"200"}]}
  
    $.ajax({
        url: '/api/products/submit',
        type: 'POST',
        data: JSON.stringify(data),
        contentType: 'application/json',
        success: function(response) {
            console.log('提交成功', response);
        }
    });
});

场景三:用 jQuery 的 serialize() 方法

JQuery 有内置的 serialize() 方法,能把表单数据转成 URL 编码格式。

<form id="my-form">
    <label><input type="checkbox" name="user_id" value="1" /> User 1</label>
    <label><input type="checkbox" name="user_id" value="2" /> User 2</label>
    <label><input type="checkbox" name="user_id" value="3" /> User 3</label>
    <button type="submit">提交</button>
</form>
$('#my-form').submit(function(e) {
    e.preventDefault();
  
    // serialize() 返回 "user_id=1&user_id=2&user_id=3" 这种格式
    let formData = $(this).serialize();
  
    $.ajax({
        url: '/api/users/submit',
        type: 'POST',
        data: formData,
        success: function(response) {
            console.log('提交成功', response);
        }
    });
});

serialize() 的好处是自动处理转义和特殊字符,缺点是返回的是 URL 编码格式,不是 JSON。如果后端期望 JSON,还要加一层转换。

场景四:用现代 JavaScript(不依赖 jQuery)

// 用原生 JavaScript,不需要 jQuery
let selectedIds = Array.from(
    document.querySelectorAll('input[name="user_id"]:checked')
).map(el => el.value);

let data = { ids: selectedIds };

fetch('/api/users/delete', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)  // fetch 的 body 需要 JSON 字符串
}).then(response => response.json())
  .then(data => console.log('成功', data))
  .catch(error => console.error('失败', error));

或者用 FormData(更现代):

let formData = new FormData();
$('input[name="user_id"]:checked').each(function() {
    formData.append('ids', this.value);  // 多值参数
});

fetch('/api/users/delete', {
    method: 'POST',
    body: formData  // FormData 会自动设置正确的 Content-Type
}).then(response => response.json())
  .then(data => console.log('成功', data));

JSON.stringify() 的高级用法

格式化输出(调试用)

let data = { ids: [1, 2, 3], names: ['Alice', 'Bob'] };

// 紧凑格式(默认)
console.log(JSON.stringify(data));
// {"ids":[1,2,3],"names":["Alice","Bob"]}

// 格式化输出(缩进 2 个空格)
console.log(JSON.stringify(data, null, 2));
// {
//   "ids": [1, 2, 3],
//   "names": ["Alice", "Bob"]
// }

过滤字段

let data = { id: 1, name: 'Alice', password: 'secret123', email: '[email protected]' };

// 只序列化 id 和 name,忽略 password
let jsonString = JSON.stringify(data, ['id', 'name']);
console.log(jsonString);  // {"id":1,"name":"Alice"}

自定义序列化逻辑

let data = { user: { id: 1, name: 'Alice' }, createdAt: new Date() };

let jsonString = JSON.stringify(data, function(key, value) {
    if (value instanceof Date) {
        return value.toISOString();  // 日期转成 ISO 格式
    }
    return value;
});
console.log(jsonString);
// {"user":{"id":1,"name":"Alice"},"createdAt":"2026-10-09T19:00:00.000Z"}

常见陷阱

陷阱一:忘记 .get()

// ❌ jQuery 的 map() 返回 jQuery 对象,不是数组
let ids = $('input[name="user_id"]:checked').map(function() {
    return this.value;
});
console.log(typeof ids);  // object(jQuery 对象)
console.log(ids.length);  // 能访问,但行为不一致

// ✅ 要加 .get() 转换成真正的数组
let ids = $('input[name="user_id"]:checked').map(function() {
    return this.value;
}).get();
console.log(typeof ids);  // object(但真正的数组)
Array.isArray(ids);  // true

陷阱二:对象属性名必须是字符串

// 虽然 JavaScript 允许这样写
let obj = { 1: 'a', 2: 'b' };

// 但 JSON 里属性名必须是字符串
let json = JSON.stringify(obj);
console.log(json);  // {"1":"a","2":"b"}

陷阱三:undefined 和函数无法序列化

let obj = {
    name: 'Alice',
    age: undefined,
    greet: function() { console.log('Hi'); }
};

let json = JSON.stringify(obj);
console.log(json);  // {"name":"Alice"}
// age 和 greet 被忽略了(JSON 不支持这些类型)

小结

批量选择数据提交的正确做法:

  1. 用 .map() 收集数据到数组或对象
  2. 用 JSON.stringify() 转成 JSON 字符串(自动处理转义)
  3. $.ajax 的 data 传 JSON 字符串,contentType 设为 'application/json'

或者用现代 fetch API:

let data = { ids: selectedIds };
fetch('/api/endpoint', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
}).then(r => r.json());

永远不要手动拼 JSON 字符串,那是给自己找麻烦。相信 JSON.stringify(),它会处理好所有转义问题。

更多推荐

章节目录