前端三大基础(又称 三大马车):
- HTML(HyperText Markup Language) —— 结构层:用于定义网页的内容和结构(标签)。
- CSS(Cascading Style Sheets) —— 渲染层:用于控制网页的样式和布局。
- JavaScript —— 行为层:用于实现网页的动态交互。
补充:HTML 负责网页的骨架,CSS 负责美化和布局,而 JavaScript 赋予网页交互性,它们共同构成了现代 Web 开发的核心技术。
JavaScript是一种高级编程语言,用于Web开发和创建交互式用户界面。它是一种动态类型语言,意味着变量类型在运行时确定。JavaScript可以在浏览器中运行,也可以在服务器端使用Node.js运行。它具有广泛的应用,包括网页开发、游戏开发、移动应用程序开发等。JavaScript具有易学性和灵活性,是Web开发中必不可少的一部分。
JavaScript 是目前最流行的编程语言之一,被广泛应用于**网页开发、游戏开发、移动应用、后端开发(Node.js)、桌面应用(Electron)**等多个领域。
学习 JavaScript 的优势:
- 前端开发的核心 —— 现代网页的交互和动态效果几乎都依赖 JavaScript。
- 生态丰富,前景广阔 —— 拥有 React、Vue、Angular 等强大的前端框架,以及 Node.js 让 JavaScript 也能用于后端开发。
- 全栈开发 —— 既能编写前端,也能处理后端逻辑,实现一站式开发。
- 高效提升开发效率 —— 通过现代前端工具(如 Webpack、Vite)和 TypeScript,可以大幅提高开发效率和代码质量。
- 强大的社区支持 —— JavaScript 拥有庞大的开发者社区和丰富的学习资源,新手学习更容易。
因此,学习 JavaScript 不仅可以帮助我们更高效地开发网页,还能拓展到更广泛的领域(如全栈、移动端、小程序等),提升职业竞争力,是前端开发者的必修技能。
JavaScript 由 Brendan Eich 在 1995 年为 Netscape 公司的浏览器 Netscape Navigator 开发,并在短短 10 天内完成了第一版。
发展历程:
- 1995 年 —— 最初命名为 LiveScript,但由于当时 Java 语言的流行,Netscape 与 Sun Microsystems 合作,将其更名为 JavaScript,实际上与 Java 关系不大。
- 1996 年 —— 微软推出 JScript,用于 IE 浏览器,与 JavaScript 类似,但存在兼容性问题。
- 1997 年 —— ECMAScript 标准诞生(ES1),JavaScript 由 ECMA(欧洲计算机制造商协会)标准化,成为 ECMAScript(ES)
- 2009 年 —— ES5 发布,新增 JSON 支持、strict mode 等特性。
- 2015 年 —— ES6(ES2015)发布,引入 let、const、箭头函数、类、模块化(import/export) 等现代特性。
- 2016 年至今 —— JavaScript 进入快速发展期,ES 每年发布新版本(如 ES7、ES8…),同时现代前端框架(React、Vue、Angular)和后端技术(Node.js)让 JavaScript 生态更加成熟。
总结:JavaScript 诞生于 Web 时代,最初用于网页交互,如今已成为 全栈开发 的核心语言,应用于前端、后端、桌面应用、移动端、游戏开发等多个领域,仍在持续进化。
JavaScript 和 ECMAScript 是同一个东西吗?不完全是。
- ECMAScript(ES) 是 JavaScript 的核心标准,由 ECMA 国际(European Computer Manufacturers Association)制定,规定了 JavaScript 语言的语法和基本功能。
- JavaScript 是 ECMAScript 的实现之一,并在 ECMAScript 标准的基础上,添加了 Web API(如 DOM、BOM)、异步操作(如 setTimeout、fetch)等功能,使其更适用于 Web 开发。
关系总结:
- ECMAScript 规定了 JavaScript 语言的基本语法,如变量、作用域、对象、函数等。
- avaScript 遵循 ECMAScript 标准,并扩展了更多的功能(如 DOM 操作、事件处理)。
- 可以认为 JavaScript 是 ECMAScript 的超集,但并不完全等同于 ECMAScript。
举例:
以下是 ECMAScript 规范内的代码:
let name = "JavaScript"; // 变量
const greet = () => `Hello, ${name}`; // 箭头函数
console.log(greet()); // 输出: Hello, JavaScript
但 DOM 操作 并不属于 ECMAScript,而是 JavaScript 在浏览器环境中的扩展:
document.getElementById("app").innerText = "Hello, JavaScript!";
总结:ECMAScript 定义了 JavaScript 的核心规则,而 JavaScript 在此基础上发展出了 更多的功能,尤其是在 Web 开发中(如 DOM 操作、事件处理)。
ECMAScript(ES) 是由 Ecma 国际(前身为欧洲计算机制造商协会)制定的脚本语言标准,用于规范 JavaScript 语法和功能。
起源:
- 1995 年,Brendan Eich 在 Netscape 开发了一种脚本语言,最初命名为 LiveScript。
- 为了借助 Java 的热度,Netscape 将其更名为 JavaScript。
- 1997 年,Netscape 将 JavaScript 提交给 Ecma 国际 进行标准化,并发布了 ECMAScript 1.0(ES1)。
ECMAScript 发展历程:
版本 | 发布时间 | 主要特性 |
---|---|---|
ES1 | 1997 | ECMAScript 诞生,定义 JavaScript 基础语法 |
ES2 | 1998 | 小幅改进,与 ISO/IEC 16262 规范对齐 |
ES3 | 1999 | 引入 try/catch 异常处理、正则表达式、JSON 支持等 |
ES4 (取消) | - | 由于意见不统一,ES4 计划被废弃 |
ES5 | 2009 | 引入 strict mode (严格模式)、JSON 、Object.defineProperty() 、Array.prototype.map() 等 |
ES6 (ES2015) | 2015 | 大量更新,包括 let 、const 、箭头函数、类(class )、Promise 、import/export 模块等 |
ES7 (ES2016) | 2016 | Array.prototype.includes() 、指数运算符 (** ) |
ES8 (ES2017) | 2017 | async/await 、Object.entries() 、Object.values() |
ES9 (ES2018) | 2018 | Promise.finally() 、Rest/Spread 语法扩展 |
ES10 (ES2019) | 2019 | flat() 、flatMap() 、Object.fromEntries() |
ES11 (ES2020) | 2020 | 可选链(?. )、空值合并(?? )、动态 import() |
ES12 (ES2021) | 2021 | String.prototype.replaceAll() 、逻辑赋值运算符 (&&= , ` |
ES13 (ES2022) | 2022 | class 私有字段(# )、top-level await |
总结:ECMAScript 由 JavaScript 标准化而来,每年都会推出新版本,为 JavaScript 语言带来更强大的功能,使其在前端、后端、移动端等领域不断发展。
JavaScript 和 Java 是 完全不同 的编程语言,它们在 语法、用途、运行环境 上都有明显区别。
- JavaScript 是一种 动态 的 脚本语言,主要用于 网页前端开发,在浏览器中运行,并由 HTML、CSS 共同构建交互式页面。
- Java 是一种 静态 的 面向对象编程语言,广泛用于 后端开发、桌面应用、移动开发(Android),需要 JVM(Java 虚拟机) 执行。
为什么 JavaScript 里有 “Java”?
JavaScript 最初在 1995 年由 Netscape 公司推出时,名称是 LiveScript。由于当时 Java 语言非常流行,Netscape 出于 营销目的,与 Sun Microsystems(Java 的开发公司)合作,将其更名为 JavaScript,但两者本质上并无关系。
在网页开发中,可以通过多种方式引入 JavaScript 代码,主要有以下几种:
直接在 HTML 标签的 onclick、onmouseover 等事件属性中写 JavaScript 代码。
<button onclick="alert('Hello, JavaScript!')">点击我</button>
✅ 优点:适用于简单的交互事件。
❌ 缺点:代码可读性差,不利于维护,不推荐使用。
在 <script> 标签内编写 JavaScript 代码,并放在 HTML 页面中。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>内部 JavaScript</title>
<script>
function showMessage() {
alert('欢迎学习 JavaScript!');
}
</script>
</head>
<body>
<button onclick="showMessage()">点击显示消息</button>
</body>
</html>
✅ 优点:适用于小型项目,代码较为集中。
❌ 缺点:HTML 和 JavaScript 耦合,影响代码的模块化。
将 JavaScript 代码写在 独立的 .js 文件 中,并在 HTML 通过 <script> 标签引入。
(1)基础用法
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>外部 JavaScript</title>
<script src="script.js"></script>
</head>
<body>
<button onclick="showMessage()">点击显示消息</button>
</body>
</html>
📂 文件结构
/project
│── index.html
│── script.js
📜 script.js
function showMessage() {
alert('Hello, 外部 JavaScript!');
}
✅ 优点:
- 代码复用性高,适合大型项目
- HTML 结构与 JavaScript 分离,提升可读性和维护性
默认情况下,<script> 会 阻塞 HTML 解析,影响页面加载速度。可以使用 defer 或 async 优化 JavaScript 加载方式。
(1)defer(延迟执行)
<script src="script.js" defer></script>
✅ 特点:
- 不会阻塞 HTML 解析,等 HTML 解析完成后再执行
- 按照 代码顺序 执行多个 defer 资源
- 适用于 依赖 DOM 结构的 JavaScript(推荐)
(2)async(异步加载)
<script src="script.js" async></script>
✅ 特点:
- 不会阻塞 HTML 解析,但下载完成后立即执行
- 多个 async 资源 执行顺序不确定,适合 不依赖 DOM 的代码(如广告、统计脚本)
- 推荐使用外部 JavaScript,保持 HTML 结构清晰
- 推荐使用 defer,确保 JavaScript 在 HTML 解析后执行
- 避免行内 JavaScript,提升代码可维护性
这里只是简单介绍一些数据结构及其特点:
栈是一种先进后出(Last In First Out, LIFO)的数据结构。它的特点是:
- 入栈(Push):将元素加入栈顶。
- 出栈(Pop):从栈顶移除元素。
- 只有栈顶的元素可以被访问。
应用场景:
- 浏览器历史记录的回退操作
- 表达式求值(如括号匹配)
- 递归算法的模拟
let stack = [];
stack.push(1); // 入栈
stack.push(2);
console.log(stack.pop()); // 出栈,输出 2
堆是一种特殊的树形数据结构,通常用于实现优先队列。它的特点是:
- 元素是部分顺序的,通常是按照完全二叉树来储存。
- 最大堆:父节点的值大于或等于子节点的值。
- 最小堆:父节点的值小于或等于子节点的值。
- 不是像栈和队列那样的顺序存储,可以通过“key”快速定位。
应用场景:
- 优先队列(如 Dijkstra 最短路径算法)
- 动态求解最大值或最小值
// 使用 JavaScript 的优先队列示例(通过堆实现)
let heap = [];
heap.push(3); // 插入元素
heap.push(1);
heap.push(2);
console.log(heap); // 堆结构显示
队列是一种先进先出(First In First Out, FIFO)的数据结构。它的特点是:
- 入队(Enqueue):将元素加入队尾。
- 出队(Dequeue):从队头移除元素。
- 队列中的元素按顺序排队,最先进入的元素最先被处理。
应用场景:
- 任务调度(如操作系统的进程调度)
- 打印任务的排队
- 异步编程中的事件队列
let queue = [];
queue.push(1); // 入队
queue.push(2);
console.log(queue.shift()); // 出队,输出 1
JavaScript 执行上下文是指在代码执行期间,JavaScript 引擎创建的一个内部数据结构,用于存储代码执行期间的变量、函数、作用域链等信息。每个执行上下文都有一个变量对象(Variable Object, VO),用于存储当前执行环境中的所有变量和函数声明。
JavaScript 代码的执行上下文主要分为三种类型:
- 全局执行上下文(Global Execution Context)
- 函数执行上下文(Function Execution Context)
- Eval 执行上下文(Eval Execution Context)(不推荐使用)
当 JavaScript 代码开始运行时,JS 引擎会首先创建一个全局执行上下文,该上下文会执行所有不在函数内部的代码,并包含以下内容:
- 创建全局对象(浏览器环境下是 window,Node.js 环境下是 global)
- 创建全局变量对象(VO)
- 将 this 绑定到全局对象
console.log(this === window); // true (浏览器环境)
var a = 10;
function test() {
console.log(a);
}
test();
在全局上下文中,this 指向全局对象 window。
每当一个函数被调用时,都会为该函数创建一个新的执行上下文,并包含:
- 函数的变量对象(VO):存储函数内部声明的变量、参数和内部函数
- 作用域链(Scope Chain):用于查找变量
- this 绑定
function foo(x) {
var y = 2;
function bar() {
console.log(x, y);
}
bar();
}
foo(5); // 输出: 5 2
在 foo 执行时,它的执行上下文会被创建,bar 也会继承 foo 的作用域链。
eval() 函数可以在运行时执行 JavaScript 代码,并会创建自己的执行上下文(但不推荐使用,因为它影响性能和安全性)。
eval("var x = 10;");
console.log(x); // 10
这里 eval 代码在执行时会创建自己的执行上下文,但它仍然会修改全局变量。
执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 销毁阶段,本文重点介绍创建阶段。
① 创建阶段
在创建阶段,js 引擎会创建一个执行上下文对象,并进行以下操作:
- 创建变量对象(Variable Object,VO):包括函数声明、函数参数、变量声明等。
- 确定 this 的指向。
- 创建作用域链(Scope Chain):用于解析变量和函数的作用域。
- 初始化变量的值:将变量初始化为 undefined。
② 执行阶段
在执行阶段,js 引擎会按照代码的顺序执行,将变量赋值、函数调用等操作加入执行栈(Execution Stack)中,直到执行栈为空。
③ 回收阶段
在销毁阶段,JavaScript 引擎会进行以下操作:
- 执行垃圾回收(Garbage Collection):回收不再使用的内存空间。
- 销毁变量对象和作用域链。
执行栈,即 “调用栈”,是一种拥有 LIFO(后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文。
js代码执行时首先会创建一个全局的执行上下文并且压入当前执行栈。每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的顶部。引擎会执行那些执行上下文位于栈顶的函数。当该函数执行结束时,执行上下文从栈中弹出,控制流程到达当前栈中的下一个上下文。
从上面的流程图,我们需要记住几个关键点:
- js执行在单线程上,所有的代码都是排队执行。
- 一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。
- 每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行完成后,当前函数的执行上下文出栈,并等待垃圾回收。
- 浏览器的 js 执行引擎总是访问栈顶的执行上下文。
- 全局上下文只有唯一的一个,它在浏览器关闭时出栈。
我们再来看个例子:
var color = 'blue';
function changeColor() {
var anotherColor = 'red';
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColors();
}
changeColor();
上述代码运行按照如下步骤:
- 当上述代码在浏览器中加载时,JavaScript 引擎会创建一个全局执行上下文并且将它推入当前的执行栈
- 调用
changeColor
函数时,此时changeColor
函数内部代码还未执行,js 执行引擎立即创建一个 changeColor 的执行上下文(简称 EC),然后把这执行上下文压入到执行栈(简称 ECStack)中。 - 执行 changeColor 函数过程中,调用
swapColors
函数,同样地,swapColors 函数执行之前也创建了一个 swapColors 的执行上下文,并压入到执行栈中。 - swapColors 函数执行完成,swapColors 函数的执行上下文出栈,并且被销毁。
- changeColor 函数执行完成,changeColor 函数的执行上下文出栈,并且被销毁。
js运行的生命周期,参照下图:
js的运行生命周期包括以下几个阶段:
- 解析阶段:js代码在执行之前需要被解析,解析器会对代码进行词法分析和语法分析,生成抽象语法树(AST)。
- 编译阶段:在编译阶段,js引擎会对AST进行优化和编译,生成可执行代码。
- 执行阶段:在执行阶段,js引擎会按照编译阶段生成的可执行代码,逐行执行js代码,执行过程中会涉及到变量的声明、赋值、函数调用等操作。在执行过程中,js引擎还会进行垃圾回收等操作,确保内存的有效使用。
js编译原理是将js代码转换为可执行的机器代码的过程,它包括三个主要阶段:解析、转换和代码生成。
- 在解析阶段,编译器将js代码转换为抽象语法树(AST)。
- 在转换阶段,编译器将AST转换为中间表示(IR),并对其进行优化。
- 在代码生成阶段,编译器将IR转换为机器代码,并生成可执行文件。
js编译器还包括一些其他的步骤,如词法分析、语法分析、类型检查和错误处理。这些步骤都是为了确保js代码能够正确地编译和执行。