
js代码大全:常用 JavaScript 示例与写法整理
JavaScript 常用于浏览器交互、表单处理、网络请求,也可以运行在 Node.js 等环境中。查找代码示例时,真正重要的不只是记住语法,还要了解代码依赖的环境、参数范围和失败情形。本文按常见任务整理可直接参考的写法,并说明容易忽略的边界。
示例以现代 JavaScript(ES2015 及之后的常见语法)为主。除 DOM 和浏览器存储部分外,多数片段可以放在浏览器控制台或 Node.js 中运行。示例中的变量名尽量独立;实际项目中应按业务修改,并配合测试。
一、变量、类型与默认值
优先使用 const 声明不会重新赋值的变量,确实需要重新赋值时使用 let。通常不建议继续使用 var:它的函数作用域和变量提升规则容易导致意外行为。注意,const 限制的是变量绑定,不能阻止对象内部属性变化。
const name = "小林";
let count = 0;
count += 1;
const settings = { theme: "light" };
settings.theme = "dark"; // 可以修改对象属性
// settings = {}; // 不可以给 const 变量重新赋值
console.log(name, count, settings.theme);
JavaScript 有 string、number、boolean、undefined、bigint、symbol 等原始类型,以及对象类型。null 表示有意设置的空值。值得注意的是,typeof null 的结果是 "object",这是语言历史遗留行为,不能用它判断是否为普通对象。
console.log(typeof "文字"); // "string"
console.log(typeof 42); // "number"
console.log(typeof null); // "object"
const value = null;
if (value === null) {
console.log("明确的空值");
}
数值计算使用 IEEE 754 双精度浮点数,部分小数不能精确表示,例如 0.1 + 0.2 不严格等于 0.3。金额计算可按最小货币单位使用整数(如分),或采用经过评估的十进制定点方案,不能直接依赖浮点数严格相等。
二、条件判断与安全的默认值
严格相等运算符 === 不做类型转换,通常比 == 更容易推理。逻辑或 || 会把 0、空字符串和 false 都当作需要回退的值;如果只有 null 或 undefined 才应该使用默认值,应选择空值合并运算符 ??。
const pageFromInput = 0;
const pageA = pageFromInput || 1; // 1:0 被视为假值
const pageB = pageFromInput ?? 1; // 0:只对 null 和 undefined 回退
console.log(pageA, pageB);
读取可能不存在的嵌套属性时,可用可选链 ?. 避免因中间值为空而抛出异常。但它不会验证数据结构是否符合业务要求,也不会代替输入校验。
const user = {
profile: {
displayName: "小林"
}
};
const displayName = user.profile?.displayName ?? "访客";
console.log(displayName);
不要将外部输入直接当作可信数据。来自表单、URL、接口响应或本地存储的值都可能缺失、格式错误或被修改。默认值适合处理缺省情况,不等于完整校验。
三、字符串处理与模板字符串
模板字符串适合拼接文本和表达式,换行也会保留。trim() 可去除字符串两端的空白,但不会清理字符串中间的空格;includes() 可检查子串是否存在。字符串方法通常返回新字符串,不会直接改写原字符串。
const rawName = " 小林 ";
const name = rawName.trim();
const message = `你好,${name}!`;
console.log(message);
console.log("javascript".includes("script")); // true
console.log("a,b,c".split(",")); // ["a", "b", "c"]
如果要把字符串转换成数字,不要仅依赖全局 isNaN,它会先进行类型转换。Number.isFinite() 可用于检查结果是否为有限数字。对于整数参数,还应明确允许范围,并处理空字符串等输入。
function parsePositiveInteger(input) {
const text = String(input).trim();
if (text === "") {
return null;
}
const value = Number(text);
if (!Number.isSafeInteger(value) || value <= 0) {
return null;
}
return value;
}
console.log(parsePositiveInteger("12")); // 12
console.log(parsePositiveInteger("1.5")); // null
console.log(parsePositiveInteger("")); // null
此例允许可转换为正安全整数的输入;如果业务只接受纯数字文本,还需在转换前用正则或逐字符规则限制格式。正则表达式应按需求设计,避免过于宽泛的匹配。
四、数组常用操作
map() 用于把数组每项转换成新数组;filter() 用于筛选;find() 返回第一个匹配项,找不到时返回 undefined。这些方法不会修改原数组,但回调函数仍可能修改数组项所引用的对象。
const products = [
{ id: 1, name: "笔记本", price: 80 },
{ id: 2, name: "键盘", price: 120 },
{ id: 3, name: "鼠标", price: 50 }
];
const names = products.map(product => product.name);
const affordable = products.filter(product => product.price <= 80);
const keyboard = products.find(product => product.name === "键盘");
console.log(names);
console.log(affordable);
console.log(keyboard);
reduce() 可用于累计求和,但回调参数顺序容易写错:依次为累计值、当前项、索引和原数组。必须提供初始值,尤其是数组可能为空时;不提供初始值的空数组调用会抛出异常。
const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => {
return sum + price;
}, 0);
console.log(total); // 60
要对数组去重,常见做法是使用 Set。它按值识别基本类型;对对象来说,只有同一个对象引用才会被视为重复,不会按对象内容自动去重。
const values = [1, 2, 2, "2", 3];
const uniqueValues = [...new Set(values)];
console.log(uniqueValues); // [1, 2, "2", 3]
const first = { id: 1 };
const second = { id: 1 };
console.log(new Set([first, second]).size); // 2
五、对象、展开语法与解构
对象展开语法适合创建浅拷贝或合并对象。后面的属性会覆盖前面的同名属性;嵌套对象仍然共享引用,因此它不是深拷贝。
const defaults = { theme: "light", pageSize: 20 };
const options = { pageSize: 50 };
const config = { ...defaults, ...options };
console.log(config); // { theme: "light", pageSize: 50 }
const original = { user: { name: "小林" } };
const copy = { ...original };
copy.user.name = "小周";
console.log(original.user.name); // "小周",嵌套对象仍共享
对象解构可以简化取值,重命名和默认值也很常用。解构默认值只在取值为 undefined 时生效,不会覆盖 null。
const response = { data: { title: "文章" } };
const { data: { title = "无标题" } = {} } = response;
console.log(title);
const { limit = 10 } = { limit: null };
console.log(limit); // null
当对象属性名来自外部输入时,避免把不可信属性名随意写入普通对象;某些特殊属性名可能造成意外行为。可使用 Map 保存任意键值,或在确有需要时使用无原型对象,并对键名和数据进行校验。
六、函数、参数校验与异常
函数参数应有明确约定。下面的示例要求传入非负有限数值,不接受数字字符串;遇到不符合约定的参数会抛出 TypeError,由调用者决定如何处理。
function calculateDiscount(price, rate = 0.1) {
if (typeof price !== "number" || !Number.isFinite(price) || price < 0) {
throw new TypeError("price 必须是非负有限数值");
}
if (typeof rate !== "number" || !Number.isFinite(rate) ||
rate < 0 || rate > 1) {
throw new RangeError("rate 必须在 0 到 1 之间");
}
return price * (1 - rate);
}
console.log(calculateDiscount(100, 0.2)); // 80
这里的折扣比例范围为 0 到 1,端点均允许;业务若只允许小于 1,需要相应调整判断。抛出异常后如果没有被捕获,会中断当前调用链,因此不要用空的 catch 悄悄吞掉错误。
try {
const result = calculateDiscount(100, 2);
console.log(result);
} catch (error) {
console.error("计算失败:", error.message);
}
纯函数对相同输入产生相同输出,并尽量不修改外部状态,更容易测试。实际函数如果会读写网络、时间、随机数或 DOM,就不是纯函数;把这些副作用集中在边界处,通常有利于维护。
七、日期与格式化
Date 适合处理时间戳和日期时间,但日期字符串的解析存在格式差异。优先使用带时区信息的标准格式或数值时间戳;对用户输入的日期,应按明确格式拆分和校验。注意月份在 Date 构造函数中从 0 开始计数。
const now = new Date();
console.log(now.toISOString()); // UTC 时间的 ISO 格式
const date = new Date(2025, 0, 15); // 本地时间:2025 年 1 月 15 日
console.log(date.getFullYear());
console.log(date.getMonth() + 1); // 输出月份时加 1
服务器存储和跨时区传输时,通常使用 UTC 时间戳或包含时区的 ISO 字符串;展示时再按用户时区格式化。不要把本地时间和 UTC 时间混为一谈,否则夏令时和时区差异可能导致日期偏移。
const formatter = new Intl.DateTimeFormat("zh-CN", {
year: "numeric",
month: "2-digit",
day: "2-digit"
});
console.log(formatter.format(new Date()));
八、Promise 与 async/await
异步操作常以 Promise 表示。使用 async 声明的函数总会返回 Promise;在函数内部用 await 等待结果。try...catch 可处理等待期间的拒绝,但应保留有用的错误信息,而不是只显示“失败”。
function wait(milliseconds) {
return new Promise(resolve => {
setTimeout(resolve, milliseconds);
});
}
async function runTask() {
console.log("开始");
await wait(300);
console.log("结束");
}
runTask().catch(error => {
console.error("任务出错:", error);
});
await 会暂停当前异步函数的后续执行。如果多个任务彼此独立,不必依次等待,可以使用 Promise.all() 并行等待;其中一个 Promise 拒绝时,Promise.all() 会拒绝,但这并不意味着其他任务自动取消。
async function loadBoth() {
const [first, second] = await Promise.all([
wait(200).then(() => "第一个完成"),
wait(300).then(() => "第二个完成")
]);
console.log(first, second);
}
loadBoth().catch(console.error);
循环中需要逐个按顺序处理异步任务时,可使用 for...of 配合 await。不需要顺序依赖时,可以先生成任务再交给 Promise.all();不要误以为 forEach 会等待异步回调完成。
九、使用 fetch 请求接口
fetch() 用于发起网络请求,浏览器和现代 Node.js 环境均提供该 API,但具体支持情况取决于运行时版本。一个常见误区是认为 HTTP 404 会让 Fetch Promise 自动拒绝;实际上通常需要检查 response.ok。网络错误、跨域限制和主动中止则可能进入异常处理。
async function getJson(url) {
const response = await fetch(url, {
headers: { Accept: "application/json" }
});
if (!response.ok) {
throw new Error(`HTTP 错误:${response.status}`);
}
return response.json();
}
getJson("https://jsonplaceholder.typicode.com/todos/1")
.then(data => console.log(data))
.catch(error => console.error("请求失败:", error.message));
该示例依赖网络访问,目标服务器还必须允许当前环境请求。response.json() 本身也是异步操作;若响应不是合法 JSON,它会拒绝。生产代码还应根据接口约定检查响应字段和类型,不能只因为解析成功就认定数据可信。
使用 AbortController 可在支持它的环境中取消请求。超时不是 Fetch 默认提供的参数,需要自己创建定时器并在完成后清理。
async function fetchWithTimeout(url, timeoutMs = 5000) {
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
throw new RangeError("timeoutMs 必须是正的有限数值");
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) {
throw new Error(`HTTP 错误:${response.status}`);
}
return await response.json();
} finally {
clearTimeout(timer);
}
}
取消请求时,错误类型和具体表现可能随运行环境不同;调用方应把主动取消与普通网络失败区分处理。不要把访问令牌等秘密放进公开的前端代码或 URL 参数中,浏览器代码对用户并不保密。
十、浏览器 DOM 与事件
下面的代码仅适用于浏览器页面,且要求页面中存在对应元素。通过 querySelector() 获取的结果可能为 null,绑定事件前应检查。把文本显示到页面时,优先使用 textContent,它会作为文本处理,而不会将字符串解析成 HTML。
const button = document.querySelector("#save-button");
const output = document.querySelector("#output");
if (button && output) {
button.addEventListener("click", () => {
output.textContent = "已保存";
});
}
不要把不可信输入直接赋给 innerHTML。它会解析 HTML,可能导致跨站脚本风险;只有在确实需要插入 HTML 且内容经过可靠消毒时才考虑使用。转义、消毒和上下文编码不是同一件事,具体做法应结合输出位置和框架安全机制。
事件监听器可在不再需要时移除。若页面组件反复创建和销毁却不清理监听器,可能出现重复响应或持有不必要引用。
const handleClick = () => {
console.log("按钮被点击");
};
button?.addEventListener("click", handleClick);
// 不再需要时:
// button?.removeEventListener("click", handleClick);
事件委托适合处理数量较多、动态添加的子元素:把监听器放在稳定的父元素上,再检查事件目标。以下示例要求目标元素具有 data-action 属性。
const list = document.querySelector("#list");
list?.addEventListener("click", event => {
const target = event.target;
if (!(target instanceof Element)) return;
const item = target.closest("[data-action='remove']");
if (item && list.contains(item)) {
item.closest("li")?.remove();
}
});
十一、本地存储与 JSON
localStorage 只能保存字符串,数据通常需要通过 JSON.stringify() 和 JSON.parse() 转换。读取可能返回 null;内容也可能损坏,或因浏览器策略、存储空间等原因无法写入,所以读写都应考虑异常。
const storageKey = "app-settings";
function saveSettings(settings) {
try {
localStorage.setItem(storageKey, JSON.stringify(settings));
return true;
} catch (error) {
console.error("保存失败:", error);
return false;
}
}
function loadSettings() {
try {
const text = localStorage.getItem(storageKey);
if (text === null) return null;
return JSON.parse(text);
} catch (error) {
console.error("读取或解析失败:", error);
return null;
}
}
saveSettings({ theme: "dark" });
console.log(loadSettings());
该代码要求运行在浏览器页面中。JSON 不能表示函数、undefined、循环引用等所有 JavaScript 值;序列化结果也不应被当作经过验证的业务对象。加载后仍要校验字段。localStorage 不适合保存密码、访问令牌或其他敏感凭据,因为同源脚本可读取它,存在跨站脚本等风险。
十二、常用小工具函数
防抖(debounce)用于把短时间内连续触发的调用合并为一次,适合搜索框输入、窗口尺寸变化等场景。下例会在最后一次调用后的指定时间执行。延迟必须是非负有限数值;使用时需留意组件销毁后定时器仍可能触发。
function debounce(fn, delay = 300) {
if (typeof fn !== "function") {
throw new TypeError("fn 必须是函数");
}
if (!Number.isFinite(delay) || delay < 0) {
throw new RangeError("delay 必须是非负有限数值");
}
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
const searchLater = debounce(query => {
console.log("搜索:", query);
}, 300);
searchLater("java");
searchLater("javascript");
节流(throttle)用于限制函数在一段时间内最多执行一次,适合滚动或拖动等高频事件。下面的简单实现按固定间隔执行一次,不保证最后一次调用一定补执行;如果业务要求尾部执行或立即执行,需要选用经过测试的实现并明确规则。
function throttle(fn, interval = 200) {
if (typeof fn !== "function") {
throw new TypeError("fn 必须是函数");
}
if (!Number.isFinite(interval) || interval < 0) {
throw new RangeError("interval 必须是非负有限数值");
}
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}
这两个函数保留调用时的 this 和参数,但没有提供取消待执行任务的接口。若页面卸载、组件销毁或输入内容变化时必须取消,应扩展 API 提供清理方法,或采用成熟库中语义明确的实现。
十三、随机数与安全边界
Math.random() 返回大于等于 0 且小于 1 的伪随机数,可用于一般界面效果或非安全用途的随机选择;它不适合生成密码、令牌或其他安全凭据。密码学用途应使用运行环境提供的安全随机 API,例如浏览器的 crypto.getRandomValues(),并遵循相应协议的字节数和编码要求。
function randomIndex(length) {
if (!Number.isSafeInteger(length) || length <= 0) {
throw new RangeError("length 必须是正安全整数");
}
return Math.floor(Math.random() * length);
}
console.log(randomIndex(5)); // 0 到 4
这段代码适用于不要求安全性的均匀索引选择;不要把它改名为“安全随机数”用于令牌或验证码保护。即使改用安全随机源,也需要正确处理取值范围,避免简单取模带来的分布偏差。
十四、常见错误检查清单
- 比较值时优先使用
===,并明确是否需要把数字字符串转换成数值。 - 不要把
||当成只处理空值的运算符;允许0或空字符串时考虑??。 - 数组可能为空时,为
reduce()提供初始值;需要结果时不要误用不等待异步回调的forEach()。 - 使用 Fetch 时检查
response.ok,并处理网络错误、JSON 解析失败和取消请求。 - 外部数据需要校验类型、范围和结构;默认值不能代替校验。
- 展示不可信文本优先使用
textContent,避免把未经处理的内容写入innerHTML。 - 对象展开是浅拷贝;日期、浮点数和时区运算都要明确业务规则。
- 不要在前端代码中放置需要保密的密钥,也不要将
Math.random()用于安全凭据。
JavaScript 示例可以作为实现起点,但不能替代接口约定、输入验证和安全评估。把参数范围写清楚,在边界输入和失败路径上做测试,再根据目标浏览器或 Node.js 版本验证运行结果,通常比直接复制一段“万能代码”更可靠。









