作为一名前端开发者,掌握JavaScript基础语法是必备技能。2026年的现代JavaScript(ES6+)已经发展得相当成熟,但核心语法依然保持着简洁高效的特点。让我们从最基础的变量声明开始,逐步深入理解这门语言的核心机制。
在JavaScript中,变量声明经历了从var到let/const的演变过程。现代开发中,我们强烈推荐使用let和const,它们解决了var带来的诸多问题。
javascript复制// 旧式声明 - 存在变量提升和函数作用域问题
var name = "张三";
// 现代声明 - 块级作用域
let age = 25;
const PI = 3.14159;
// const的特殊性
const person = { name: "李四" };
person.age = 30; // 合法操作
// person = {}; // 报错:Assignment to constant variable
重要提示:const声明的变量不能被重新赋值,但对于对象和数组这类引用类型,其内部属性是可以修改的。const保证的是变量引用的不变性,而非对象内容的不变性。
JavaScript有8种基本数据类型,理解它们的特性对开发至关重要:
| 类型 | 示例 | typeof结果 | 特性说明 |
|---|---|---|---|
| Number | 42, 3.14, NaN | "number" | 所有数字都是64位浮点数 |
| String | "hello", 模板 |
"string" | 支持单/双引号和模板字符串 |
| Boolean | true, false | "boolean" | 逻辑值 |
| Undefined | let x; | "undefined" | 未初始化的变量默认值 |
| Null | let y = null; | "object" | 表示空对象引用 |
| Symbol | Symbol('id') | "symbol" | ES6引入的唯一标识符 |
| BigInt | 12345678901234567890n | "bigint" | 表示大于2^53-1的整数 |
| Object | {}, [], function(){} | "object" | 引用类型,包括数组和函数 |
类型判断的陷阱与技巧:
javascript复制console.log(typeof null); // "object" (历史遗留问题)
console.log([] instanceof Array); // true (推荐判断数组)
console.log(typeof function(){}); // "function" (特殊处理)
ES6引入的模板字符串彻底改变了字符串处理方式:
javascript复制const user = {
name: "王五",
age: 30,
skills: ["JavaScript", "React", "Node.js"]
};
// 基本插值
console.log(`用户${user.name}今年${user.age}岁`);
// 多行字符串
const htmlTemplate = `
<div class="user-card">
<h2>${user.name}</h2>
<ul>
${user.skills.map(skill => `<li>${skill}</li>`).join('')}
</ul>
</div>
`;
// 标签模板(高级用法)
function highlight(strings, ...values) {
return strings.reduce((result, str, i) =>
`${result}${str}<span class="highlight">${values[i] || ''}</span>`, '');
}
console.log(highlight`用户${user.name}今年${user.age}岁`);
现代JavaScript提供了多种强大的运算符:
javascript复制// 逻辑运算符短路特性
const defaultValue = user.nickname || "匿名用户"; // 常用默认值设置
// 空值合并运算符(??)
const config = {
timeout: 0,
title: null,
animation: false
};
const timeout = config.timeout ?? 3000; // 0会被保留,只有null/undefined才会用默认值
// 可选链运算符(?.)
const city = user?.address?.city; // 安全访问深层属性
// 实际应用场景
function getUserEmail(user) {
return user?.contact?.email ?? '无邮箱信息';
}
条件判断和循环是编程基础,但有多种优化写法:
javascript复制// 条件判断的多种形式
// 1. 传统if-else
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'C';
}
// 2. 三元运算符
const message = isLoggedIn
? `欢迎回来,${user.name}`
: '请先登录';
// 3. 逻辑运算符短路
isAdmin && showAdminPanel();
// 循环的现代写法
const numbers = [1, 2, 3, 4, 5];
// for...of循环(推荐)
for (const num of numbers) {
console.log(num);
}
// forEach方法
numbers.forEach((num, index) => {
console.log(`索引${index}的值是${num}`);
});
// 对象遍历
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}
函数是JavaScript的一等公民,有多种定义方式:
javascript复制// 1. 函数声明
function sum(a, b) {
return a + b;
}
// 2. 函数表达式
const multiply = function(a, b) {
return a * b;
};
// 3. 箭头函数(ES6+)
const divide = (a, b) => a / b;
// 4. 方法简写(ES6)
const calculator = {
add(a, b) {
return a + b;
},
subtract: (a, b) => a - b
};
// this绑定差异
const person = {
name: '张三',
sayName() {
console.log(this.name); // 正确指向person对象
},
sayNameArrow: () => {
console.log(this.name); // 指向外层作用域(通常是window)
}
};
注意事项:箭头函数没有自己的this、arguments、super或new.target绑定,适合用在需要继承外层this值的场景,如数组方法回调。但不适合作为对象方法或构造函数。
现代JavaScript提供了丰富的数组方法,掌握它们能极大提高开发效率:
javascript复制const products = [
{ id: 1, name: '手机', price: 1999, stock: 20 },
{ id: 2, name: '笔记本', price: 5999, stock: 5 },
{ id: 3, name: '耳机', price: 299, stock: 0 }
];
// 1. 转换方法
const names = products.map(p => p.name); // ["手机", "笔记本", "耳机"]
const expensive = products.filter(p => p.price > 1000); // 筛选高价商品
const totalValue = products.reduce((sum, p) => sum + p.price * p.stock, 0);
// 2. 查找方法
const outOfStock = products.find(p => p.stock === 0); // 找到第一个缺货商品
const hasExpensive = products.some(p => p.price > 5000); // 是否有高价商品
const allInStock = products.every(p => p.stock > 0); // 是否全部有货
// 3. 排序方法
const sortedByPrice = [...products].sort((a, b) => a.price - b.price); // 价格升序
const sortedByName = [...products].sort((a, b) =>
a.name.localeCompare(b.name)); // 名称字母序
// 4. 其他实用方法
const hasPhone = products.some(p => p.name.includes('手机')); // 检查是否存在手机
const prices = products.flatMap(p => [p.price, p.price * 0.8]); // 平展映射
const uniqueCategories = [...new Set(products.map(p => p.category))]; // 去重
性能提示:对于大型数组,某些方法如filter、map会创建新数组,可能影响性能。在这种情况下,考虑使用for循环或while循环。
ES6+为对象操作带来了许多便利特性:
javascript复制// 对象字面量增强
const name = '李四';
const age = 28;
const person = {
name, // 属性简写
age,
// 方法简写
introduce() {
return `我是${this.name},今年${this.age}岁`;
},
// 计算属性名
['status_' + age]: 'active'
};
// 对象解构
const { name: personName, age: personAge } = person;
console.log(personName, personAge); // 李四 28
// 对象展开
const updatedPerson = {
...person,
age: 29, // 覆盖原属性
job: '工程师' // 添加新属性
};
// 对象冻结
const config = Object.freeze({
apiUrl: 'https://api.example.com',
timeout: 5000
});
// config.timeout = 3000; // 严格模式下会报错
JavaScript的类型转换有时会让人困惑,理解规则很重要:
javascript复制// 显式类型转换
const str = '123';
const num = Number(str); // 123
const bool = Boolean(num); // true
const strFromNum = String(num); // "123"
// 隐式类型转换
const result1 = '5' + 3; // "53" (字符串拼接)
const result2 = '5' - 3; // 2 (数字运算)
const result3 = '5' * '2'; // 10 (数字运算)
// 真假值判断
const falsyValues = [false, 0, '', null, undefined, NaN];
const truthyValues = ['0', 'false', [], {}, function(){}];
// 严格相等与类型转换
console.log(1 == '1'); // true (值相等)
console.log(1 === '1'); // false (类型不同)
// 特殊比较
console.log(NaN === NaN); // false (唯一不等于自身的值)
console.log(Object.is(NaN, NaN)); // true (ES6改进)
类型转换最佳实践:
现代JavaScript项目通常采用模块化组织方式:
javascript复制// utils.js
export function formatDate(date) {
return new Date(date).toLocaleDateString();
}
export const APP_NAME = 'MyApp';
// app.js
import { formatDate, APP_NAME } from './utils.js';
console.log(`${APP_NAME} - ${formatDate(new Date())}`);
// 默认导出
// logger.js
export default function(message) {
console.log(`[${new Date().toISOString()}] ${message}`);
}
// app.js
import log from './logger.js';
log('应用启动');
健壮的错误处理是专业开发的关键:
javascript复制// 基本try-catch
try {
const data = JSON.parse(userInput);
} catch (error) {
console.error('解析JSON失败:', error.message);
// 恢复或上报错误
}
// 自定义错误
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
function validateUser(user) {
if (!user.name) {
throw new ValidationError('用户名不能为空');
}
}
// 错误边界处理
function safeParse(json) {
try {
return JSON.parse(json);
} catch {
return null; // 静默处理,返回null
}
}
// 调试技巧
console.table(products); // 表格形式输出
console.time('filter');
const filtered = products.filter(p => p.price > 1000);
console.timeEnd('filter'); // 测量执行时间
编写高性能JavaScript代码的实用技巧:
减少DOM操作:批量更新而非频繁单次操作
javascript复制// 不好
items.forEach(item => {
document.body.appendChild(createItemElement(item));
});
// 好
const fragment = document.createDocumentFragment();
items.forEach(item => {
fragment.appendChild(createItemElement(item));
});
document.body.appendChild(fragment);
事件委托:利用事件冒泡减少事件监听器
javascript复制// 不好
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', handleClick);
});
// 好
document.addEventListener('click', event => {
if (event.target.classList.contains('btn')) {
handleClick(event);
}
});
避免内存泄漏:
使用Web Workers处理CPU密集型任务:
javascript复制// main.js
const worker = new Worker('task.js');
worker.postMessage(data);
worker.onmessage = function(event) {
console.log('结果:', event.data);
};
// task.js
self.onmessage = function(event) {
const result = heavyComputation(event.data);
self.postMessage(result);
};
javascript复制// 问题案例
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出5个5
}
// 解决方案1:使用let
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出0,1,2,3,4
}
// 解决方案2:IIFE
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
javascript复制const obj = {
name: '示例',
printName() {
console.log(this.name);
},
printNameDelayed() {
setTimeout(function() {
console.log(this.name); // 错误:this指向window/global
}, 100);
},
printNameCorrect() {
setTimeout(() => {
console.log(this.name); // 正确:箭头函数继承this
}, 100);
}
};
javascript复制// 数组去重
const numbers = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(numbers)]; // [1,2,3,4,5]
// 数组扁平化
const nested = [1, [2, [3, [4]], 5]];
const flat1 = nested.flat(Infinity); // [1,2,3,4,5] (ES2019)
const flat2 = nested.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flat2(val) : val), []); // 递归方案
javascript复制function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
const clone = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}
// 现代简单方案(有局限性)
const clone = JSON.parse(JSON.stringify(original));
虽然本文主要关注基础语法,但了解一些前沿特性也很重要:
可选链(Optional Chaining):
javascript复制const city = user?.address?.city ?? '未知';
空值合并(Nullish Coalescing):
javascript复制const timeout = settings.timeout ?? 3000; // 只有null/undefined才会用默认值
Promise与async/await:
javascript复制async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
类字段声明:
javascript复制class Counter {
count = 0; // 类字段
increment = () => { // 箭头函数方法
this.count++;
}
}
顶层await:
javascript复制// 模块顶层可以直接使用await
const data = await fetchData();
export { data };
掌握这些基础语法后,你可以更自信地探索JavaScript的高级主题,如闭包、原型继承、设计模式等。记住,编程语言的学习是一个持续的过程,不断实践才能融会贯通。