Javascript基础
快速开始
新建文件夹js_demo
在js_demo文件夹下新建文件test.html、test.js
向test.html中添加代码:
html<head> <script type="text/javascript" src="test.js"></script> </head>向test.js中添加代码:
javascriptalert("Hi, JavaScript!");双击运行test.html, 显示效果:

JavaScript 程序不能独立运行,只能在宿主环境中执行。一般情况下可以把JavaScript代码放在网页中,借助浏览器环境来运行。
语法和数据类型
语法基础
- JavaScript 是区分大小写的
- 在Javascript中,指令被称为语句,并使用分号
;分隔。 - Javascript是按块执行的,但是不同块都属于同一个作用域(全局作用域),后面块中的代码可以访问前面块中的变量。
注释
// 单行注释
/* 这是一个更长的,
* 多行注释
*/
/* 你可以通过转义正斜杠 \/ */变量
JavaScript 有三种变量声明方式。
var:声明一个变量,可选择将其初始化为一个值。let:声明一个块级作用域的局部变量,可选择将其初始化为一个值。const:声明一个块级作用域的只读命名常量。变量
JavaScript 变量的名字又叫做标识符,标识符通常以字母、下划线(_)或者美元符号($)开头;后续的字符也可以是数字(0-9)。因为 JavaScript 是区分大小写的,所以字母包含从 A 到 Z 的大写字母和从 a 到 z 的小写字母。
合法的标识符示例:
Number_hits、temp99、$credit和_name。声明变量
你可以用以下两种方式声明变量:
- 使用关键字
var。例如var x = 42。这个语法可以用来声明局部变量和全局变量,具体取决于执行上下文。 - 使用关键字
const或let。例如let y = 13。这个语法可以用来声明块级作用域的局部变量。
jsvar a; var a, b, c; var b = 1;JavaScript引擎的解析方式:先解析代码,获取所有被声明的变量,提升到代码的头部,然后再一行一行地运行,这成为变量提升。
- 使用关键字
变量作用域
一个变量可能属于下列作用域之一:
全局作用域:在脚本模式中运行的所有代码的默认作用域。
模块作用域:在模块模式中运行的代码的作用域。
函数作用域:由函数创建的作用域。
块级作用域:用一对花括号创建的作用域(块)。
当你在函数的外部声明变量时,该变量被称作全局变量,因为当前文档中任何其他代码都能使用它。当你在函数内声明变量时,该变量被称作局部变量,因为它仅在那个函数内可用。
变量提升
用
var声明的变量会被提升,意味着你可以在该变量所在的作用域的任意地方引用该变量,即使还没有到达变量声明的地方。你可以看见var声明好像被提升到该变量的函数或全局作用域的顶部。然而,如果你在声明变量之前访问该变量,其值总是undefined,因为只有该变量的声明和默认初始化(为undefined)被提升,而不是它的赋值。全局变量
使用
var在任何函数、模块或代码块({})之外声明的变量会成为全局变量。使用
var声明的全局变量会成为全局对象(如window)的不可配置属性。
js// 在脚本的最顶层声明 var globalVar = "我是一个全局变量 (var)"; function myFunction() { console.log(globalVar); // 可以访问 } console.log(window.globalVar); // "我是一个全局变量 (var)"常量
可以用
const关键字创建一个只读命名常量。常量标识符的语法和任何变量标识符的语法相同常量必须为其初始化一个值,并且不能后续修改值。
常量的作用域规则和
let块级作用域变量的一致。
数据结构与类型
Javascript定义了6种基本的数据类型:
| 数据类型 | 含义 | 说明 |
|---|---|---|
| null | 空值 | 表示非对象 |
| undefined | 未定义的值 | 已声明,未赋值的变量的默认值 |
| Number | 数字 | 数学运算的值 |
| String | 字符串 | 表示字符串信息 |
| Boolean | 布尔值 | true 、false |
| BigInt | 整数 | 任意精度的整数 |
| object | 对象 | 包括狭义的对象、数组、函数 |
使用typeof运算符可以检测变量的类型:
console.log(typeof 1); // number
console.log(typeof "abc"); // string
console.log(typeof true); // boolean
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof function() {}); // function
console.log(typeof undefined); // undefined比较运算符
当我们对Number做比较时,可以通过比较运算符得到一个布尔值:
2 > 5; // false
5 >= 2; // true
7 == 7; // true实际上,JavaScript允许对任意数据类型做比较:
false == 0; // true
false === 0; // false要特别注意相等运算符==。JavaScript在设计时,有两种比较运算符:
第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。
由于JavaScript这个设计缺陷,不要使用==比较,始终坚持使用===比较。
另一个例外是NaN这个特殊的Number与所有其他值都不相等,包括它自己:
NaN === NaN; // false唯一能判断NaN的方法是通过isNaN()函数:
isNaN(NaN); // true数据类型转换
JavaScript是一门动态类型语言,能够根据运算环境自动转换值的类型:
| 值(value) | 字符串操作环境 | 数字运算环境 | 逻辑运算环境 | 对象操作环境 |
|---|---|---|---|---|
| undefined | "undefined" | NaN | false | Error |
| null | "null" | 0 | false | Error |
| 非空字符串 | - | 字符串对应的数字值; NaN | true | String |
| 空字符串 | - | 0 | false | String |
| 0 | "0" | 不转换 | false | Number |
| NaN | "NaN" | 不转换 | false | Number |
| Infinity | "Infinity" | 不转换 | true | Number |
| -Infinity | "-Infinity" | 不转换 | true | Number |
| Number.MAX_VALUE | "1.7976931348 623157e+308" | 不转换 | true | Number |
| NUMBER.MIN_VALUE | "5e-324" | 不转换 | true | Number |
| 其他所有数字 | "数字的字符串值" | 不转换 | true | Number |
| true | "true" | 1 | 不转换 | Boolean |
| false | "false" | 0 | 不转换 | Boolean |
| 对象 | toString() | valueOf()或toString或NaN | true | 不转换 |
在某些情况下,需要我们手动转换类型:
转换为字符串
使用 + 运算符,当值与空字符串相加时,会自动转为字符串
jsvar n = 123; n = n + ""; console.log(typeof n); // string使用
toString()jsvar a = 1e-4; // 1*10^-4 console.log(a.toString()); // "0.0001"
转换为小数格式字符串
num.toFixed(num):指定小数点后num位,输出字符串jsvar a = 10; console.log(a.toFixed(2)) // "10.00"num.toExponential(num):把数字转换为科学计数法,并指定小数点后保留num位(四舍五入),输出字符串jsvar a = 123456789; console.log(a.toExponential(2)) // "1.23e+8" console.log(a.toExponential(4)) // "1.2346e+8"num.toPrecision(num): 把数字转换为科学计数法,并指定有效数字为num位(四舍五入),输出字符串jsvar a = 123456789; console.log(a.toPrecision(2)) // "1.2e+8" console.log(a.toPrecision(4)) // "1.235e+8"
转换为数字
常用值转换为数字说明如下:
true->1false->0""->0Undefined->NaNnull->0NaN->NaNInfinity->Infinity
常用方法如下:
parseInt():转换为整数parseFloat():转换为浮点数
console.log(parseInt("123abc")); // 123
console.log(parseInt("1.73")); // 1
console.log(parseInt(".123")); // NaN
// 如果是以0开头的字符串,则parseInt()把它视为八进制数字,转换为十进制返回
var d = "010"
console.log(parseInt(d)) // 返回十进制 8
// 如果是以0x开头的字符串,则parseInt()把它视为十六进制数字,转换为十进制返回
var e = "0x10"
console.log(parseInt(e)) // 返回十进制 16转换为布尔值
使用两个感叹号!!可以将值转换为布尔类型
jsvar a = 1; console.log(!!a); //true使用一个感叹号可以将值转换为布尔类型并取反
jsvar a = 1; console.log(!a); //false使用
Boolean()函数可以转换为布尔类型jsvar a = 1; console.log(Boolean(a)) //true
转换为对象
使用 new 命令调用String、Number、Boolean类型函数,可以把字符串、数字和布尔类型包装为对应类型的对象
var n = "123"
console.log(typeof new String(n)) // object
console.log(typeof new Number(n)) // object
console.log(typeof new Boolean(n)) // object强制类型转换
Boolean(value):把参数转换为布尔类型Number(value):把参数转换为数字String(value):把参数值转换为字符串
流程控制与错误处理
块语句
块语句是Javascript最基本的语句。块由一对花括号界定:
{
statement1;
statement2;
// …
statementN;
}备注: 在块中用
var声明的变量不是块级作用域的,而是函数作用域或全局作用域的。
条件语句
if语句
if...else
jsif (condition) { statement1; } else { statement2; }if...else if...else
jsif (condition1) { statement1; } else if (condition2) { statement2; } else if (conditionN) { statementN; } else { statementLast; }if判断中的真值与假值
下面这些值求值为
false(也叫做假值):falseundefinednull0NaN空字符串("")
除此之外所有其他的值(包括所有的对象)在被传递给条件语句时会求值为
true。注意:空数组
[]、字符串"false"在if判断中为true
switch
switch (expression) {
case label1:
statements1;
break;
case label2:
statements2;
break;
// …
default:
statementsDefault;
}异常处理
JavaScript 异常类型ECMAScript 异常,DOMException
throw 语句
throw 语句的作用是主动抛出一个异常。当程序执行到 throw 时,当前函数的执行会立即停止,控制权将交给调用栈中最近的异常处理程序(catch 块)。
你可以抛出任何类型的值:字符串、数字、布尔值,但最佳实践是抛出一个 Error 对象或其子类的实例,因为它们自带堆栈跟踪等有用的调试信息。
// 1. 抛出 Error 对象(推荐)
throw new Error('发生了一个通用错误');
// 2. 抛出更具体的错误类型
throw new SyntaxError('语法错误');
throw new TypeError('类型错误');
throw new ReferenceError('引用错误');
// 3. 甚至可以抛出其他类型(不推荐)
throw '这是一个字符串错误'; // 不推荐
throw 404; // 不推荐
throw { message: '错误详情', code: 500 }; // 有时用于自定义错误对象你可以创建自己的错误类,继承自 Error,以包含更多上下文信息。
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field; // 自定义属性,记录是哪个字段出错
}
}
// 使用自定义错误
throw new ValidationError('邮箱格式不正确', 'email');try...catch...finally
try {
// 可能会出错的代码
riskyOperation();
console.log('这行在出错后不会执行');
} catch (error) {
// 如果 try 块中抛出异常,执行这里的代码
console.error('捕获到错误:', error.message);
// 可以在这里进行错误上报、给用户友好提示等
} finally {
// 无论是否出错,最终都会执行
console.log('清理工作完成');
}
// 错误被捕获后,程序会继续执行后面的代码,而不会崩溃
console.log('程序继续正常运行');循环与迭代
JavaScript 中提供了这些循环语句:
- for 语句
- while 语句
- do...while 语句
- for...in 语句
- for...of 语句
- label 语句
- break 语句
- continue 语句
for
for ([初始表达式]; [条件表达式]; [增量表达式]) {
// 要执行的代码块
}while
while (条件表达式) {
// 要执行的代码块
}do...while
与 while 类似,但保证代码块至少执行一次,因为条件判断在循环之后。
do {
// 要执行的代码块
} while (条件表达式);for...in
用于遍历对象的可枚举属性(包括原型链上的)。主要用于对象,不推荐用于数组。
for (变量 in 对象) {
// 使用变量的代码
}示例:
const person = {
name: 'Alice',
age: 30,
city: 'New York'
};
for (const key in person) {
console.log(`${key}: ${person[key]}`);
// 输出: name: Alice, age: 30, city: New York
}for...of
用于遍历可迭代对象(Array, String, Map, Set, arguments等)的值。
for (变量 of 可迭代对象) {
// 使用变量的代码
}示例:
const colors = ['red', 'green', 'blue'];
for (const color of colors) {
console.log(color); // 输出: 'red', 'green', 'blue'
}循环中断
break:
- 直接结束本次循环
- 在嵌套循环中, break 只在它所在的循环生效
continue:
- 中断本次循环, 进入下一次循环
- 在嵌套循环中, continue 也只在它所在的循环生效
函数
函数定义(函数声明)
传统方式
传统方式定义函数,具有函数提升特性,即可以在定义前调用
js// 函数声明 function greet(name) { return `Hello, ${name}!`; } console.log(greet('Alice')); // "Hello, Alice!" // 函数提升:可以在定义前调用 sayHello(); // "Hello!" (正常工作) function sayHello() { console.log("Hello!"); }函数表达式
将函数赋值给变量,此时没有函数提升特性
js// 函数表达式 let greet = function(name) { return `Hello, ${name}!`; }; console.log(greet('Bob')); // "Hello, Bob!" // 没有提升,会报错 tryHello(); // Error: tryHello is not a function let tryHello = function() { console.log("Trying hello..."); };箭头函数
更简洁的语法,没有自己的
this、arguments、super和new.targetjs// 基本语法 const add = (a, b) => { return a + b; }; // 单执行语句可以省略花括号 const multiply = (a, b) => a * b; // 单个参数可省略括号 const square = x => x * x; // 无参数需要空括号 const sayHi = () => console.log("Hi!"); console.log(add(2, 3)); // 5 console.log(multiply(2, 3)); // 6 console.log(square(4)); // 16立即调用表达式IIFE
定义后立即执行的函数,用于创建独立作用域。
现代模块化中较少使用,但在旧代码中很常见
js(function() { let privateVar = '我是私有的'; console.log('IIFE 立即执行'); })(); // 带参数的 IIFE (function(name) { console.log(`Hello, ${name}!`); })('World');回调函数
函数参数
默认参数
jsfunction multiply(a, b = 1) { return a * b; }剩余参数
将多个参数收集到一个数组中
jsfunction showTags(title, ...tags) { console.log(`标题: ${title}`); console.log(`标签: ${tags.join(', ')}`); } showTags('JS教程', '编程', '前端', 'JavaScript');
返回值
如果没有 return 或 return 后无值,函数返回 undefined。
作用域和闭包
作用域
在函数内定义的变量不能在函数之外的任何地方访问
定义在全局域中的函数可以访问所有全局变量
内层函数可以访问外层函数能访问的所有变量,外层函数无法访问内层函数变量
const globalVar = '全局变量';
function outer() {
const outerVar = '外部变量';
function inner() {
const innerVar = '内部变量';
console.log(innerVar); // 可以访问
console.log(outerVar); // 可以访问
console.log(globalVar); // 可以访问
}
inner();
// console.log(innerVar); // 错误:无法访问内部变量
}
outer();