JavaScript 基础
JS概念
JS基础概念
-
JS是一种运行在客户端(浏览器)的编程语言, 实现人机交换结果
-
作用:
- 网页特效
- 表单验证
- 数据交互
- 服务端编程(node.js)
-
JS的组成
- ECMAScript—javaScript语言基础
- Web APIs—(DOM: 页面文档对象模型)(BOM: 浏览器对象模型)
JS书写
-
位置
-
内部: 写到< /body >上方
<script>alert('hello js'); </script> </body>
-
外部: 以.js结尾的文件, 然后引入至html中, 引入位置与内部一致
<script src="./index.js"></script> </body>
-
内联: 类似于引入CSS样式
<button onclick="alert('hello world')">f**k me</button>
-
-
注释写法: 与C语言一致, 即 // 和 /* */
-
结束符: 以 ; 为结束符, 在实际开发中可写可不写, 但要统一
字面量
在计算机科学中, 字面量是在计算机中描述 事和物
JS语法
输入和输出
-
输出语法
document.write("<h1> 输出至文档 </h1>");alert("警示框");console.log("控制台打印");
-
输入语法
prompt('在警示框内输入');
变量基础
-
定义
- 用来存储数据的"盒子"
- 变量是容器, 而非数据
-
使用(与C语言差不多)
1. 声明变量:
let age;2. 赋值变量:
age = 18;
-
命名规则与规范
-
规则:
- 不能用关键字
- 只能由下划线、字母、数字、$组成, 不能数字开头
- 字母严格区分大小写
-
规范:
- 起名要有意义, 让人能看的懂
- 起名遵守小驼峰命名法
-
-
var的缺点
- 可以先使用, 再声明(不合理)
- var可以重复声明
- 比如变量提升、全局变量、没有块级作用域等
数组
-
数组是一种将一组数据存储在单个变量名下的优雅方式
let numArr = [1, 2, 3, 4, 5];
-
数组是有序的, 编号从0开始
console.log(numArr[0]); //打印1
-
数组内的数据类型是任意的, 不必一致
-
用.length属性获得数组的长度
console.log(numArr.length);
常量基础
-
定义: 使用const声明的变量称为常量, 声明时必须赋值, 不允许再次赋值
const PI = 3.14;
数据类型
-
意义:
- 更加充分利用高效的利用内存
- 更加方便程序员使用数据
基本数据类型
-
JS 是一门弱数据类型的语言, 不同于 java
-
有以下几种类型(基本数据类型)
- number
- string
- boolean
- undefined
- null
-
如何检测数据类型
typeof(X);
或
typeof X;
-
如何转换数据类型
-
隐式转换
-
‘+’ 两边只要有一个是字符串, 就会把另外一个转为字符串, 但+"123"的操作会把字符型转换为数字型
-
‘-’, ‘*’, ‘/’, '%'等运算符, 会把字符串转换为数字类型
-
-
let numSt = "123";
let numSt1 = numSt + 456; // num = "123456"let num = +numSt; // num = 123
-
显式转换
- Number(数据) — 转化为数字型
- parseInt(数据) — 只保留整数()
- parseFloat(数据) — 保留小数
数字类型(number)
-
算术运算符: + 、- 、* 、/ 、% (优先级为日常运算)
-
当运算时有错误的数据类型会输出 NaN, 任何对 NaN 的操作都会返回 NaN
字符串类型(string)
-
通过单引号, 双引号, 反引号包裹的数据为字符串类型
-
引号之间可以相互嵌套, 但不能相同嵌套
-
可以使用 + 来拼接字符串(数字相加, 字符相连, 字符串 + 数字 = 字符串)
-
当然, JS 和 C 语言一样, 可以格式化输出
let str = `javaScript`; console.log("%s", str);
-
模版字符串, 相较于格式化输出更方便, 字符串必须用反引号, 变量放入${}内
console.log(`这是${str}`);
布尔类型(bool)
-
只有两个值, true 和 false, 表示判断真假
-
“”、0、NaN、null、undefined 都为 false, 其他都为 true
未定义类型
- 只有一个值—undefined, 当声明变量时却没赋值, 则这个变量为未定义类型
null(空类型)
- 只有一个值—null, 把 null 作为尚未创建的对象
运算符
-
类型:
- 赋值运算符
- 自增自减运算符
- 比较运算符
- 逻辑运算符
-
运算符优先级: 与C语言等其他语言相同
赋值运算符
- 对变量进行赋值的运算符, 如 " = ", 其他赋值运算(+=)和 C 语言大差不差
自增自减运算符
- 自增/自减运算符" ++ ", " – ". 用法和 C 语言相同
比较运算符
-
" === " 表示左右值和类型是否全等, " !== " 表示左右两边是否不全等
-
" == "运算符也会进行隐式转换, 转换为数字型
-
NaN 不等于任何类型和值, 包括它自己, 参与它的运算返回值均为 false
-
比较结果为 bool 类型
-
字符串比较, 是比较的字符对应的 ascll 码
逻辑运算符
- 包括" && ", " || ", " ! ", 用法和 C 语言相同
隐式类型转换
-
运算符的左右两边的数据类型不同时, 会进行隐式类型转换, 转换规则如下:
- 布尔值和数字值: 布尔值转换为数字值 1/0, 数字值转换为布尔值 true/false
- 字符串和数字值: 字符串转换为数字值, 数字值转换为字符串
- 字符串和布尔值: 布尔值转换为字符串"true"/“false”
- 其他类型转换为字符串
- 隐式类型转换的优先级低于其他运算符, 如" - "运算符, 它会先将字符串转换为数字值再进行运算
- 只有" + "可以将数字型转换为字符串型, 在字符串与数字的运算中
- 隐式类型转换的常见场景:
- 条件判断语句中的条件表达式
- 算术运算符的操作数
- 赋值运算符的右侧表达式
- 函数调用的参数
- 变量初始化表达式
- 数组元素赋值
- 对象属性赋值
- 等等
运算符的特殊行为(类型转换总结)
- + 运算符:当任一操作数为字符串时,执行字符串拼接
1 + "2" // "12"
true + "false" // "truefalse"
- 其他算术运算符(-, *, /, %):将操作数转换为数字
"5" - 3 // 2
"10" / "2" // 5
- 常见隐式转换场景
- 条件判断
if (1) { /* 会执行,因为1被转换为true */ }
if ("") { /* 不会执行,空字符串被转换为false */ }
- 算术运算
let result = "10" * 2; // 20
- 比较运算
"10" == 10 // true (类型转换后比较)
"10" === 10 // false (严格相等,不转换类型)
- 其他场景
// 函数参数
function log(x) { console.log(x) }
log(123); // 数字
log("123"); // 字符串// 数组元素
let arr = [1, "2", true];// 对象属性
let obj = {num: "123",bool: 1
};注意事项:
== 会进行隐式类型转换,而 === 不会+ 是唯一会优先进行字符串拼接的算术运算符某些转换结果可能出乎意料:[] + {} // "[object Object]"# 语句和结构## 选择(分支)结构### if 语句```javascript
let num = +prompt("请输入一个数字");
if (num % 4 === 0 && num % 100 !== 0) {alert("true");
} else {alert("false");
}
switch 语句
注: switch 匹配时是全等(类型和值), 不只是数值相等
let num1 = +prompt("输入第一个数字");
let num2 = +prompt("输入第二个数字");let sp = prompt("输入运算符");switch (sp) {case "+":alert(num1 + num2);break;case "-":alert(num1 - num2);break;case "*":alert(num1 * num2);break;case "/":alert(num1 / num2);break;default:console.log("运算符错误");
}
基本循环语句
while 语句
let num = 0;
let cut = 0;
while (cut < 10) {num += 2;cut++;
}
alert(num);
-
循环三要素
- 变量起始值
- 终止条件
- 变量变化量
-
break 语句: 跳出循环
-
continue 语句: 跳过本次循环, 继续下一次循环
for 语句
注: 在遍历数组时, 数组越界时会打印 undefined
for (let i = 0; i < 10; i++) {console.log(i);
}
-
for 语句三要素
- 初始化
- 循环条件
- 变化量
-
循环嵌套
for (let i = 0; i < 10; i++) {for (let j = 0; j < 10; j++) {console.log(i + " " + j);}
}
数组进阶
声明数组
- 字面量声明(推荐使用)
let arr = [1, 2, 3, "四", 5, true];
let arr = []; // 声明一个空数组
- 构造函数声明
let arr = new Array(1, 2, 3, "四", 5, true);
let arr = new Array(); // 声明一个空数组
- 构造二维数组(使用字面量构造, 推荐使用)
let numArr = [];
for (let i = 0; i < 10; i++) {numArr[i] = [];for (let j = 0; j < 10; j++) {numArr[i][j] = 0;}
}
- 使用 fill 和 map 方法声明二维数组
const rows = 3;
const cols = 4;
const matrix = new Array(rows).fill().map(() => new Array(cols).fill(0));console.log(matrix);
遍历数组
- for 循环
for (let i = 0; i < arr.length; i++) {console.log(arr[i]);
}
- forEach 方法(数组方法)
arr.forEach(function (item, index, arr) {// item: 数组元素// index: 数组索引// arr: 数组本身console.log(item);
});
- for…of 循环
for (let item of arr) {console.log(item);
}
数组方法
- push 方法
arr.push(6);
// 向数组 arr(末尾) 中添加元素 6
// 返回数组的新长度
- pop 方法
arr.pop();
// 移除数组的最后一个元素
// 返回移除的元素
- shift 方法
arr.shift();
// 移除数组的第一个元素,并返回该元素
- unshift 方法
arr.unshift(0);
// 在数组的开头添加元素 0
- splice 方法
arr.splice(2, 1, 4, 5);
// 从索引 2 开始(包括索引2),删除 1 个元素,并在该位置插入 4, 5
// 若删除0个元素, 则在索引2后面插入元素
// 返回被删除的元素组成的数组
- concat 方法
let newArr = arr.concat([7, 8, 9]);
// 使用 concat 方法将数组 arr 与包含元素 7, 8, 9 的新数组合并,结果存储在 newArr 中
- join 方法
let str = arr.join("-");
// 将数组 arr 中的元素使用 "-" 连接成一个字符串,并赋值给变量 str, 默认使用逗号分隔
- map 方法
// 可以遍历数组处理数据, 并返回一个新的数组
let newArr = arr.map(function (item, index) {return item * 2;
});
- fill 方法
arr.fill(0, 2, 4);
// 用 0 填充数组 arr 中索引 2 到 4 之间的元素(包括第一个索引但不包括最后一个索引)
排序(三大基础排序, 了解即可)
冒泡排序
// 冒泡排序
function bubbleSort(arr) {let len = arr.length;for (let i = 0; i < len - 1; i++) {for (let j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {let temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}
选择排序
// 选择排序
function selectionSort(arr) {let len = arr.length;for (let i = 0; i < len - 1; i++) {let minIndex = i;for (let j = i + 1; j < len; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}if (minIndex !== i) {let temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}
插入排序
// 插入排序
function insertionSort(arr) {let len = arr.length;for (let i = 1; i < len; i++) {let current = arr[i];let j = i - 1;while (j >= 0 && arr[j] > current) {arr[j + 1] = arr[j];j--;}arr[j + 1] = current;}
}
函数
函数的定义
function myFunction(arg1, arg2) {// 函数体return arg1 + arg2;// 返回值
}
函数的调用
myFunction(1, 2); // 3
函数的参数
- 函数可以有0个或多个参数。参数可以是任意类型,包括数字、字符串、对象、数组等。
function myFunction(arg1 = 0, arg2 = 0) { // 默认参数// 函数体return arg1 + arg2;
}let result = myFunction(1, 2); // 3
let result2 = myFunction("hello", "world"); // "helloworld"
函数的返回值
- 函数可以返回任意类型的值,包括数字、字符串、对象、数组等。
function myFunction(arg1, arg2) {// 函数体return arg1 + arg2;// 若要返回多个值,可以返回一个数组// return [arg1, arg2];// 也可以返回对象// return {sum: arg1 + arg2};
}let result = myFunction(1, 2); // 3
console.log(result); // 3
函数的作用域
-
函数的作用域决定了函数内的变量能访问哪些变量,以及它们的值是什么。
-
使用
let
和const
声明的变量,其作用域为函数内部的块级作用域。 -
如果函数内部, 变量没有使用
let
和const
声明, 则该变量为全局变量。 -
函数的形参可以看做局部变量。
-
访问原则: 局部变量 > 全局变量 > 函数参数。
// 使用var声明的变量, 其作用域为函数内部的块级作用域顶部, 但值不会提升到顶部
function myFunction() {console.log(x); // undefined, 因为变量提升, 若用let或const声明, 为ReferenceErrorvar x = 1;console.log(x); // 1
}
函数的作用域链(学习对象之后了解)
-
函数的作用域链是一个对象,它包含了函数执行时的作用域链。
-
当函数执行时,会创建一个作用域链,包含了函数的局部作用域、其上层函数的作用域、全局作用域。
function myFunction() {var x = 1;console.log(x); // 1
}myFunction();console.log(x); // ReferenceError: x is not defined
函数的闭包
- 函数可以访问其外部作用域的变量(全局变量),这种函数称为闭包。
function myFunction() {var x = 1;function innerFunction() {console.log(x); // 1}return innerFunction;
}var myClosure = myFunction();
myClosure();
函数的递归
- 函数可以调用自身,这种函数称为递归函数。
// 阶乘函数
function factorial(n) {if (n === 1) {return 1;} else {return n * factorial(n - 1);}
}console.log(factorial(5)); // 120
匿名函数
var myFunc = function() {console.log("Hello, world!");
};myFunc(); // "Hello, world!"
-
匿名函数与具名函数的区别:
- 具名函数的调用可以写到任何位置
- 匿名函数必须在定义后调用
立即执行函数表达式(IIFE)
- 避免全局变量污染,提高代码的可读性。
(function() {console.log("Hello, world!");
})(); // "Hello, world!"
逻辑中断
- 如果左边能够判断真假, 则不必判断右边。(不推荐使用)
function myFunction(x, y) {x = x || 0;y = y || 0;// 类似于形参的默认值, 若x或y为false, 则返回0return x + y;
}
- 在新语法中, 用空值运算符
const value = someValue ?? "default";
// 只在someValue为null或undefined时使用默认值, default.
对象(object)
什么是对象?
-
在计算机编程中,对象是一个抽象概念,它是由数据和操作数据的行为组成的整体。对象是对现实世界中事物的一种抽象,它可以包含数据和操作数据的行为。对象是由属性和方法组成的,属性是对象的状态,方法是对象可以执行的操作。对象可以被创建、使用、修改和销毁。对象是软件系统的基本构造块,是构成系统的基本单元。
-
在JavaScript中,对象是一个无序的集合,它由属性和方法组成。属性是对象的状态,方法是对象可以执行的操作。对象可以被创建、使用、修改和销毁。对象是JavaScript的核心概念之一。
-
在JS中, 一切皆对象, 包括数字, 字符串, 数组, 函数, 正则表达式, 日期, 等等。
对象创建
- 对象可以被创建使用两种方式:字面量和构造函数。
字面量创建对象(推荐使用)
- 字面量创建对象是指通过直接在代码中定义一个对象,并将属性和方法(函数)赋值给它。
// 创建一个对象
let person = {name: 'John', // 注意标点符号age: 30,'now-time': '2025-03-20', // 属性名中包含特殊字符时,需要用单引号括起来greet: function() {console.log(`Hello, my name is ${this.name}`);}
};console.log(person); // {name: "John", age: 30, greet: ƒ}// 访问对象的属性
console.log(person.name); // John
console.log(person['now-time']); // 2025-03-20, 注意属性名需要用单引号括起来// 调用对象的方法
person.greet(); // Hello, my name is Johnperson.age = 35; // 修改对象的属性
console.log(person.age); // 35person.city = 'New York'; // 添加新的属性
console.log(person.city); // New Yorkdelete person.age; // 删除对象的属性
console.log(person); // {name: "John", greet: ƒ, city: "New York"}
构造函数创建对象
- 构造函数创建对象是指通过定义一个函数,并将属性和方法赋值给它,然后通过new关键字来调用该函数,创建出一个对象。
// 创建一个构造函数
function Person(name, age) {this.name = name;this.age = age;this.greet = function() {console.log(`Hello, my name is ${this.name}`);};}// 创建一个对象const person1 = new Person('John', 30); // 使用 new 来实例化const person2 = new Person('Mary', 25);// 访问对象的属性console.log(person1.name); // Johnconsole.log(person2.age); // 25// 调用对象的方法person1.greet(); // Hello, my name is Johnperson2.greet(); // Hello, my name is Mary// 验证person1和person2是否是同一个对象console.log(person1 === person2); // false
- 构造函数创建对象时,每次调用构造函数都会创建一个新的对象。因此,person1和 person2是两个不同的对象。
对象遍历
- 对象可以被遍历,可以遍历对象的属性和方法。
// 遍历对象属性
for (let key in person) {console.log(key); // name, age, greet key是属性名, 字符串类型console.log(person[key]); // John, 30, ƒ(){} person[key]是属性值
}// 遍历对象方法
for (let key in person) {if (typeof person[key] === 'function') {console.log(key); // greet}
}
对象数组
- 对象数组是指一个数组中包含多个对象。
// 创建一个对象数组
let people = [{name: 'John', age: 30},{name: 'Mary', age: 25},{name: 'Tom', age: 20}
];// 遍历对象数组
for (let i = 0; i < people.length; i++) {console.log(people[i].name); // John, Mary, Tom
}// 遍历对象数组的属性
for (let i = 0; i < people.length; i++) {for (let key in people[i]) {console.log(key); // name, age}
}// 遍历对象数组的属性和方法
for (let i = 0; i < people.length; i++) {for (let key in people[i]) {if (typeof people[i][key] === 'function') {console.log(key); // greet} else {console.log(key); // name, age}}
}
内置对象
Math对象
- Math对象是JavaScript的内置对象,它提供了一些常用的数学函数。
// 计算平方根
console.log(Math.sqrt(9)); // 3// 计算绝对值
console.log(Math.abs(-3)); // 3// 计算最大值
console.log(Math.max(3, 5, 1)); // 5// 计算最小值
console.log(Math.min(3, 5, 1)); // 1// 计算随机数 左闭右开 [0, 1)
console.log(Math.random()); // 0.123456789console.log(Math.floor(Math.random() * (10 + 1))); // 随机生成10(包括10)以内的整数// 在数组中随机抽取元素
let arr = [1, 2, 3, 4, 5];
console.log(arr[Math.floor(Math.random() * arr.length)]); // 随机抽取数组中的一个元素// 生成n到m的随机整数
console.log(Math.floor(Math.random() * (m - n + 1)) + n); // 随机生成n到m的整数// 计算圆周率
console.log(Math.PI); // 3.141592653589793// 向上取整
console.log(Math.ceil(3.2)); // 4// 向下取整
console.log(Math.floor(3.8)); // 3// 四舍五入 在计算负数时, .5取大的, .5以上取小的
console.log(Math.round(3.5)); // 4
Date对象
- Date对象是JavaScript的内置对象,它提供了日期和时间处理函数。
// 创建一个日期对象
let date = new Date();// 格式化日期
console.log(date.toLocaleString()); // 2021/10/12 下午10:15:30// 获取日期
console.log(date.getDate()); // 12// 获取月份
console.log(date.getMonth()); // 9// 获取年份
console.log(date.getFullYear()); // 2021// 日期加减
let newDate = new Date(date.getTime() + 1000 * 60 * 60 * 24); // 加一天
console.log(newDate.toLocaleString()); // 2021/10/13 下午10:15:30let newDate = new Date(date.getTime() - 1000 * 60 * 60 * 24); // 减一天
console.log(newDate.toLocaleString()); // 2021/10/11 下午10:15:30