JavaScript 基础:变量、函数与DOM操作

2019-08-20 前端

JavaScript 是 Web 的核心编程语言,为网页带来了交互性。HTML 提供结构,CSS 提供样式,而 JavaScript 让网页「活」起来。本文将带你学习 JavaScript 的基础知识:变量声明、数据类型、函数、DOM 操作和事件处理,最后实现一个实战轮播图。

JavaScript 概述

JavaScript(简称 JS)是一种动态类型的弱类型脚本语言。它可以在浏览器中运行,也可以在 Node.js 环境下运行与服务端代码。

<!-- 引入方式 1:内部脚本 -->
<script>
  console.log('Hello, JS!');
</script>

<!-- 引入方式 2:外部脚本(推荐) -->
<script src="script.js"></script>

<!-- 注意:<script> 可以放在 <head> 或 <body> 末尾 -->
<!-- 放在末尾是传统最佳实践(现在可以用 defer/async 属性) -->

变量声明:var、let 与 const

ES6(ES2015)引入了 let 和 const,现在已成为标准。

// --- var(旧式,尽量避免使用)---
var name = '张三';
var name = '李四';  // var 允许重复声明,容易造成 bug
console.log(name);   // '李四'

// --- let(可变的变量,推荐代替 var)---
let age = 25;
age = 26;            // let 可以重新赋值
// let age = 27;     // ❌ 错误:let 不允许重复声明

// --- const(常量,值不可重新赋值)---
const PI = 3.14159;
// PI = 3;           // ❌ 错误:const 不能被重新赋值

// 注意:const 对象的内容可以修改
const person = { name: '张三' };
person.name = '李四'; // ✅ 可以修改属性
// person = {};      // ❌ 不能重新赋值

变量作用域

关键字 作用域 变量提升 重复声明
var 函数作用域 是(初始化为 undefined) 允许
let 块级作用域 {} 是(但暂存死区 TDZ) 禁止
const 块级作用域 {} 是(但暂存死区 TDZ) 禁止
// 块级作用域对比
{
  var a = 1;    // 函数作用域,跳出块也能访问
  let b = 2;    // 块级作用域,跳出块无法访问
  const c = 3;  // 块级作用域
}
console.log(a); // 1
// console.log(b); // ❌ ReferenceError
// console.log(c); // ❌ ReferenceError

数据类型

JavaScript 有 7 种基本数据类型(原始类型)和 1 种引用类型(对象)。

类型检测

typeof 42;          // "number"
typeof 'hello';     // "string"
typeof true;        // "boolean"
typeof undefined;   // "undefined"
typeof null;        // "object"  —— 这是 JS 的一个历史遗留 bug!
typeof Symbol();    // "symbol"
typeof 123n;        // "bigint"
typeof {};          // "object"
typeof [];          // "object"
typeof function(){} // "function"

// 检测数组的正确方法
Array.isArray([1, 2, 3]); // true

函数

函数是可复用的代码块,JavaScript 中有多种定义方式。

函数声明

// 函数声明(会提升,可以在声明前调用)
function greet(name) {
  return `你好,${name}!`;
}
console.log(greet('张三')); // "你好,张三!"

函数表达式

// 函数表达式(不提升,必须先赋值再调用)
const add = function(a, b) {
  return a + b;
};
console.log(add(3, 5)); // 8

箭头函数(ES6 推荐)

// 箭头函数——更简洁
const subtract = (a, b) => a - b;
console.log(subtract(10, 3)); // 7

// 多行时用花括号 + return
const multiply = (a, b) => {
  console.log(`计算 ${a} * ${b}`);
  return a * b;
};

// 只有一个参数时可以省略括号
const square = x => x * x;

// 没有参数时也要写空括号
const hello = () => 'Hello!';

参数的默认值与剩余参数

// 默认参数
function greet(name = '访客') {
  return `你好,${name}!`;
}
console.log(greet()); // "你好,访客!"

// 剩余参数(Rest 参数):将多余参数转为数组
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

DOM 操作

DOM(Document Object Model)是 HTML 文档的编程接口。JavaScript 通过 DOM API 来读取和修改页面内容。

获取元素

// 通过 ID 获取(返回单个元素或 null)
const title = document.getElementById('title');

// 通过 CSS 选择器获取第一个匹配元素(推荐用法)
const firstCard = document.querySelector('.card');

// 通过 CSS 选择器获取所有匹配元素(返回 NodeList)
const allCards = document.querySelectorAll('.card');
// NodeList 可用 forEach 遍历
allCards.forEach(card => console.log(card));

