Escape、encodeURI、encodeURIComponent 编码函数详解
Escape、encodeURI、encodeURIComponent:JavaScript 编码函数详解
在 Web 开发中,正确处理 URL 和特殊字符至关重要。JavaScript 提供了三个主要函数用于编码:escape()、encodeURI() 和 encodeURIComponent()。让我们深入探讨它们的作用、区别以及最佳实践。
核心区别对比表
| 特性 | escape() |
encodeURI() |
encodeURIComponent() |
|---|---|---|---|
| 是否废弃 | 是 | 否 | 否 |
| 保留字符 | A-Z a-z 0-9 * @ - _ + . / |
A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # |
A-Z a-z 0-9 - _ . ! ~ * ' ( ) |
| 编码结果 | %XX 或 %uXXXX |
%XX |
%XX |
| 使用场景 | 不应使用 | 完整 URL | URL 参数值 |
| 解码函数 | unescape() |
decodeURI() |
decodeURIComponent() |
详细分析与示例
1. escape() - 已废弃的函数
// 示例
console.log(escape("Hello World!")); // "Hello%20World%21"
console.log(escape("测试")); // "%u6D4B%u8BD5" (Unicode 转义)
console.log(escape("email@example.com")); // "email@example.com"
console.log(escape("/path/to/file")); // "/path/to/file" (斜杠未编码)
特点:
- 已从 ECMAScript 标准中移除,不应在新项目中使用
- 对 ASCII 字母数字和
* @ - _ + . /不编码 - 空格转为
%20 - 其他字符转为
%XX或%uXXXX格式 - 不适用于 URL 编码,因为未正确处理 URI 保留字符
2. encodeURI() - 用于完整 URL
// 示例
const url = "https://example.com/路径/文件.html?query=值#片段";
console.log(encodeURI(url));
// "https://example.com/%E8%B7%AF%E5%BE%84/%E6%96%87%E4%BB%B6.html?query=%E5%80%BC#%E7%89%87%E6%AE%B5"
特点:
- 设计用于编码整个 URI
- 保留 URI 完整结构(协议、主机、路径、查询参数分隔符等)
- 不编码:
A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # - 编码非 ASCII 字符(如中文)和空格
- 不会破坏 URL 结构
3. encodeURIComponent() - 用于 URL 组件
// 示例
const paramValue = "name=John&Doe&age=30";
console.log(encodeURIComponent(paramValue));
// "name%3DJohn%26Doe%26age%3D30"
const fullURL = `https://example.com/search?q=${encodeURIComponent("咖啡 & 茶")}`;
console.log(fullURL);
// "https://example.com/search?q=%E5%92%96%E5%95%A1%20%26%20%E8%8C%B6"
特点:
- 设计用于编码 URI 组件(查询参数、路径片段等)
- 编码所有非标准字符,包括
?,=,&,#等保留字符 - 不编码:
A-Z a-z 0-9 - _ . ! ~ * ' ( ) - 确保组件值不会破坏 URL 结构
- 适用于 Cookie 值、表单数据等需要严格编码的场景
何时使用哪个函数?
✅ 推荐使用场景
// 场景1:构建完整URL(使用 encodeURI)
const baseURL = "https://example.com/用户资料/我的文档.html";
const safeURL = encodeURI(baseURL);
console.log(safeURL);
// "https://example.com/%E7%94%A8%E6%88%B7%E8%B5%84%E6%96%99/%E6%88%91%E7%9A%84%E6%96%87%E6%A1%A3.html"
// 场景2:编码查询参数值(使用 encodeURIComponent)
const query = "search&sort=desc";
const apiUrl = `https://api.example.com/data?q=${encodeURIComponent(query)}`;
console.log(apiUrl);
// "https://api.example.com/data?q=search%26sort%3Ddesc"
// 场景3:编码特殊值
const cookieValue = "user=123; session=abc";
document.cookie = `data=${encodeURIComponent(cookieValue)}`;
❌ 避免使用的场景
// 错误1:使用 escape() 编码URL
const badURL = escape("https://example.com/测试?q=a&b");
console.log(badURL);
// "https%3A//example.com/%u6D4B%u8BD5%3Fq%3Da%26b" - 破坏了协议部分
// 错误2:使用 encodeURI() 编码查询参数
const unsafeParam = encodeURI("a=1&b=2");
const badAPI = `https://api.example.com?params=${unsafeParam}`;
console.log(badAPI);
// "https://api.example.com?params=a=1&b=2" - & 字符未被编码,会解析为两个参数
// 错误3:混合使用
const mixed = encodeURI("path/") + encodeURIComponent("file?name=test");
console.log(mixed);
// "path/file%3Fname%3Dtest" - 路径结构被破坏
关键结论
-
escape()已废弃 - 不应在新代码中使用,仅存在于旧浏览器中用于向后兼容 -
encodeURI()用于完整 URL:- 保留 URL 结构(
:,/,?,&,=等) - 编码路径中的特殊字符和空格
- 不编码查询参数中的保留字符
- 保留 URL 结构(
-
encodeURIComponent()用于 URL 组件:- 编码所有特殊字符,包括保留字符
- 适用于查询参数值、路径片段等
- 确保组件值不会破坏 URL 结构
-
最佳实践:
// 构建安全URL的推荐方法 function buildURL(base, path, queryParams) { const encodedPath = encodeURI(path); const queryString = Object.entries(queryParams) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}` ) .join('&'); return `${base}/${encodedPath}?${queryString}`; } // 示例用法 const url = buildURL('https://api.example.com', 'user/profile', { id: '123#test', name: 'John & Jane' }); console.log(url); // "https://api.example.com/user/profile?id=123%23test&name=John%20%26%20Jane"
记住这些函数的区别和正确用法,可以避免 URL 解析错误、安全问题(如注入攻击)和跨浏览器兼容性问题。在现代 Web 开发中,始终优先使用 encodeURI() 和 encodeURIComponent(),并完全避免使用 escape()。
可视化对比工具
https://www.quanxiaoha.com/tools/url-decode
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>URL编码函数对比工具</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
color: #333;
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
overflow: hidden;
padding: 30px;
}
header {
text-align: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
h1 {
font-size: 2.5rem;
color: #1a2a6c;
margin-bottom: 10px;
}
.subtitle {
color: #555;
font-size: 1.2rem;
max-width: 800px;
margin: 0 auto;
line-height: 1.6;
}
.input-section {
background: #f8f9fa;
border-radius: 10px;
padding: 25px;
margin-bottom: 30px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
}
.input-group {
display: flex;
gap: 15px;
margin-bottom: 20px;
}
input {
flex: 1;
padding: 15px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 1.1rem;
transition: all 0.3s;
}
input:focus {
outline: none;
border-color: #4a6fcb;
box-shadow: 0 0 0 3px rgba(74, 111, 203, 0.2);
}
button {
background: #4a6fcb;
color: white;
border: none;
border-radius: 8px;
padding: 0 25px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
button:hover {
background: #3a5bb0;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.presets {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.preset-btn {
background: #e9ecef;
border: none;
border-radius: 20px;
padding: 8px 15px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s;
}
.preset-btn:hover {
background: #dde2e6;
transform: translateY(-1px);
}
.results-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.result-card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.3s;
border: 1px solid #eee;
}
.result-card:hover {
transform: translateY(-5px);
}
.card-header {
padding: 20px;
color: white;
display: flex;
align-items: center;
gap: 12px;
}
.card-header i {
font-size: 1.8rem;
}
.escape .card-header { background: #dc3545; }
.uri .card-header { background: #0d6efd; }
.component .card-header { background: #198754; }
.card-body {
padding: 25px;
min-height: 250px;
display: flex;
flex-direction: column;
}
.result-content {
background: #f8f9fa;
border-radius: 8px;
padding: 15px;
flex-grow: 1;
font-family: 'Courier New', monospace;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
margin-bottom: 20px;
}
.info-box {
background: #e9f7ef;
border-left: 4px solid #198754;
padding: 12px 15px;
border-radius: 4px;
font-size: 0.95rem;
margin-top: auto;
}
.warning-box {
background: #fce8e6;
border-left: 4px solid #dc3545;
padding: 12px 15px;
border-radius: 4px;
font-size: 0.95rem;
}
.comparison-section {
background: #f8f9fa;
border-radius: 10px;
padding: 25px;
margin-top: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #dee2e6;
}
th {
background-color: #e9ecef;
font-weight: 600;
}
tr:hover {
background-color: rgba(0, 0, 0, 0.02);
}
.check {
color: #198754;
font-weight: bold;
}
.cross {
color: #dc3545;
font-weight: bold;
}
footer {
text-align: center;
margin-top: 30px;
padding-top: 20px;
color: #6c757d;
font-size: 0.9rem;
border-top: 1px solid #eee;
}
@media (max-width: 768px) {
.input-group {
flex-direction: column;
}
button {
padding: 15px;
}
.results-container {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-link"></i> URL编码函数对比工具</h1>
<p class="subtitle">直观比较JavaScript中escape(), encodeURI()和encodeURIComponent()三种编码函数的行为和区别</p>
</header>
<section class="input-section">
<div class="input-group">
<input type="text" id="inputText" value="https://example.com/路径?q=搜索&sort=desc#section" placeholder="输入要编码的文本...">
<button id="encodeBtn"><i class="fas fa-code"></i> 编码文本</button>
</div>
<h3>预设示例:</h3>
<div class="presets">
<button class="preset-btn" data-value="Hello World!">Hello World!</button>
<button class="preset-btn" data-value="name=John Doe&age=30">查询参数</button>
<button class="preset-btn" data-value="中文/测试">中文字符</button>
<button class="preset-btn" data-value="email@example.com">邮箱地址</button>
<button class="preset-btn" data-value="符号: !@#$%^&*()">特殊符号</button>
</div>
</section>
<div class="results-container">
<div class="result-card escape">
<div class="card-header">
<i class="fas fa-exclamation-triangle"></i>
<h2>escape()</h2>
</div>
<div class="card-body">
<h3>编码结果:</h3>
<div class="result-content" id="escapeResult">等待输入...</div>
<div class="warning-box">
<i class="fas fa-exclamation-circle"></i> 警告:此函数已被弃用,不应用于新项目。它不会对 "+" 字符进行编码,可能会导致问题。
</div>
</div>
</div>
<div class="result-card uri">
<div class="card-header">
<i class="fas fa-globe"></i>
<h2>encodeURI()</h2>
</div>
<div class="card-body">
<h3>编码结果:</h3>
<div class="result-content" id="uriResult">等待输入...</div>
<div class="info-box">
<i class="fas fa-info-circle"></i> 适用于编码完整URL,保留URL结构(如 :, /, ?, &, = 等字符)
</div>
</div>
</div>
<div class="result-card component">
<div class="card-header">
<i class="fas fa-cog"></i>
<h2>encodeURIComponent()</h2>
</div>
<div class="card-body">
<h3>编码结果:</h3>
<div class="result-content" id="componentResult">等待输入...</div>
<div class="info-box">
<i class="fas fa-info-circle"></i> 适用于编码URL组件(查询参数值等),编码所有特殊字符
</div>
</div>
</div>
</div>
<section class="comparison-section">
<h2><i class="fas fa-balance-scale"></i> 函数对比</h2>
<table>
<thead>
<tr>
<th>特性</th>
<th>escape()</th>
<th>encodeURI()</th>
<th>encodeURIComponent()</th>
</tr>
</thead>
<tbody>
<tr>
<td>是否标准</td>
<td class="cross">已废弃</td>
<td class="check">标准</td>
<td class="check">标准</td>
</tr>
<tr>
<td>是否编码URL保留字符 (:/?#[]@!$&'()*+,;=)</td>
<td class="cross">部分编码</td>
<td class="cross">不编码</td>
<td class="check">全部编码</td>
</tr>
<tr>
<td>是否编码非保留字符 (字母数字和 -_.~)</td>
<td class="cross">部分编码</td>
<td class="cross">不编码</td>
<td class="cross">不编码</td>
</tr>
<tr>
<td>是否编码Unicode字符</td>
<td class="check">%uXXXX格式</td>
<td class="check">UTF-8编码</td>
<td class="check">UTF-8编码</td>
</tr>
<tr>
<td>空格编码</td>
<td>%20</td>
<td>%20</td>
<td>%20</td>
</tr>
<tr>
<td>最佳使用场景</td>
<td>无 - 不应使用</td>
<td>完整URL编码</td>
<td>URL参数值编码</td>
</tr>
</tbody>
</table>
</section>
<footer>
<p>© 2023 URL编码函数对比工具 | 在Web开发中请优先使用encodeURI()和encodeURIComponent()</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const inputText = document.getElementById('inputText');
const encodeBtn = document.getElementById('encodeBtn');
const escapeResult = document.getElementById('escapeResult');
const uriResult = document.getElementById('uriResult');
const componentResult = document.getElementById('componentResult');
const presetBtns = document.querySelectorAll('.preset-btn');
// 初始编码示例文本
encodeText();
// 编码按钮事件
encodeBtn.addEventListener('click', encodeText);
// 预设按钮事件
presetBtns.forEach(btn => {
btn.addEventListener('click', function() {
inputText.value = this.getAttribute('data-value');
encodeText();
});
});
// 编码函数
function encodeText() {
const text = inputText.value;
if (!text.trim()) {
escapeResult.textContent = '请输入文本';
uriResult.textContent = '请输入文本';
componentResult.textContent = '请输入文本';
return;
}
// 使用不同的编码函数
escapeResult.textContent = escape(text);
uriResult.textContent = encodeURI(text);
componentResult.textContent = encodeURIComponent(text);
}
// 按Enter键也可以触发编码
inputText.addEventListener('keyup', function(e) {
if (e.key === 'Enter') {
encodeText();
}
});
});
</script>
</body>
</html>

浙公网安备 33010602011771号