JavaScript 核心知识学习笔记:给Java开发者的实战指南
开篇:从Java到JavaScript的转变
作为一名Java开发者开始学习JavaScript时,我发现最大的挑战不是语法本身,而是思维方式的转变。Java是强类型、面向对象的语言,而JavaScript是弱类型、原型继承的脚本语言。这篇文章记录了我学习JS核心概念时的心得,特别会指出与Java的关键差异。
一、String(字符串):比Java更灵活的文本处理
与Java的核心差异
在Java中,String是不可变对象,我们习惯用StringBuilder
来拼接。但JavaScript的字符串处理要灵活得多。
// JavaScript的字符串声明let str1 = "Hello";let str2 = 'World';let str3 = `Hello ${str2}`;console.log(str3); // Java中需要:
// String str3 = String.format("Hello %s", str2);
字符串拼接的演进
let name = "张三";
let age = 25;// 方式1:传统拼接(类似Java)
let msg1 = "姓名:" + name + ",年龄:" + age;// 方式2:模板字符串(推荐)
let msg2 = `姓名:${name},年龄:${age}`;// 甚至可以在${}中执行表达式
let msg3 = `明年年龄:${age + 1}`;
这比Java的StringBuilder或String.format()直观很多,我现在基本只用模板字符串。
常用方法对比
let text = "JavaScript";// Java: text.length() -> JavaScript: text.length(注意没有括号)
console.log(text.length); // 10// 大小写转换(与Java类似)
text.toUpperCase(); // "JAVASCRIPT"
text.toLowerCase(); // "javascript"// 查找子串
text.includes("Script"); // true(Java 需要用 contains())
text.indexOf("Script"); // 4(与Java相同)
text.startsWith("Java"); // true
text.endsWith("Script"); // true// 截取(注意参数与Java的substring略有不同)
text.slice(0, 4); // "Java"(推荐用这个)
text.substring(0, 4); // "Java"(与Java行为类似)// 替换
text.replace("Java", "Type"); // "TypeScript"(只替换第一个)
text.replaceAll("a", "A"); // "JAvaScript"(替换所有)// 分割成数组
text.split(""); // ["J", "a", "v", "a", "S", "c", "r", "i", "p", "t"]
实战案例:输入验证
function validateUsername(username) {// 去除首尾空格(类似Java的trim())username = username.trim();// 长度检查if (username.length < 3 || username.length > 20) {return { valid: false, message: "用户名长度必须在3-20之间" };}// 格式检查(只允许字母、数字、下划线)let pattern = /^[a-zA-Z0-9_]+$/;if (!pattern.test(username)) {return { valid: false, message: "用户名只能包含字母、数字和下划线" };}return { valid: true, message: "验证通过" };
}console.log(validateUsername("user_123")); // { valid: true, ... }
console.log(validateUsername("ab")); // { valid: false, ... }
二、Array(数组):比Java数组强大百倍
关键差异认知
这是我从Java转JS时最大的惊喜:JavaScript的数组是动态的、功能丰富的。
// Java: int[] arr = new int[5]; 固定长度
// JavaScript: 数组是动态的,可以随时增删let arr = []; // 空数组
arr.push(1); // 添加元素
arr.push(2);
arr.push(3);
console.log(arr.length); // 3// 可以存储不同类型(与Java泛型不同)
let mixed = [1, "text", true, { name: "obj" }]; // 完全合法
基础操作
let numbers = [1, 2, 3, 4, 5];// 添加/删除元素
numbers.push(6); // 末尾添加:[1,2,3,4,5,6]
numbers.pop(); // 末尾删除:[1,2,3,4,5]
numbers.unshift(0); // 开头添加:[0,1,2,3,4,5]
numbers.shift(); // 开头删除:[1,2,3,4,5]// 查找元素
numbers.indexOf(3); // 2(返回索引,类似Java的Arrays.asList().indexOf())
numbers.includes(3); // true// 截取(类似Java的Arrays.copyOfRange())
let sliced = numbers.slice(1, 3); // [2, 3]
函数式编程方法(重点!)
这是JavaScript相比Java数组最强大的地方。虽然Java 8也引入了Stream API,但JS的数组方法更简洁直观。
let products = [{ id: 1, name: "笔记本", price: 5000, inStock: true },{ id: 2, name: "鼠标", price: 100, inStock: true },{ id: 3, name: "键盘", price: 300, inStock: false },{ id: 4, name: "显示器", price: 2000, inStock: true }
];// filter:筛选(类似Java的Stream.filter())
let inStockProducts = products.filter(p => p.inStock);
// Java: products.stream().filter(p -> p.isInStock()).collect(Collectors.toList());// map:转换(类似Java的Stream.map())
let names = products.map(p => p.name);
// Java: products.stream().map(Product::getName).collect(Collectors.toList());// find:查找第一个匹配项(类似Java的Stream.findFirst())
let expensiveProduct = products.find(p => p.price > 1000);// reduce:聚合(类似Java的Stream.reduce())
let totalPrice = products.reduce((sum, p) => sum + p.price, 0);
// Java: products.stream().mapToInt(Product::getPrice).sum();// some:至少有一个满足条件(类似Java的Stream.anyMatch())
let hasExpensive = products.some(p => p.price > 1000); // true// every:全部满足条件(类似Java的Stream.allMatch())
let allInStock = products.every(p => p.inStock); // false// 链式调用
let result = products.filter(p => p.inStock).map(p => ({ name: p.name, price: p.price })).sort((a, b) => a.price - b.price);
console.log("In-stock products:", inStockProducts);
console.log("Product names:", names);
实战案例:数据处理
// 场景:处理从API获取的订单数据
let orders = [{ orderId: "001", userId: 1, amount: 299, status: "completed" },{ orderId: "002", userId: 2, amount: 599, status: "pending" },{ orderId: "003", userId: 1, amount: 199, status: "completed" },{ orderId: "004", userId: 3, amount: 899, status: "completed" }
];// 统计某用户的已完成订单总额
function getTotalAmount(userId) {return orders.filter(order => order.userId === userId && order.status === "completed").reduce((total, order) => total + order.amount, 0);
}console.log(getTotalAmount(1)); // 498// 按金额分组
function groupByAmount() {return {low: orders.filter(o => o.amount < 300),medium: orders.filter(o => o.amount >= 300 && o.amount < 600),high: orders.filter(o => o.amount >= 600)};
}
三、Object(对象):理解原型而非类
思维转变
Java中我们用class
定义对象,JavaScript虽然ES6也引入了class
关键字,但本质是原型继承。对象字面量的使用非常频繁。
// JavaScript对象字面量(最常用)
let user = {id: 1,username: "admin",email: "admin@example.com",// 方法getInfo: function() {return `${this.username} (${this.email})`;}
};// 等价的Java代码需要先定义类:
// public class User {
// private int id;
// private String username;
// private String email;
// public String getInfo() { ... }
// }
// User user = new User();
对象操作
let config = {apiUrl: "https://api.example.com",timeout: 5000,retries: 3
};// 访问属性
console.log(config.apiUrl); // 点号访问
console.log(config["timeout"]); // 括号访问(动态属性名时很有用)// 动态属性名
let propName = "retries";
console.log(config[propName]); // 3// 添加属性
config.debug = true;// 删除属性(Java中不常见的操作)
delete config.debug;// 检查属性是否存在
if ("timeout" in config) {console.log("timeout配置存在");
}// 获取所有属性名(类似Java的反射)
let keys = Object.keys(config); // ["apiUrl", "timeout", "retries"]
let values = Object.values(config); // 对应的值数组
let entries = Object.entries(config); // [["apiUrl", "..."], ...]
对象解构(ES6特性)
这是JavaScript特有的语法糖,能大幅简化代码:
let user = {id: 1,username: "zhangsan",email: "zhangsan@example.com",role: "admin"
};// 传统方式
let username = user.username;
let email = user.email;// 解构赋值
let { username, email } = user;// 函数参数解构(特别实用)
function sendEmail({ email, username }) {console.log(`发送邮件给 ${username}: ${email}`);
}sendEmail(user); // 直接传入对象,自动提取需要的属性
四、JSON:前后端数据交换的桥梁
与Java对比
在Java中,我们用Jackson或Gson来序列化/反序列化对象。JavaScript原生就支持JSON操作,这是它的一大优势。
// Java需要:
// ObjectMapper mapper = new ObjectMapper();
// String json = mapper.writeValueAsString(object);
// Object obj = mapper.readValue(json, Object.class);// JavaScript只需要:
let jsonString = JSON.stringify(object);
let object = JSON.parse(jsonString);
JSON.stringify:将 JavaScript对象转换为 JSON字符串,便于网络传输或本地存储。
JSON.parse:将 JSON字符串解析为 JavaScript对象,实现数据的读取和使用。
基础操作
let userData = {userId: 1001,username: "lisi",roles: ["user", "editor"],metadata: {lastLogin: "2025-10-22",loginCount: 15}
};// 对象转JSON字符串
let jsonStr = JSON.stringify(userData);
console.log(jsonStr);
// '{"userId":1001,"username":"lisi","roles":["user","editor"],"metadata":{...}}'// 格式化输出(带缩进)
let prettyJson = JSON.stringify(userData, null, 2);
console.log(prettyJson);// JSON字符串转对象
let parsed = JSON.parse(jsonStr);
console.log(parsed.username); // "lisi"
实战场景:API数据处理
// 场景:处理REST API响应
function fetchUserData(userId) {// 模拟API响应的JSON字符串let response = `{"code": 200,"message": "success","data": {"user": {"id": ${userId},"name": "张三","email": "zhangsan@example.com"},"permissions": ["read", "write"]}}`;// 解析JSONlet result = JSON.parse(response);if (result.code === 200) {return result.data;} else {throw new Error(result.message);}
}// 使用
try {let userData = fetchUserData(1001);console.log(`用户名:${userData.user.name}`);console.log(`权限:${userData.permissions.join(", ")}`);
} catch (error) {console.error("获取用户数据失败:", error.message);
}
数据转换与验证
// 场景:表单数据提交
function submitForm(formData) {// 构建请求体let requestBody = {username: formData.username.trim(),email: formData.email.toLowerCase(),age: parseInt(formData.age),timestamp: Date.now()};// 验证if (!requestBody.username || requestBody.username.length < 3) {throw new Error("用户名至少3个字符");}// 转换为JSONlet jsonData = JSON.stringify(requestBody);// 模拟发送请求console.log("发送数据:", jsonData);return jsonData;
}// 测试
try {submitForm({username: "test_user",email: "TEST@EXAMPLE.COM",age: "25"});
} catch (error) {console.error(error.message);
}
五、DOM:网页操作的核心API
与Java Swing/JavaFX的对比
如果你写过Java桌面应用,DOM操作类似于Swing的组件操作,但更直接、更动态。
基础选择器
// 获取元素的几种方式
let element1 = document.getElementById("myId"); // 通过ID
let elements1 = document.getElementsByClassName("myClass"); // 通过类名(返回集合)
let elements2 = document.getElementsByTagName("div"); // 通过标签名
let element2 = document.querySelector(".myClass"); // CSS选择器(推荐)
let elements3 = document.querySelectorAll(".myClass"); // 所有匹配元素
我的建议:优先使用querySelector
和querySelectorAll
,它们更灵活,支持所有CSS选择器,也是。当前最为常用的。
实战案例1:动态表格生成
假设有这样的HTML结构:
<!DOCTYPE html>
<html>
<head><title>用户列表</title><style>table { border-collapse: collapse; width: 100%; }th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }th { background-color: #4CAF50; color: white; }</style>
</head>
<body><div id="app"><h2>用户管理</h2><table id="userTable"><thead><tr><th>ID</th><th>姓名</th><th>邮箱</th><th>操作</th></tr></thead><tbody id="tableBody"></tbody></table></div><script src="app.js"></script>
</body>
</html>
JavaScript代码(app.js):
// 模拟从API获取的数据
let users = [{ id: 1, name: "张三", email: "zhangsan@example.com" },{ id: 2, name: "李四", email: "lisi@example.com" },{ id: 3, name: "王五", email: "wangwu@example.com" }
];// 渲染表格
function renderTable() {let tbody = document.getElementById("tableBody");tbody.innerHTML = ""; // 清空现有内容users.forEach(user => {let row = document.createElement("tr");row.innerHTML = `<td>${user.id}</td><td>${user.name}</td><td>${user.email}</td><td><button onclick="editUser(${user.id})">编辑</button><button onclick="deleteUser(${user.id})">删除</button></td>`;tbody.appendChild(row);});
}// 编辑用户
function editUser(id) {let user = users.find(u => u.id === id);if (user) {let newName = prompt("输入新姓名:", user.name);if (newName) {user.name = newName;renderTable(); // 重新渲染}}
}// 删除用户
function deleteUser(id) {if (confirm("确定要删除吗?")) {users = users.filter(u => u.id !== id);renderTable();}
}// 页面加载时渲染表格
document.addEventListener("DOMContentLoaded", function() {renderTable();
});
以上HTML JS代码执行结果:
实战案例2:表单处理与验证
HTML结构:
<form id="loginForm"><div><label for="username">用户名:</label><input type="text" id="username" name="username"><span id="usernameError" style="color: red;"></span></div><div><label for="password">密码:</label><input type="password" id="password" name="password"><span id="passwordError" style="color: red;"></span></div><button type="submit">登录</button>
</form>
<div id="result"></div>
JavaScript代码:
let form = document.getElementById("loginForm");form.addEventListener("submit", function(event) {event.preventDefault(); // 阻止表单默认提交行为// 清空之前的错误信息document.getElementById("usernameError").textContent = "";document.getElementById("passwordError").textContent = "";// 获取表单数据let username = document.getElementById("username").value.trim();let password = document.getElementById("password").value;// 验证let isValid = true;if (username.length < 3) {document.getElementById("usernameError").textContent = "用户名至少3个字符";isValid = false;}if (password.length < 6) {document.getElementById("passwordError").textContent = "密码至少6个字符";isValid = false;}if (isValid) {// 提交数据submitLogin(username, password);}
});function submitLogin(username, password) {// 模拟API请求let loginData = {username: username,password: password,timestamp: Date.now()};console.log("提交登录:", JSON.stringify(loginData));// 显示结果document.getElementById("result").innerHTML = `<p style="color: green;">登录成功!欢迎 ${username}</p>`;
}
六、BOM:浏览器对象模型
核心概念
BOM提供了与浏览器交互的接口,这是Java开发中不会接触到的领域。主要包括:
-
window
:全局对象 -
navigator
:浏览器信息 -
location
:URL操作 -
history
:浏览历史 -
screen
:屏幕信息
window对象
// 弹窗(开发调试时常用)
alert("提示信息");
let confirmed = confirm("确定要删除吗?"); // 返回boolean
let input = prompt("请输入姓名:", "默认值");// 定时器(类似Java的Timer)定时器任务我常用SpringTask
setTimeout(function() {console.log("3秒后执行");
}, 3000);let intervalId = setInterval(function() {console.log("每2秒执行一次");
}, 2000);// 清除定时器
clearInterval(intervalId);// 页面尺寸
console.log(window.innerWidth); // 视口宽度
console.log(window.innerHeight); // 视口高度
location对象
// URL操作
console.log(location.href); // 完整URL
console.log(location.hostname); // 主机名
console.log(location.pathname); // 路径
console.log(location.search); // 查询字符串// 跳转
location.href = "https://example.com";
location.reload(); // 刷新页面// 解析URL参数
function getUrlParams() {let params = {};let queryString = location.search.substring(1);let pairs = queryString.split("&");pairs.forEach(pair => {let [key, value] = pair.split("=");params[key] = decodeURIComponent(value);});return params;
}// 使用URLSearchParams(现代方式)
let params = new URLSearchParams(location.search);
console.log(params.get("id")); // 获取参数值
localStorage(本地存储)
// 存储数据(类似Java的Properties文件)
localStorage.setItem("username", "zhangsan");
localStorage.setItem("theme", "dark");// 存储对象需要序列化
let user = { id: 1, name: "张三" };
localStorage.setItem("user", JSON.stringify(user));// 读取数据
let username = localStorage.getItem("username");
let userStr = localStorage.getItem("user");
let userObj = JSON.parse(userStr);// 删除数据
localStorage.removeItem("username");
localStorage.clear(); // 清空所有
实战案例:会话管理
// 用户会话管理类
class SessionManager {constructor() {this.TOKEN_KEY = "auth_token";this.USER_KEY = "user_info";}// 保存登录信息saveSession(token, userInfo) {localStorage.setItem(this.TOKEN_KEY, token);localStorage.setItem(this.USER_KEY, JSON.stringify(userInfo));}// 获取tokengetToken() {return localStorage.getItem(this.TOKEN_KEY);}// 获取用户信息getUserInfo() {let userStr = localStorage.getItem(this.USER_KEY);return userStr ? JSON.parse(userStr) : null;}// 检查是否登录isLoggedIn() {return this.getToken() !== null;}// 登出logout() {localStorage.removeItem(this.TOKEN_KEY);localStorage.removeItem(this.USER_KEY);location.href = "/login.html";}
}// 使用
let session = new SessionManager();// 登录后保存会话
session.saveSession("abc123token", {id: 1,username: "zhangsan",role: "admin"
});// 页面加载时检查登录状态
if (!session.isLoggedIn()) {location.href = "/login.html";
} else {let user = session.getUserInfo();console.log(`欢迎回来,${user.username}!`);
}
总结:Java开发者学习JS的建议
从Java转到JavaScript这段时间,最大的收获是理解了这两种语言在设计理念上的根本差异。Java追求严谨和可控,而JavaScript更注重灵活和实用。刚开始我总想用Java的思维去理解JS,比如纠结于没有强类型、对象不是基于类的等等,但慢慢发现这正是JavaScript的优势所在。