【JavaScript】核心语法全攻略:从零基础到面向对象实战
JavaScript 是一种高级的、解释型的编程语言。
- 高级:意味着它更接近人类语言(英语),而不是枯燥的机器指令(0 和 1)。
- 解释型:意味着代码不需要复杂的“翻译”过程,浏览器拿到代码就能直接执行。
如果说HTML是房子的框架,那么CSS就是房子的装修,而JavaScript就是房子的智能系统。
和java并无关系,只是名字像而已。
一,导入JS
1.行内式
直接把代码写在 HTML 标签的属性里(比如 onclick)。
<button onclick="alert('点我干嘛?')">点我</button>
2.内部式
在 HTML 文档中使用
<script>
let message = "欢迎来到 JS 世界";
console.log(message);
</script>
3.外部式
像 CSS 引入 .css 一样,JS 也有自己的 .js 文件。
在 HTML 中写:
<script src="myCode.js"></script>,
意思就是从这个文件中读取。
注意,在这里,如果引入了外部文件,还想在再这里写当前网页的专属逻辑时,需要分两个标签写,写在引入外部文件的script中时就会无视内部的代码。
还有,默认情况下,他会严格按照在HTML中书写script标签的先后顺序来执行。
所以,浏览器在解析 HTML 时,如果遇到一个普通的外部 JS 标签,它会执行以下动作:
- 停止解析后面的 HTML。
- 下载这个 JS 文件。
- 运行这个 JS 文件。
- 继续解析后面的 HTML 或下一个
所以,如果你的第一个 JS 文件 main.js 体积巨大或者服务器网速极慢,第二个 <script> 里的代码就只能在那干等着,而且用户此时看到的网页可能也是卡住的、半成品的。
为了不让网页因为等 JS 而卡死,现代开发通常会给标签加两个属性:
-
defer(最推荐,推迟执行)
<script src="main.js" defer></script> <script src="other.js" defer></script>浏览器在后台默默下载 JS,不耽误继续画网页
-
async(异步执行)
<script src="main.js" async></script>谁先下完谁先跑。
二,基础语法
1.变量
在 JS 里,你想记住一个数字或一段话,必须把它放进变量里。
最常用以下关键字。
let age = 18; // 声明一个叫 age 的变量,存入 18
const name = "JS"; // 声明一个叫 name 的常量
age = 19; // 没问题,修改了变量的值
// name = "Java"; // 报错!常量不能改
还可以用var,但是需要避免使用,除非要维护遗留代码或理解特殊行为。
var声明的变量会成为window(浏览器)或global的属性,
它可以重复声明同名变量,后面的覆盖前面的。
它会被提升到作用域顶部,但只提升声明,初始化仍然在原位置,声明前访问回事undefined,let就不能在声明前使用,会报错。
2. 数据类型
JS 是一门“聪明”的语言,它会根据你写的内容自动判断类型。
1. 基本数据类型(7 种)
| 类型 | 例子 | 描述 |
|---|---|---|
| String (字符串) | "Hello" |
文本,必须用引号(单双引号均可) |
| Number (数字) | 100, 3.14 |
所有的数字,不分整数小数 |
| Boolean (布尔) | true, false |
只有“对”和“错”两种状态 |
| Undefined | let x; |
声明了变量但没给值,它就是“未定义” |
| Null | null |
表示“空”,通常用来清空一个变量 |
| Symbol (符号) | Symbol("id") |
创建唯一标识符,常用于对象属性名,避免冲突 |
| BigInt (大整数) | 9007199254740991n |
表示超大整数,末尾必须加 n |
2. 引用类型(Object 及其衍生)
| 类型 | 例子 | 描述 |
|---|---|---|
| Object (对象) | { name: "张三" } |
复杂数据,可以装很多属性 |
| Array (数组) | [1, 2, 3] |
有序的数据列表,可以装多个值(类型可不相同) |
| Function (函数) | function fn() {} |
可执行的代码块,本身也是一种特殊的对象 |
| Date (日期) | new Date() |
处理日期和时间 |
| RegExp (正则) | /ab+c/ |
用于模式匹配 |
3. 如何区分数组和普通对象?
let arr = [1, 2, 3];
let obj = { 0: 1, 1: 2, 2: 3 };
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(obj)); // false
4. typeof 的常见陷阱
typeof "hello" // "string"
typeof 123 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ❌ JS 遗留的 bug
typeof {} // "object"
typeof [] // "object" ❌ 数组也返回 "object"
typeof function(){} // "function" ✅
typeof Symbol() // "symbol"
typeof 123n // "bigint"
判断
null的正确方法:value === null
判断数组的正确方法:Array.isArray(value)
3.运算符
和python并无什么不同。。。
算术运算符(加减乘除 + 取余)
+:加法-:减法*:乘法/:除法%:取余数(例如10 % 3的结果是1)
赋值运算符
=:把右边的值赋给左边的变量(例如x = 10)
比较运算符
>:大于<:小于===:严格相等(值和类型都必须相同,推荐使用)==:宽松相等(会尝试自动转换类型再比较,容易产生 Bug,不推荐使用)
注意:判断相等一定要用
===,不要用==。
逻辑运算符
&&(AND):两者都为真,结果才为真||(OR):只要有一个为真,结果就为真!(NOT):取反(真变假,假变真)
4. 流程控制
和 Python 也差不多,就是格式的不同(Python 用缩进和冒号,JS 用花括号 {} 和分号)。
① 条件判断:if...else
let score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
② 多分支精确匹配:switch
当有多个固定值需要匹配时,比多个 else if 更清晰。
let grade = "B";
switch (grade) {
case "A":
console.log("90分以上");
break; // 跳出 switch,不加会继续往下执行
case "B":
console.log("80分以上");
break;
case "C":
console.log("70分以上");
break;
default:
console.log("需要努力");
}
switch使用严格相等===判断,注意break的穿透问题。
③ 循环结构
| 循环类型 | 适用场景 | 示例代码 |
|---|---|---|
for |
知道循环次数(最常用) | for (let i = 0; i < 5; i++) { ... } |
while |
条件前置,循环次数未知 | while (条件) { ... } |
do...while |
至少执行一次再判断 | do { ... } while (条件); |
示例:
// for 循环
for (let i = 0; i < 5; i++) {
console.log("当前数字是:" + i);
}
// while 循环
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
// do...while (至少执行一次)
let j = 10;
do {
console.log("至少运行一次");
j++;
} while (j < 5);
④ 循环控制:break 与 continue
break:立即跳出整个循环(或switch)。continue:跳过本次循环的剩余代码,直接进入下一次迭代。
for (let i = 0; i < 5; i++) {
if (i === 2) continue; // 跳过 i=2 时的输出
if (i === 4) break; // 到 i=4 时完全停止循环
console.log(i); // 输出 0, 1, 3
}
⑤ 专门用于遍历的循环
| 循环 | 适用对象 | 示例 |
|---|---|---|
for...in |
对象的键(属性名) | for (let key in obj) { ... } |
for...of |
可迭代对象的值(数组、字符串、Map、Set) | for (let val of arr) { ... } |
// 对象用 for...in
let person = { name: "张三", age: 18 };
for (let key in person) {
console.log(key, person[key]);
}
// 数组用 for...of
let arr = [10, 20, 30];
for (let value of arr) {
console.log(value); // 10, 20, 30
}
for...in遍历数组会得到索引(字符串),通常不推荐;遍历数组推荐用for或for...of。
补充,Map和Set是什么?forEach方法?
在上面提到for……of的时候有说他们是可迭代对象,但是之前没遇到过。
- Map(映射)是一种键值对的集合,任何值都可以作为键或者值,它比传统的普通对象更灵活。
map.size可以获取大小,相比较{}来说,它频繁增删键值对更好。
使用set(键,值)添加键值对,get获取,has判断,clear清空。 - Set是一种值的有序集合,它像是python中的集合那样,会自动去重。
也有size属性,使用add添加,has判断存在,delete删除,clear清空。 - forEach 并不是所有可迭代对象(iterable)都有的方法。它只存在于特定的内置类型(Array, Map, Set 等)。
总之,它可以用来很方便的获取到value,key并通过箭头函数来做处理。
5. 函数 (Functions):代码的“模具”
函数是把一段常用的代码封装起来,给它起个名字,可以重复调用。
// 1. 定义函数
function sayHi(userName) {
console.log("你好," + userName);
}
// 2. 调用函数
sayHi("阿强");
sayHi("小红");
① 返回值:return
函数可以返回一个结果,调用者可以拿到这个值继续使用。如果没有 return,函数默认返回 undefined。
function add(a, b) {
return a + b; // 返回计算结果
}
let result = add(3, 5);
console.log(result); // 8
return会立刻结束函数执行,后面的代码不再运行。
② 参数默认值
如果调用时没有传某个参数,可以给它一个默认值。
function greet(name = "匿名用户") {
console.log("Hello, " + name);
}
greet("阿强"); // Hello, 阿强
greet(); // Hello, 匿名用户
③ 函数表达式:把函数赋给变量
函数也可以当作值,赋给变量。这种写法叫函数表达式。
const sayHi = function(userName) {
console.log("你好," + userName);
};
sayHi("阿强");
函数表达式与函数定义的区别:函数定义会被“提升”,可以在定义前调用;函数表达式必须先赋值后调用。
④ 箭头函数 (Arrow Function):ES6 简洁写法
语法更短,并且它内部的 this 行为与普通函数不同(适合回调场景)。
// 普通写法
const add1 = function(a, b) {
return a + b;
};
// 箭头函数写法
const add2 = (a, b) => a + b; // 单行可省略 { return }
console.log(add2(3, 5)); // 8
箭头函数简化规则:
- 只有一个参数时,括号可省略:
x => x * 2 - 函数体只有一条
return语句时,可省略{}和return
⑤ 函数作用域
函数内部声明的变量,外部无法访问(局部变量)。函数可以访问外部(全局)变量。
let globalVar = "我是全局的";
function test() {
let localVar = "我是局部的";
console.log(globalVar); // ✅ 可以访问全局
}
test();
console.log(localVar); // ❌ 报错:localVar is not defined
⑥ 回调函数:把函数当作参数传给另一个函数
这是 JavaScript 中非常常见的模式,例如事件处理、定时器、数组遍历。
function processUserInput(callback) {
let name = "张三";
callback(name); // 调用传进来的函数
}
// 传入一个匿名函数作为回调
processUserInput(function(name) {
console.log("你好," + name);
});
箭头函数常用于回调:
[1, 2, 3].forEach(item => {
console.log(item * 2);
});
⑦ 立即执行函数 (IIFE)
定义后立刻执行,常用于创建一个独立的作用域,避免污染全局。
(function() {
let temp = "只能在内部访问";
console.log("函数已执行");
})();
⑧ 函数声明与函数表达式的区别(提升)
| 类型 | 示例 | 能否在定义前调用 |
|---|---|---|
| 函数声明 | function foo() {} |
✅ 可以(被提升) |
| 函数表达式 | const foo = function() {} |
❌ 不可以 |
// 函数声明 - 可以提前调用
sayHello(); // 正常运行
function sayHello() { console.log("Hello"); }
// 函数表达式 - 提前调用会报错
sayHi(); // ❌ Cannot access 'sayHi' before initialization
const sayHi = function() { console.log("Hi"); };
⑨ 常见内置函数举例
| 函数 | 作用 | 示例 |
|---|---|---|
console.log() |
打印输出 | console.log("hello") |
parseInt() |
字符串转整数 | parseInt("3.14") → 3 |
parseFloat() |
字符串转浮点数 | parseFloat("3.14") → 3.14 |
setTimeout() |
延迟执行 | setTimeout(() => console.log("1秒后"), 1000) |
setInterval() |
循环定时执行 | setInterval(() => console.log("每2秒"), 2000) |
⑩ 各场景推荐
| 场景 | 推荐写法 |
|---|---|
| 简单单行计算 | 箭头函数(省略 {} 和 return) |
需要自己的 this 或不熟悉 this 规则 |
普通函数(function) |
| 需要提前调用(提升) | 函数声明 |
| 作为另一个函数的参数(回调) | 箭头函数 或 匿名函数表达式 |
| 需要立即执行并隔离作用域 | IIFE(立即执行函数) |
6. 对象(Object):复杂数据的容器
在 JS 中,对象是属性(变量)和方法(函数)的集合。它就像一个真实的物体,既有状态(长什么样),又有行为(能做什么)。
6.1 创建与属性访问(语法细节)
创建对象最标准的方式是 字面量。但在访问属性时,有两种非常重要的语法:
let user = {
name: "张三",
"my-age": 18, // 含有特殊字符的键必须加引号
city: "北京"
};
// 1. 点表示法 (Dot Notation) —— 最常用
console.log(user.name);
// 2. 方括号表示法 (Bracket Notation) —— 两种必选场景:
// 场景 A:键名不符合变量命名规则(如含有横杠、数字开头)
console.log(user["my-age"]);
// 场景 B:键名存在变量里(动态访问)
let key = "city";
console.log(user[key]); // 等同于 user.city
6.2 属性的动态增删
JS 的对象是动态的,你可以在程序运行的任何时候修改它的结构。
let car = { brand: "Tesla" };
// 新增
car.color = "红色";
// 修改
car.brand = "BYD";
// 删除 (使用 delete 关键字)
delete car.color;
console.log(car.color); // 输出 undefined,因为已经被删除了
6.3 对象的方法与 this 关键字
方法是存储在对象属性中的函数。this 关键字是对象的“自称”。
let player = {
nickname: "头号玩家",
level: 10,
// ES6 简写方法语法
upgrade() {
// this 指向调用这个方法的对象
this.level++;
console.log(`${this.nickname} 升级了!当前等级:${this.level}`);
}
};
player.upgrade();
使用字面量的方式创建对象,更适合创建一个独立,唯一存在的单例,不需要复用。
待会要讲的class才适合多个相似对象,它和python中的class很像。
6.4 遍历与静态工具方法
当你有一堆数据存在对象里时,你需要手段把它们拿出来。
| 方法 | 作用 | 返回值类型 |
|---|---|---|
for...in |
遍历对象所有的键名 | 循环执行 |
Object.keys(obj) |
获取对象所有键名 | 数组 (Array) |
Object.values(obj) |
获取对象所有键值 | 数组 (Array) |
示例代码:
let scores = { math: 90, english: 80 };
// 遍历
for (let subject in scores) {
console.log(`${subject} 的分数是 ${scores[subject]}`);
}
// 快速检查
console.log(Object.keys(scores)); // ["math", "english"]
6.5 现代类与继承 (Class & Inheritance)
这是目前大型项目中最主流的写法。它让代码看起来更有条理。
// 1. 类:对象的蓝图
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
showInfo() {
console.log(`用户: ${this.name}, 邮箱: ${this.email}`);
}0
}
// 2. 继承:在蓝图基础上扩展
class Admin extends User {
constructor(name, email, role) {
super(name, email); // 必须先调用 super,继承父类的初始化逻辑
this.role = role;
}
// 重写父类方法
showInfo() {
super.showInfo(); // 先执行父类的逻辑
console.log(`权限级别: ${this.role}`);
}
}
const boss = new Admin("老王", "wang@test.com", "超级管理员");
boss.showInfo();
6.6 核心必读:解构赋值 (Destructuring)
这是 ES6 引入的极简语法,现在几乎随处可见。
const settings = { theme: "Dark", fontSize: "14px", showSidebar: true };
// 以前:let theme = settings.theme;
// 现在:直接从对象中“提取”出同名变量
const { theme, fontSize } = settings;
console.log(theme); // "Dark"
更多推荐

所有评论(0)