JS入门
JS 是什么
- JS 是 JavaScript 的缩写,它是一种广泛使用的高级、解释型的编程语言。JavaScript 最初被创建来使网页更加动态和交互式。它是互联网上三大核心技术之一,与 HTML 和 CSS 并列。HTML负责网页的结构,CSS 负责样式,而 JavaScript 则负责网页的行为和交互性。
- JavaScript 可以在浏览器中运行,这意味着它可以在用户的设备上本地执行,而不需要服务器的直接参与。这使得网页能够响应用户的操作,如点击按钮、提交表单、动态加载内容等。
- 随着技术的发展,JavaScript 的用途已经从最初的客户端脚本语言扩展到服务器端编程(如Node.js),以及开发移动应用、桌面应用、游戏等。JavaScript 生态系统非常庞大,拥有大量的框架和库(如React, Angular, Vue等),使得开发复杂的应用变得更加容易和高效。
JS 引入方式
-
内联 JavaScript
在 HTML 文件中,可以直接在
<script>
标签内编写 JavaScript 代码。这种方式被称为内联 JavaScript。1
2
3
4<script>
// 这里是JavaScript代码
alert('Hello, World!');
</script> -
外部 JavaScript 文件
将 JavaScript 代码写在一个外部的
.js
文件中,然后通过在 HTML 文件的<script>
标签的src
属性中指定文件路径来引入。1
2<!-- 引入外部JavaScript文件 -->
<script src="path/to/your-script.js"></script> -
事件处理属性
在 HTML 标签的事件处理属性中直接写入 JavaScript 代码。例如,使用
onclick
属性处理点击事件。1
2<!-- 使用事件处理属性 -->
<button onclick="alert('你点击了按钮!')">点击我</button> -
JavaScript 模块
如果你使用的是现代 JavaScript,可以利用ES6模块的特性。你可以创建模块并导出函数、变量等,然后在其他文件中导入它们。
1
2
3
4// math.js
export function add(x, y) {
return x + y;
}1
2
3
4
5<!-- 在HTML文件中导入模块 -->
<script type="module">
import { add } from './math.js';
console.log(add(2, 3));
</script> -
异步加载
使用
async
或defer
属性加载外部 JavaScript 文件,可以控制文件加载的行为。async
属性会在文件下载完后立即执行,而defer
属性会在文档解析完成后、DOMContentLoaded 事件触发前执行。1
2
3
4
5<!-- 异步加载 -->
<script src="path/to/your-script.js" async></script>
<!-- 推迟执行直到文档解析完毕 -->
<script src="path/to/your-script.js" defer></script>
变量定义
-
简介
在JavaScript中,你可以使用
var
、let
或者const
来声明变量。 -
定义
-
var
这是在 ES6 之前最常用的声明变量的关键字,它声明的变量有一个函数作用域或者被提升至其当前作用域的顶部。
1
2var greeting = 'Hello, World!';
console.log(greeting); // 输出: Hello, World! -
let
引入于 ES6(ECMAScript 2015),
let
提供了块级作用域的变量声明。变量在声明它的块或子块之外不能被访问。1
2let name = 'Alice';
console.log(name); // 输出: Alice -
const
同样是 ES6 新增的关键字,用于声明一个只读的常量。一旦被赋值,其值就不能被改变。
1
2
3const pi = 3.14159;
console.log(pi); // 输出: 3.14159
// pi = 1; 尝试修改pi的值会导致错误
-
-
示例
以下是使用
let
和const
的一个示例,表明它们是如何工作在不同作用域的:1
2
3
4
5
6
7
8
9
10if (true) {
let letVariable = 'This can only be accessed within this block';
const constVariable = 'This is also block-scoped and cannot be reassigned';
console.log(letVariable); // 正常运行
console.log(constVariable); // 正常运行
}
// 以下将会抛出错误,因为letVariable和constVariable是在块内声明的
console.log(letVariable); // 引发错误
console.log(constVariable); // 引发错误请注意,虽然
var
仍然可以在现代 JavaScript 中使用,但是由于它可能导致潜在的作用域混淆,推荐在可能的情况下优先使用let
和const
。
数据类型
-
简介
JavaScript 是一种动态类型语言,这意味着你不需要在声明变量时指定数据类型,数据类型会在代码执行时根据需要自动确定。
-
基本类型(Primitive Types)
-
Number
用于任何类型的数字,包括整数和浮点数。
1
2let integer = 100; // 整数
let floatingPoint = 10.5; // 浮点数 -
String
用于字符的序列,可以是一个字符或者多个字符组成的文本。用单引号、双引号或模板字面量表示,
+
可以进行字符串的拼接。1
2
3let singleQuoteString = 'Hello!';
let doubleQuoteString = "Hello, World!";
let templateLiteral = `Hello, ${name}!`; // ES6模板字面量 -
Boolean
代表逻辑实体,可以有两个值:
true
或false
。1
2let isTrue = true;
let isFalse = false; -
Null
表示一个空值或不存在的对象,通常用来表示意料之外的“无值”情况。
1
2let emptyValue = null;
console.log(emptyValue); // 输出: null -
Undefined
当一个变量被声明了,但没有被赋值时,它的值就是
undefined
。1
2let notAssigned;
console.log(notAssigned); // 输出: undefined -
Symbol(新增于ES6)
表示一个独一无二的值,通过
Symbol()
函数创建。常用来作为对象的唯一属性。1
2
3let symbol1 = Symbol('symbol');
let symbol2 = Symbol('symbol');
console.log(symbol1 === symbol2); // 输出: false -
BigInt(新增于ES2020)
用于表示非常大的整数,远超过 Number 类型可以表示的范围。
1
2let bigNumber = BigInt(1234567890123456789012345678901234567890n);
console.log(bigNumber); // 输出: 1234567890123456789012345678901234567890n
-
-
引用类型(Reference Types)
-
Object
一种数据结构,用于存储键值对。
1
2
3
4let person = {
name: 'Alice',
age: 30
}; -
Array
用于存储有序集合的对象。
1
let colors = ['red', 'green', 'blue'];
-
Function
JavaScript 函数其实是一种对象。
1
2
3function greet() {
console.log('Hello, World!');
} -
Date
用于处理日期和时间的对象。
1
let today = new Date();
-
RegExp
表示正则表达式的对象。
1
let pattern = /ab+c/;
-
Map 和 Set(ES6)
Map
是键值对的集合,Set
是值的集合,两者都可以存储不重复的值。1
2let map = new Map();
let set = new Set();
-
基本运算
-
算术运算符
-
加法(
+
)1
let sum = 10 + 5; // 结果是 15
-
减法(
-
)1
let difference = 10 - 5; // 结果是 5
-
乘法(
*
)1
let product = 10 * 5; // 结果是 50
-
除法(
/
)1
let quotient = 10 / 5; // 结果是 2
-
取余(
%
)1
let remainder = 10 % 3; // 结果是 1
-
自增(
++
)1
2let count = 0;
count++; // count 现在是 1 -
自减(
--
)1
2let count = 0;
count--; // count 现在是 -1
-
-
赋值运算符
-
简单赋值(
=
)1
let a = 10; // 将 10 赋值给 a
-
加法赋值(
+=
)1
2let a = 10;
a += 5; // 等同于 a = a + 5,现在 a 是 15 -
减法赋值(
-=
)1
2let a = 10;
a -= 5; // 等同于 a = a - 5,现在 a 是 5 -
乘法赋值(
*=
)1
2let a = 10;
a *= 5; // 等同于 a = a * 5,现在 a 是 50 -
除法赋值(
/=
)1
2let a = 10;
a /= 5; // 等同于 a = a / 5,现在 a 是 2 -
按位与赋值(
&=
)1
2
3let a = 9; // 二进制表示: 1001
a &= 5; // 二进制表示: 0101
// 结果: a = 1,因为 1001 & 0101 = 0001
-
-
比较运算符
-
等于(
==
)1
2
3if (5 == '5') { // 返回 true,因为进行了类型转换
// 代码块
} -
全等于(
===
)1
2
3if (5 === '5') { // 返回 false,因为类型不同
// 代码块
} -
不等于(
!=
)1
2
3if (5 != '8') { // 返回 true,因为 5 不等于 '8'
// 代码块
} -
大于(
>
)1
2
3if (10 > 5) { // 返回 true
// 代码块会执行
} -
小于(
<
)1
2
3if (5 < 10) { // 返回 true
// 代码块会执行
} -
大于或等于(
>=
)1
2
3if (5 >= 5) { // 返回 true
// 代码块会执行
} -
小于或等于(
<=
)1
2
3if (5 <= 10) { // 返回 true
// 代码块会执行
}
-
-
逻辑运算符
-
逻辑与(
&&
)1
2
3if (true && false) { // 返回 false
// 代码块不会执行
} -
逻辑或(
||
)1
2
3if (true || false) { // 返回 true
// 代码块会执行
} -
逻辑非(
!
)1
2let truthy = true;
let falsy = !truthy; // falsy 是 false
-
-
按位运算符
-
按位与(
&
)1
let andResult = 5 & 1; // 结果是 1 (0101 & 0001)
-
按位或(
|
)1
let orResult = 5 | 2; // 结果是 7 (0101 | 0010)
-
按位异或(
^
)1
let xorResult = 5 ^ 1; // 结果是 4 (0101 ^ 0001)
-
按位非(
~
)1
let notResult = ~5; // 结果是 -6 (按位取反操作)
-
左移(
<<
)1
let leftShift = 5 << 1; // 结果是 10 (0101 << 1)
-
符号右移(
>>
)1
let signRightShift = -5 >> 1; // 结果是 -3 (按符号位填充右移)
-
无符号右移(
>>>
)1
let zeroFillRightShift = -5 >>> 1; // 结果是 2147483645 (无符号右移)
-
-
三目运算符
- 三目运算符也称为条件运算符,它是一种简洁的条件语句,用于根据条件来选择不同的值或执行不同的操作。
- 三目运算符的语法如下:
1
condition ? expression1 : expression2
- 如果条件为真(即
condition
为真),则返回expression1
的值;如果条件为假,则返回expression2
的值。 - 示例
1
let result = (10 > 5) ? '大于' : '小于或等于'; // result 是 '大于'
-
==
和===
有啥区别?-
双等号
==
(等于)- 它执行抽象相等性比较。
- 当使用
==
对两个值进行比较时,如果它们不是相同类型的,JavaScript会尝试将它们转换为一个共同类型然后进行比较。 - 这意味着在比较之前可能会发生类型转换,有时会产生非直觉的结果。
- 例如:
1
20 == '0' // true,因为字符串 '0' 被转换为数字 0
1 == true // true,因为布尔值 true 被转换为数字 1
-
三等号
===
(严格等于)- 它执行严格相等性比较。
- 使用
===
时,如果两个值的类型不同,那么它们就被认为是不等的,不会发生类型转换。 - 只有在两个值的类型相同并且它们的值也相等的情况下,
===
才返回true
。 - 例如:
1
20 === '0' // false,因为它们类型不同
1 === true // false,同样因为类型不同 - 因此,
===
被认为是更严格的相等性检查,它可以让你避免类型转换可能引入的错误,这也是为什么推荐在比较时使用===
的原因。
-
流程控制
-
条件语句
-
if
语句用于在满足条件时执行一段代码块。如果条件为真,则执行代码块;否则,跳过代码块。
1
2
3if (condition) {
// 当 condition 为 true 时执行的代码
}1
2
3
4let score = 90;
if (score > 70) {
console.log("优秀");
} -
if...else
语句在满足条件时执行一个代码块,否则执行另一个代码块。
1
2
3
4
5if (condition) {
// 当 condition 为 true 时执行的代码
} else {
// 当 condition 为 false 时执行的代码
}1
2
3
4
5
6let score = 60;
if (score >= 70) {
console.log("及格了");
} else {
console.log("未及格");
} -
if...else if...else
语句用于在多个条件之间进行选择。
1
2
3
4
5
6
7if (condition1) {
// 当 condition1 为 true 时执行的代码
} else if (condition2) {
// 当 condition1 为 false 且 condition2 为 true 时执行的代码
} else {
// 当 condition1 和 condition2 都为 false 时执行的代码
}1
2
3
4
5
6
7
8let score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 70) {
console.log("良好");
} else {
console.log("需要努力");
} -
switch
语句1
2
3
4
5
6
7
8
9
10
11switch (expression) {
case value1:
// 当 expression 等于 value1 时执行的代码
break;
case value2:
// 当 expression 等于 value2 时执行的代码
break;
// 更多的 case...
default:
// 当 expression 与所有 case 都不匹配时执行的代码
}1
2
3
4
5
6
7
8
9
10
11let fruit = "apple";
switch (fruit) {
case "banana":
console.log("香蕉");
break;
case "apple":
console.log("苹果");
break;
default:
console.log("未知水果");
}
-
-
循环语句
-
while
循环在满足条件时重复执行一个代码块,条件在循环开始前进行检查。
1
2
3while (condition) {
// 只要 condition 为 true 就不断执行的代码
}1
2
3
4
5let i = 0;
while (i < 5) {
console.log(i);
i++;
} -
do...while
循环在满足条件时重复执行一个代码块,条件在循环结束后进行检查。
1
2
3do {
// 循环体内的代码至少会执行一次,之后如果 condition 为 true 则继续执行
} while (condition);1
2
3
4
5let i = 0;
do {
console.log(i);
i++;
} while (i < 5); -
for
循环用于重复执行一个代码块,可以指定循环的初始条件、终止条件和每次迭代后的操作。
1
2
3for (initialization; condition; finalExpression) {
// 使用初始化表达式开始,条件为 true 持续执行的代码,每次迭代后执行最终表达式
}1
2
3for (let i = 0; i < 5; i++) {
console.log(i);
} -
for...in
循环(用于对象的属性)1
2
3for (let key in object) {
// 对于对象 object 中的每个属性执行的代码
}1
2
3
4let person = { firstName: "John", lastName: "Doe" };
for (let key in person) {
console.log(key + ": " + person[key]);
} -
for...of
循环(用于可迭代对象,比如数组、字符串等)1
2
3for (let value of iterable) {
// 对于可迭代对象 iterable 中的每个元素执行的代码
}1
2
3
4let colors = ["红", "绿", "蓝"];
for (let color of colors) {
console.log(color);
}
-
-
跳转语句
-
break
语句- 立即退出最近的循环或
switch
语句。 - 在
switch
语句中防止代码自动地从一个case
跌落到另一个case
。 - 示例
1
2
3
4
5
6for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // 当 i 等于 5 的时候退出循环
}
console.log(i);
}
- 立即退出最近的循环或
-
continue
语句- 跳过循环体内接下来的语句,立即进行下一次的迭代。
- 示例
1
2
3
4
5
6for (let i = 0; i < 10; i++) {
if (i % 2 === 0) {
continue; // 当 i 是偶数时,跳过当前循环的剩余部分
}
console.log(i); // 打印出奇数
}
-
return
语句- 退出函数,并返回一个值(如果有的话)。
- 示例
1
2
3
4function multiply(a, b) {
return a * b; // 返回两个数的乘积
}
console.log(multiply(5, 3));
-
throw
语句- 抛出一个用户自定义的异常。
- 示例
1
2
3
4
5
6
7
8
9
10
11function checkNumber(num) {
if (isNaN(num)) {
throw "不是一个数字"; // 抛出异常
}
return "是一个数字";
}
try {
checkNumber("A");
} catch (e) {
console.log(e); // 输出:"不是一个数字"
}
-
-
异常处理语句
try...catch
语句1
2
3
4
5
6
7try {
// 尝试执行的代码,可能会产生错误
} catch (error) {
// 当 try 块中的代码抛出错误时执行的代码
} finally {
// 无论是否有错误被捕获,finally 块中的代码都会执行
}1
2
3
4
5
6
7
8
9
10
11try {
// 尝试执行的代码
let x = 2;
let y = x + z; // 引用一个未定义的变量 z
} catch (error) {
// 捕获到错误时执行的代码
console.log(error.message); // 输出错误信息
} finally {
// 无论是否捕获到错误,都会执行的代码
console.log("无论如何我都会执行");
}
函数使用
-
函数声明(Function Declaration)
通过函数声明创建的函数是一种最基本的方式。这类函数的特点是函数提升(Hoisting),意味着你可以在声明之前调用它们,因为 JavaScript 引擎会将函数声明提升到作用域的顶部。
1
2
3
4
5
6
7// 定义函数
function greet(name) {
return `Hello, ${name}!`;
}
// 调用函数
console.log(greet('Alice')); // 输出:Hello, Alice! -
函数表达式(Function Expression)
函数表达式允许你将匿名函数赋值给一个变量。这些函数不会提升,也就是说你必须在定义之后才能调用它们。函数表达式可以是匿名的,也可以命名。
1
2
3
4
5
6
7// 函数表达式将一个匿名函数赋值给变量
const square = function (number) {
return number * number;
};
// 调用函数
console.log(square(4)); // 输出:16 -
箭头函数(Arrow Function)
ES6引入了箭头函数,它提供了一种更简洁的方式来写匿名函数表达式。箭头函数不仅语法简洁,还有其他特点,如不绑定自己的
this
值,通常用于回调和函数式编程。1
2
3
4
5// 简单的箭头函数
const add = (a, b) => a + b;
// 调用箭头函数
console.log(add(5, 3)); // 输出:8 -
立即调用的函数表达式(IIFE - Immediately Invoked Function Expression)
立即调用函数表达式是一种模式,其中定义的函数会立即执行。IIFE通常用来创建一个独立的作用域,这样函数内部的任何变量都不会污染全局作用域。
1
2
3(function () {
console.log('这段代码立即执行了!');
})(); -
构造函数(Constructor Function)
构造函数是用来创建具有特定类型的新对象的特殊函数。使用
new
关键字调用构造函数时,函数内的this
会指向新创建的对象。这是一种传统的 JavaScript 面向对象编程(OOP)方式。1
2
3
4
5
6
7
8
9
10
11
12
13
14// 构造函数通常首字母大写
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = function () {
return this.firstName + ' ' + this.lastName;
};
}
// 创建一个新对象
const johnDoe = new Person('John', 'Doe');
// 调用构造函数中的方法
console.log(johnDoe.fullName()); // 输出:John Doe -
回调函数(Callback Function)
回调函数是传递给另一个函数作为参数的函数,这个参数函数在后者内部的某个时点执行,通常是在异步操作完成后。回调函数允许代码在合适的时候运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 导入readline模块
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
// 定义 greet 函数
function greet(name) {
console.log(`Hello, ${name}!`);
readline.close();
}
// 定义 processUserInput 函数
function processUserInput(callback) {
readline.question('Please enter your name: ', (name) => {
callback(name);
});
}
// 调用函数并传入 greet 作为回调函数
processUserInput(greet); -
默认参数(Default Parameters)
默认参数是在不传递参数或者传递的参数是
undefined
时,为函数参数提供默认值的一种方式。它可以清楚地表达参数的意图并避免在函数体内部检查参数是否提供的逻辑。1
2
3
4
5
6
7
8
9function sayHello(name = 'World') {
console.log(`Hello, ${name}!`);
}
// 调用函数没有传入参数,将使用默认参数
sayHello(); // 输出:Hello, World!
// 调用函数并传入参数
sayHello('Dave'); // 输出:Hello, Dave! -
Rest 参数(Rest Parameters)
Rest 参数语法允许我们将不确定数量的参数表示为一个数组。这样可以更容易地处理函数接收多个参数的情形,而不用担心函数调用时参数的具体个数。
1
2
3
4
5
6
7// 使用...语法接受多个参数
function sumAll(...numbers) {
return numbers.reduce((acc, current) => acc + current, 0);
}
// 传入任意数量的参数
console.log(sumAll(1, 2, 3, 4)); // 输出:10 -
变量作用域
- 全局作用域:在代码中任何地方都能访问到的变量。如果一个变量在函数之外被声明,它就是全局变量,可以在代码的任何地方被访问。
1
2
3
4
5
6
7
8var a = "global";
function displayValue() {
console.log(a); // 可以访问全局变量a
}
displayValue(); // 输出 "global"
console.log(a); // 输出 "global" - 局部作用域:只在定义它的函数或代码块内部可访问的变量。局部作用域又可以进一步分为:
- 函数作用域:变量在整个函数中都是可访问的,包括函数内部的块。
1
2
3
4
5
6
7
8
9
10
11
12function someFunction() {
var b = "local";
function innerFunction() {
console.log(b); // 可以访问外部函数的变量b
}
innerFunction(); // 输出 "local"
}
someFunction();
console.log(b); // 错误:b is not defined - 块级作用域(ES6新增):通过
let
和const
声明的变量在代码块({}
)中是可访问的,但在代码块外是不可访问的。1
2
3
4
5
6
7
8
9
10function testBlockScope() {
if (true) {
let c = "block scoped";
console.log(c); // 可以访问c
}
console.log(c); // 错误:c is not defined
}
testBlockScope();
- 函数作用域:变量在整个函数中都是可访问的,包括函数内部的块。
- 作用域链
在 JavaScript 中,如果在当前作用域中找不到某个变量,解释器会向上查找这个变量,这个过程称为作用域链。如果在全局作用域中依旧找不到该变量,则会抛出一个错误。 - 提升(Hoisting)
在 JavaScript 中,变量和函数声明都会被提升到它们作用域的顶部。这意味着我们可以在变量声明之前引用它们。但是,var
声明的变量会被初始化为undefined
,而let
和const
声明的变量不会被初始化。
- 全局作用域:在代码中任何地方都能访问到的变量。如果一个变量在函数之外被声明,它就是全局变量,可以在代码的任何地方被访问。
常用函数
-
字符串函数和方法
charAt(index)
:返回指定位置的字符。concat()
:连接两个或多个字符串。includes(substring)
:检查字符串是否包含指定的子串。indexOf(substring)
:返回子串在字符串中的位置。slice(start, end)
:提取字符串的一部分并返回新字符串。split(separator)
:将字符串分割成数组。toLowerCase()
:将字符串转换成小写。toUpperCase()
:将字符串转换成大写。trim()
:去除字符串两端的空白字符。
-
数组函数和方法
push()
:向数组的末尾添加一个或多个元素,并返回新的长度。pop()
:移除数组最后一个元素,并返回该元素。shift()
:移除数组的第一个元素,并返回该元素。unshift()
:向数组的开头添加一个或多个元素,并返回新的长度。slice(start, end)
:提取数组的一部分,并返回一个新数组。splice(index, howMany, elements)
:添加或删除数组的元素。map()
:创建一个新数组,其结果是该数组中的每个元素调用一次提供的函数。filter()
:创建一个新数组,包含通过所提供函数实现的测试的所有元素。reduce()
:对数组中的每个元素执行一个由你提供的reducer函数(升序执行),将其结果汇总为单个返回值。
-
数字和数学函数
Math.random()
:生成一个介于0和1之间的随机数。Math.round(number)
:四舍五入到最接近的整数。Math.floor(number)
:向下取整。Math.ceil(number)
:向上取整。parseInt(string, radix)
:解析一个字符串并返回一个整数。parseFloat(string)
:解析一个字符串并返回一个浮点数。
-
日期函数
Date.now()
:返回自1970年1月1日以来的毫秒数。new Date()
:构造一个新的日期对象。
-
定时器函数
setTimeout(function, milliseconds)
:在指定的毫秒数后调用函数一次。setInterval(function, milliseconds)
:按照指定的周期(以毫秒计)来调用函数或计算表达式。clearTimeout(timeoutId)
:取消由 setTimeout() 方法设置的 timeout。clearInterval(intervalId)
:取消由 setInterval() 设置的定时器。
-
JSON函数
JSON.stringify(value)
:将JavaScript对象转换为JSON字符串。JSON.parse(text)
:将JSON字符串转换为JavaScript对象。
-
DOM操作方法
document.getElementById()
:获取对应ID的元素。document.getElementsByClassName()
:获取拥有指定类名的元素集合。document.getElementsByTagName()
:获取具有指定标签名的元素集合。document.querySelector()
:返回文档中匹配指定CSS选择器的第一个元素。document.querySelectorAll()
:返回文档中匹配指定CSS选择器的所有元素集合。