JavaScript 基础语法
一、JavaScript 简介
JavaScript是一种运行在浏览器中的脚本语言,用于为网页添加交互功能。它的核心部分称为 ECMAScript,每年发布一个新版本,目前主流使用的是 ES6及之后的版本。
JS 代码有三种引入方式:
html
<!-- 1. 内联:直接写在 HTML 标签的事件属性中 -->
<button onclick="alert('点击了')">点击</button>
<!-- 2. 内部:写在 <script> 标签中 -->
<script>
console.log('Hello World');
</script>
<!-- 3. 外部:通过 src 引入独立的 .js 文件 -->
<script src="app.js"></script>
console.log() 是最常用的调试手段,用于在浏览器控制台输出信息。
二、变量与常量
2.1 声明方式
JS 有三种声明变量的关键字:var、let、const。
js
// var:ES5 时代的声明方式,有变量提升和作用域问题,现在较少使用
var name = '张三';
// let:ES6 引入,块级作用域,可以重新赋值
let age = 20;
age = 21; // 允许
// const:ES6 引入,块级作用域,声明后不可重新赋值
const PI = 3.14;
// PI = 3.15; // 报错:Assignment to constant variable
// 声明但不赋值,默认值为 undefined
let x;
console.log(x); // undefined
| 关键字 | 作用域 | 可重新赋值 | 变量提升 | 推荐使用 |
|---|---|---|---|---|
| var | 函数级 | 是 | 是 | 不推荐 |
| let | 块级 | 是 | 否 | 推荐 |
| const | 块级 | 否 | 否 | 首选 |
2.2 命名规则
- 由字母、数字、下划线
_和美元符号$组成 - 不能以数字开头
- 区分大小写(
name和Name是两个变量) - 不能使用保留字(如
if、for、class等) - 习惯使用驼峰命名法:
firstName、userAge、isActive
三、数据类型
JS 的数据类型分为基本类型 和引用类型。
3.1 基本类型
js
// 1. Number ------ 数字(整数和浮点数统一为一种类型)
let count = 100;
let price = 19.99;
console.log(typeof count); // "number"
// 2. String ------ 字符串(单引号、双引号、反引号均可)
let msg1 = 'hello';
let msg2 = "world";
let msg3 = `你好`; // 反引号支持模板字符串
// 模板字符串:可以在字符串中嵌入变量和表达式
let name = '小明';
let greeting = `我的名字是 ${name},我今年 ${20 + 1} 岁`;
console.log(greeting); // "我的名字是 小明,我今年 21 岁"
// 3. Boolean ------ 布尔值,只有 true 和 false
let isLogin = true;
let isVip = false;
// 4. Undefined ------ 未定义,变量声明但未赋值时的默认值
let something;
console.log(something); // undefined
console.log(typeof something); // "undefined"
// 5. Null ------ 空值,表示"什么都没有",需要主动赋值
let obj = null;
console.log(typeof obj); // "object"(这是一个历史遗留 bug)
// 6. Symbol ------ 符号,创建唯一标识
let id1 = Symbol('id');
let id2 = Symbol('id');
console.log(id1 === id2); // false,即使描述相同,Symbol 也是唯一的
3.2 引用类型
最常用的引用类型是对象。数组、函数等本质上都是对象。
js
// 对象
let person = {
name: '小红',
age: 18
};
// 数组
let fruits = ['苹果', '香蕉', '橘子'];
// 函数
function sayHello() {
console.log('hello');
}
// 引用类型的特点:赋值时传递的是引用(地址),而非复制值
let a = [1, 2, 3];
let b = a;
b.push(4);
console.log(a); // [1, 2, 3, 4],a 也被修改了
3.3 typeof 运算符
typeof 用于检测数据类型:
js
console.log(typeof 42); // "number"
console.log(typeof 'hello'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(注意:历史遗留,null 不是对象)
console.log(typeof Symbol()); // "symbol"
console.log(typeof 10n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"(数组也是对象)
console.log(typeof function(){});// "function"
四、运算符
4.1 算术运算符
js
let a = 10;
let b = 3;
console.log(a + b); // 13 加法
console.log(a - b); // 7 减法
console.log(a * b); // 30 乘法
console.log(a / b); // 3.33333... 除法
console.log(a % b); // 1 取余
console.log(a ** b); // 1000 幂运算(ES6)
console.log(++a); // 11 自增(先加后用)
console.log(a++); // 11 自增(先用后加)
console.log(a); // 12
console.log(--a); // 11 自减
4.2 赋值运算符
js
let x = 10;
x += 5; // x = x + 5 → 15
x -= 3; // x = x - 3 → 12
x *= 2; // x = x * 2 → 24
x /= 4; // x = x / 4 → 6
x %= 4; // x = x % 4 → 2
4.3 比较运算符
js
// 等值比较
console.log(5 == '5'); // true (值相等,会做类型转换)
console.log(5 === '5'); // false (全等,值和类型都必须相同)
console.log(5 != '5'); // false (不等,会做类型转换)
console.log(5 !== '5'); // true (不全等,类型不同直接返回 true)
// 大小比较
console.log(10 > 5); // true
console.log(10 >= 10); // true
console.log(3 < 1); // false
console.log(3 <= 3); // true
实践中优先使用 === 和 !==,避免因隐式类型转换导致的意外结果。
4.4 逻辑运算符
js
// 与(&&):两边都为 true 才返回 true
console.log(true && true); // true
console.log(true && false); // false
// 或(||):至少一边为 true 就返回 true
console.log(true || false); // true
console.log(false || false); // false
// 非(!):取反
console.log(!true); // false
console.log(!false); // true
// 短路求值 ------ 常用技巧
let name = '';
let displayName = name || '匿名用户'; // 如果 name 为空,使用默认值
console.log(displayName); // "匿名用户"
let obj = {};
let result = obj && obj.name; // 如果 obj 存在,再访问它的属性
console.log(result); // undefined,没有报错
4.5 运算符优先级
从高到低:括号 () → 算术 * / % → 算术 + - → 比较 > < >= <= → 等值 == === != !== → 逻辑 && → 逻辑 || → 赋值 =。
不确定优先级时,直接用括号明确意图即可。
五、流程控制
5.1 if / else if / else
js
let score = 85;
if (score >= 90) {
console.log('优秀');
} else if (score >= 80) {
console.log('良好');
} else if (score >= 60) {
console.log('及格');
} else {
console.log('不及格');
}
// 输出:良好
5.2 三元运算符
条件 ? 成立时的值 : 不成立时的值
js
let age = 20;
let canEnter = age >= 18 ? '可以进入' : '不可进入';
console.log(canEnter); // "可以进入"
5.3 switch 语句
js
let day = 3;
switch (day) {
case 1:
console.log('星期一');
break; // 别忘了 break,否则会"穿透"到下一个 case
case 2:
console.log('星期二');
break;
case 3:
console.log('星期三');
break;
default: // 以上都不匹配时执行
console.log('其他日期');
}
// 输出:星期三
5.4 循环
js
// for 循环 ------ 已知循环次数时使用
for (let i = 0; i < 5; i++) {
console.log(`第 ${i + 1} 次循环`);
}
// while 循环 ------ 条件为真就一直执行
let count = 0;
while (count < 3) {
console.log(`count = ${count}`);
count++;
}
// do...while 循环 ------ 至少执行一次,再判断条件
let num = 0;
do {
console.log(`num = ${num}`);
num++;
} while (num < 0); // 条件为 false,但循环体已经执行了一次
// break ------ 跳出整个循环
for (let i = 0; i < 10; i++) {
if (i === 5) break;
console.log(i); // 0 1 2 3 4
}
// continue ------ 跳过当前这次循环,继续下一次
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i); // 0 1 3 4
}
六、函数
6.1 函数声明
js
// 方式一:函数声明(会被提升,可以在定义前调用)
function add(a, b) {
return a + b;
}
console.log(add(3, 5)); // 8
// 方式二:函数表达式(不会被提升,必须先定义再调用)
const multiply = function(a, b) {
return a * b;
};
console.log(multiply(3, 5)); // 15
// 方式三:箭头函数(ES6,更简洁)
const subtract = (a, b) => {
return a - b;
};
// 如果函数体只有一行 return,可以进一步简写
const divide = (a, b) => a / b;
console.log(divide(10, 2)); // 5
// 如果只有一个参数,参数的括号也可以省略
const square = x => x * x;
console.log(square(4)); // 16
6.2 参数
js
// 默认参数(ES6)------ 不传参时使用默认值
function greet(name = '访客') {
console.log(`你好,${name}`);
}
greet('小明'); // 你好,小明
greet(); // 你好,访客
// 剩余参数(...)------ 将多余的实参收集成一个数组
function sum(...numbers) {
let total = 0;
for (let n of numbers) {
total += n;
}
return total;
}
console.log(sum(1, 2, 3, 4)); // 10
// arguments 对象 ------ 函数内部可以访问所有传入的实参(类数组)
function showArgs() {
console.log(arguments); // Arguments(3) [1, 2, 3]
console.log(arguments[0]); // 1
console.log(arguments.length);// 3
}
showArgs(1, 2, 3);
6.3 返回值
js
// 函数默认返回 undefined
function noReturn() {
let x = 10;
// 没有 return,默认返回 undefined
}
console.log(noReturn()); // undefined
// return 会立即结束函数执行
function check(num) {
if (num < 0) {
return '负数'; // 遇到 return,后面的代码不再执行
}
return '非负数';
}
console.log(check(-5)); // "负数"
七、数组
7.1 创建数组
js
// 字面量创建(推荐)
let arr1 = [1, 2, 3, 4, 5];
// 构造函数创建
let arr2 = new Array(1, 2, 3);
// 创建指定长度的空数组
let arr3 = new Array(5); // 长度为 5 的空数组,每个元素为 undefined
// 通过索引访问和修改
console.log(arr1[0]); // 1
arr1[0] = 10; // 修改第一个元素
console.log(arr1); // [10, 2, 3, 4, 5]
// 数组可以存放不同类型的数据(虽然不推荐混放)
let mixed = [1, 'hello', true, { name: 'test' }, [1, 2]];
7.2 常用方法
js
let arr = [1, 2, 3];
// --- 增删 ---
arr.push(4); // 尾部添加,返回新长度 4,arr 变为 [1,2,3,4]
arr.pop(); // 尾部删除,返回被删元素 4,arr 变为 [1,2,3]
arr.unshift(0); // 头部添加,返回新长度 4,arr 变为 [0,1,2,3]
arr.shift(); // 头部删除,返回被删元素 0,arr 变为 [1,2,3]
// --- 查找 ---
let nums = [10, 20, 30, 20];
console.log(nums.indexOf(20)); // 1(从左查找,返回第一个匹配的索引)
console.log(nums.lastIndexOf(20)); // 3(从右查找)
console.log(nums.indexOf(999)); // -1(没找到)
console.log(nums.includes(30)); // true(ES6,是否存在)
// --- 排序 ---
let letters = ['c', 'a', 'b'];
letters.sort();
console.log(letters); // ['a', 'b', 'c']
let nums2 = [3, 1, 10, 2];
nums2.sort(); // 默认按字符串排序
console.log(nums2); // [1, 10, 2, 3],不是预期的结果
nums2.sort((a, b) => a - b); // 传入比较函数,按数值升序
console.log(nums2); // [1, 2, 3, 10]
letters.reverse(); // 反转
console.log(letters); // ['c', 'b', 'a']
// --- 切割与拼接 ---
let arr2 = [1, 2, 3, 4, 5];
console.log(arr2.slice(1, 3)); // [2, 3](截取索引 1 到 3-1,原数组不变)
console.log(arr2.slice(2)); // [3, 4, 5](从索引 2 截取到末尾)
// splice 会修改原数组:splice(起始索引, 删除个数, 要添加的元素...)
let arr3 = [1, 2, 3, 4, 5];
arr3.splice(2, 1); // 从索引 2 开始删除 1 个元素 → arr3 变为 [1,2,4,5]
arr3.splice(1, 0, 'a', 'b'); // 在索引 1 处插入 → arr3 变为 [1,'a','b',2,4,5]
// --- 连接 ---
let a = [1, 2];
let b = [3, 4];
let c = a.concat(b);
console.log(c); // [1, 2, 3, 4],原数组不变
7.3 遍历数组
js
let arr = ['a', 'b', 'c'];
// 传统 for 循环
for (let i = 0; i < arr.length; i++) {
console.log(i, arr[i]);
}
// for...of(ES6)------ 遍历值
for (let item of arr) {
console.log(item); // 'a', 'b', 'c'
}
// forEach ------ 对每个元素执行回调
arr.forEach(function(item, index) {
console.log(index, item);
});
八、对象
8.1 创建对象
js
// 字面量创建(最常用)
let person = {
name: '小明',
age: 20,
isStudent: true,
// 方法:对象的属性值为函数
sayHello: function() {
console.log(`你好,我是 ${this.name}`);
}
};
// 访问属性
console.log(person.name); // 点号访问 → "小明"
console.log(person['age']); // 方括号访问 → 20
// 修改和新增属性
person.age = 21; // 修改已有属性
person.city = '北京'; // 新增属性
console.log(person.city); // "北京"
// 删除属性
delete person.city;
console.log(person.city); // undefined
8.2 this 关键字
js
let user = {
name: '小红',
greet: function() {
console.log(this.name); // this 指向调用该方法的对象
}
};
user.greet(); // "小红"
// 箭头函数没有自己的 this,它会捕获外层作用域的 this
let car = {
brand: 'Tesla',
showBrand: function() {
// 普通函数中的 this 指向 car
console.log(this.brand);
setTimeout(() => {
// 箭头函数没有自己的 this,使用外层 showBrand 的 this
console.log(this.brand); // "Tesla"
}, 1000);
}
};
car.showBrand();
8.3 遍历对象
js
let student = {
name: '小华',
age: 22,
grade: 'A'
};
// for...in ------ 遍历对象的键
for (let key in student) {
console.log(key, student[key]);
}
// 输出:name 小华 age 22 grade A
// Object.keys() ------ 获取所有键组成的数组
console.log(Object.keys(student)); // ['name', 'age', 'grade']
// Object.values() ------ 获取所有值组成的数组
console.log(Object.values(student)); // ['小华', 22, 'A']
// Object.entries() ------ 获取键值对数组
console.log(Object.entries(student)); // [['name','小华'], ['age',22], ['grade','A']]
九、类型转换
9.1 显式转换
js
// 转为字符串
console.log(String(123)); // "123"
console.log(String(true)); // "true"
console.log((456).toString()); // "456"
// 转为数字
console.log(Number('42')); // 42
console.log(Number('3.14abc')); // NaN(Not a Number)
console.log(parseInt('42px')); // 42(解析出整数部分)
console.log(parseFloat('3.14abc')); // 3.14
// 转为布尔值
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean('')); // false(空字符串)
console.log(Boolean('hello')); // true(非空字符串)
console.log(Boolean(null)); // false
console.log(Boolean(undefined));// false
9.2 隐式转换(自动发生)
js
// 运算中的隐式转换
console.log('5' - 2); // 3(字符串转为数字)
console.log('5' + 2); // "52"(数字转为字符串,+ 号有字符串拼接功能)
console.log('5' * '2'); // 10(两个都转为数字)
// 逻辑判断中的隐式转换 ------ 假值(falsy)只有以下 6 个:
// false、0、''(空字符串)、null、undefined、NaN
// 其余所有值都是真值(truthy)
if ('') console.log('空字符串是真'); // 不执行
if (0) console.log('0 是真'); // 不执行
if (' ') console.log('空格字符串是真'); // 执行
if ([]) console.log('空数组是真'); // 执行
if ({}) console.log('空对象是真'); // 执行
十、作用域
作用域决定了变量在代码中的可访问范围。
js
// 全局作用域:在任何代码块外部声明的变量,全局可访问
let globalVar = '我是全局变量';
function test() {
// 函数作用域:在函数内部声明的变量,只能在函数内部访问
let localVar = '我是局部变量';
console.log(globalVar); // 可以访问
console.log(localVar); // 可以访问
}
test();
console.log(globalVar); // 可以访问
// console.log(localVar); // 报错:localVar is not defined
// 块级作用域(let 和 const):花括号 {} 内部声明的变量,外部不可访问
{
let blockVar = '块级变量';
const blockConst = '块级常量';
var noBlockVar = 'var 不遵循块级作用域';
}
// console.log(blockVar); // 报错
console.log(noBlockVar); // 可以访问(var 的问题所在)
作用域链 :当在函数内部访问一个变量时,JS 会先从当前作用域查找,找不到就向上一级作用域查找,直到全局作用域。如果全局也没有,则报 ReferenceError。
js
let outer = '外部';
function outerFunc() {
let inner = '内部';
function innerFunc() {
console.log(outer); // 从外层找到 → "外部"
console.log(inner); // 从外层找到 → "内部"
}
innerFunc();
}
outerFunc();
十一、字符串常用方法
js
let str = 'Hello JavaScript';
console.log(str.length); // 16(字符串长度)
console.log(str[0]); // "H"(通过索引访问字符)
console.log(str.charAt(1)); // "e"
console.log(str.indexOf('Java')); // 6(子串位置)
console.log(str.includes('Script')); // true(是否包含)
console.log(str.startsWith('Hell')); // true(是否以某字符串开头)
console.log(str.endsWith('pt')); // true(是否以某字符串结尾)
console.log(str.slice(0, 5)); // "Hello"(截取索引 0~4)
console.log(str.substring(0, 5)); // "Hello"(同上,但不支持负数索引)
console.log(str.toUpperCase()); // "HELLO JAVASCRIPT"(转大写)
console.log(str.toLowerCase()); // "hello javascript"(转小写)
console.log(' abc '.trim()); // "abc"(去除首尾空格)
console.log('a,b,c'.split(',')); // ['a', 'b', 'c'](按分隔符拆成数组)
let arr = ['我', '爱', 'JS'];
console.log(arr.join('')); // "我爱JS"(数组合并为字符串)
console.log('abc'.repeat(3)); // "abcabcabc"(重复拼接)
十二、Math 对象
js
console.log(Math.PI); // 3.141592653589793
console.log(Math.abs(-5)); // 5(绝对值)
console.log(Math.ceil(3.1)); // 4(向上取整)
console.log(Math.floor(3.9)); // 3(向下取整)
console.log(Math.round(3.5)); // 4(四舍五入)
console.log(Math.max(1, 5, 3)); // 5(最大值)
console.log(Math.min(1, 5, 3)); // 1(最小值)
console.log(Math.pow(2, 3)); // 8(2 的 3 次方)
console.log(Math.sqrt(16)); // 4(平方根)
console.log(Math.random()); // 0 ~ 1 之间的随机小数(不包括 1)
// 生成 1 到 100 之间的随机整数
let randInt = Math.floor(Math.random() * 100) + 1;