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声明, 为ReferenceError
var 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, 则返回0
return 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 John
person.age = 35; // 修改对象的属性
console.log(person.age); // 35
person.city = 'New York'; // 添加新的属性
console.log(person.city); // New York
delete 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); // John
console.log(person2.age); // 25
// 调用对象的方法
person1.greet(); // Hello, my name is John
person2.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.123456789
console.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:30
let newDate = new Date(date.getTime() - 1000 * 60 * 60 * 24); // 减一天
console.log(newDate.toLocaleString()); // 2021/10/11 下午10:15:30