// 旧式方法(不推荐,但仍在大量代码中)
document.getElementsByClassName('card');  // HTMLCollection
document.getElementsByTagName('div');     // HTMLCollection

修改内容与属性

const el = document.querySelector('.title');

// 修改文本内容
el.textContent = '新标题';            // 纯文本,安全(不解析 HTML)
el.innerText = '另一个标题';          // 考虑了 CSS 隐藏(较慢)

// 修改 HTML 内容(⚠️ 小心 XSS!)
el.innerHTML = '<span>带标签的文字</span>';

// 修改属性
el.setAttribute('data-id', '123');
console.log(el.getAttribute('data-id'));

// 操作 CSS 类
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('expanded');
console.log(el.classList.contains('active')); // true

// 直接修改样式
el.style.color = 'red';
el.style.fontSize = '20px';  // 注意使用驼峰命名

创建与插入元素

// 创建新元素
const newDiv = document.createElement('div');
newDiv.textContent = '我是新创建的元素';
newDiv.classList.add('box');

// 插入到 DOM
const container = document.querySelector('.container');
container.appendChild(newDiv);       // 末尾追加
container.prepend(newDiv);           // 开头插入
container.insertBefore(newDiv, ref); // 在 ref 前插入

// 模板方式插入(支持 HTML)
container.insertAdjacentHTML('beforeend', '<p>新的段落</p>');
// 选项:'beforebegin', 'afterbegin', 'beforeend', 'afterend'

// 删除元素
newDiv.remove();  // 直接移除自身(现代方法)
// 或者:container.removeChild(newDiv);

事件处理

事件是用户与页面交互的桥梁。JavaScript 通过事件监听器来响应各种操作。

// 添加事件监听(推荐方式)
const button = document.querySelector('#btn');
button.addEventListener('click', function(event) {
  console.log('按钮被点击了!', event);
});

// 事件对象 event —— 包含事件的详细信息
button.addEventListener('click', (e) => {
  console.log(e.target);       // 触发事件的元素
  console.log(e.type);         // 事件类型:"click"
  e.preventDefault();          // 阻止默认行为(如表单提交)
  e.stopPropagation();         // 阻止事件冒泡
});

常用事件类型

// 鼠标事件
element.addEventListener('click', handler);    // 点击
element.addEventListener('dblclick', handler); // 双击
element.addEventListener('mouseover', handler);// 悬停
element.addEventListener('mouseout', handler); // 移出
element.addEventListener('mousedown', handler);// 按下
element.addEventListener('mouseup', handler);  // 松开

// 键盘事件
element.addEventListener('keydown', handler);  // 按下
element.addEventListener('keyup', handler);    // 松开
// 从 event.key 获取按键名称
document.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') console.log('回车键被按下');
  if (e.key === 'Escape') console.log('ESC 被按下');
});

// 表单事件
element.addEventListener('submit', handler);   // 表单提交
element.addEventListener('input', handler);    // 输入变化
element.addEventListener('change', handler);   // 值改变(失去焦点)
element.addEventListener('focus', handler);    // 获得焦点
element.addEventListener('blur', handler);     // 失去焦点

// 文档/窗口事件
document.addEventListener('DOMContentLoaded', handler);
// DOM 加载完毕(不等图片等资源),适合在此启动 JS
window.addEventListener('load', handler);       // 所有资源加载完毕
window.addEventListener('scroll', handler);     // 滚动
window.addEventListener('resize', handler);     // 窗口大小变化

事件冒泡与捕获

<div id="outer">
  <button id="inner">点击我</button>
</div>

<script>
  document.querySelector('#outer').addEventListener('click', () => {
    console.log('外层 div(冒泡阶段)');
  });
  document.querySelector('#inner').addEventListener('click', (e) => {
    console.log('按钮(冒泡阶段)');
    e.stopPropagation(); // 阻止冒泡到外层
  });
  // 冒泡顺序:inner → outer → body → document
</script>

实战:轮播图

下面实现一个完整的自动轮播图:

总结

本文介绍了 JavaScript 的基础知识:

  1. 变量声明:let 和 const 替代 var
  2. 数据类型:7 种原始类型 + 对象
  3. 函数:声明式、表达式、箭头函数
  4. DOM 操作:获取元素、修改内容、创建和插入元素
  5. 事件处理:事件监听、事件类型、冒泡机制
  6. 实战:完整的轮播图实现

JavaScript 的世界非常大,本文只是为你打开一扇门。持续练习是掌握 JS 的唯一途径!

扩展阅读