JavaScript学习(三)

[TOC]

数组

什么是数组

数组(Array)也是一种复合数据类型,可以存储多种类型的数据。数组存储的数据称为元素,数组中存储的是有序元素,每一个元素都有对应的索引(index),索引是从0开始的正整数,0对应数组第一个元素,依次后推。数组中的元素是通过索引来操作的

创建数组的格式:

  • const 数组名 = new Array();
  • const 数组名 = [ ]; (这是通过数组字面量创建数组,推荐这种格式创建数组)

添加数组格式:

  • 数组名[索引] = 元素;

修改数组元素同添加数组格式,只是把需要修改的元素通过索引修改即可。

读取数组某元素格式:

  • 数组名[索引]
  • 读取到空元素不会报错,会返回undefined。

数组中的元素是可以非连续添加的,但是尽量不要添加非连续元素

length:

  • 获取数组的长度。
  • 数组的长度是数组中最大索引+1。
  • 可以通过 数组名[数组名.length] = xx ; 来向数组的最后添加元素。
  • 可以修改数组的 length ,如果长度变长会在数组后面增加空属性,如果变短会把数组后面的元素删除。
const arr = [1, 2, 3];
console.log(arr); //1,2,3
arr[0] = 3;
console.log(arr[0]); //3
arr[arr.length] = 4;
console.log(arr.length); //4
console.log(arr); //1,2,3,4
console.log(typeof arr); //object

可以通过 for 循环来遍历数组中的元素。

const arr = ["小明", "小方", "小兰"];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}; //正向遍历
for (let i = arr.length - 1; i >= 0; i--) {
    console.log(arr[i]);
}; //反向遍历
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    };
};

//打印18岁同学的姓名和年龄
const arr1 = [
    new Person("小明", 15),
    new Person("小方", 18),
    new Person("小兰", 16)
];
for (let i = 0; i < arr1.length; i++) {
    if (arr1[i].age === 18) {
        console.log(arr1[i].name + "," + arr1[i].age);
    };
};

除了 for 循环遍历数组,还有 for-of 方法也可以遍历数组(for-of不仅可以遍历数组,它可以遍历一切可迭代对象,但是只能满足从前往后方式遍历)。数组中有几个元素, for-of循环体就循环多少次,每次循环会把元素赋值给变量。

格式:

  • for(let 变量 of 可迭代对象){ 代码 };
const arr = ["小明", "小方", "小兰"];
for (let value of arr) {
    console.log(value);
};
for (let value of "hello") {
    console.log(value);
};

数组的方法

Array.isArray():

  • 检查一个对象是否是数组,是则返回true。

at():

  • 可以根据索引获取指定元素。
  • 可以获取负值索引的元素,负数是元素从后往前开始计算的,-1就是指倒数第一个,-2就是指倒数第二个。

concat():

  • 用来连接两个或多个数组。

indexOf():

  • 用来获取元素第一次出现的索引位置。
  • 参数:
    • 要查询的元素。
    • 元素的起始位置。

lastIndexOf():

  • 用来获取元素在数组中最后一次出现的位置。
  • 参数:
    • 要查询的元素。
    • 与 indexof() 相反,从后往前开始算的起始位置开始往前,也就是从该索引值之后的元素不包括在内。
  • 返回值:
    • 查询到便返回索引值。
    • 未查询到返回 -1。

join():

  • 将数组中元素连接为一个字符串。
  • 参数:
    • 设置元素之间用来连接的字符。

slice():

  • 用来截取数组(非破坏性方法)。
  • 参数:
    • 截取的起始位置。(包括该位置)
    • 截取的结束位置。(不包括该位置)
    • 如果不写结束位置参数,会一直截取到最后。
    • 索引参数可以为负值,从后往前计算。
    • 如果起始和结束位置的参数都不写,则可以对数组进行浅拷贝(浅复制)。
const arr = ["小白", "小绿", "小蓝", "小紫", "小绿", "小黑"];
const arr1 = ["小明", "小兰", "小方"];
console.log(Array.isArray(arr)); //true
console.log(arr.at(0)); //小白
console.log(arr.at(3)); //小紫
console.log(arr.concat(arr1));
console.log(arr.indexOf("小绿", 3)); //4
console.log(arr.lastIndexOf("小绿", 3)); //1
console.log(arr.indexOf("小兰")); //-1
console.log(arr.lastIndexOf("小兰")); //-1
console.log(arr.join("-"));
console.log(arr.slice(0, 2)); //小白,小绿
console.log(arr.slice(0, -2)); //小白,小绿,小蓝,小紫

对象的复制

对象的复制必须要创建一个新的对象。当调用数组的 slice() 方法时,会新建一个对象存储截取的元素,可以完成复制。

const arr = ["小明", "小兰", "小方"];
const arr1 = arr; //这不是复制,修改元素后对两个数组都有影响
console.log(arr === arr1); //true,指向相同的对象
const arr3 = arr.slice(); //调用slice方法时会新创建一个对象用来存储截取的元素
console.log(arr === arr3); //false,两个数组指向的不是同一个对象

浅拷贝和深拷贝

浅拷贝(shallow copy):

  • 一般对对象的拷贝都是浅拷贝,浅拷贝只复制一层。
  • 如果对象存储的属性是原始值,拷贝的深浅不重要。
  • 浅拷贝只会复制对象本身,不会复制对象的属性。

深拷贝(deep copy):

  • 深拷贝会进行深层的复制,除了复制对象本身还会复制对象的属性和元素。
  • 考虑到性能问题,一般不会使用深拷贝。
  • structuredClone() :专门用来深拷贝的方法。
const arr = [{ name: "小明" }, { name: "小兰" }, { name: "小方" }];
const arr1 = arr.slice(); //浅拷贝,只复制对象本身
console.log(arr === arr1); //false
console.log(arr[0] === arr1[0]); //true
const arr2 = structuredClone(arr); //专门用来深拷贝的方法
console.log(arr === arr2); //false
console.log(arr[0] === arr2[0]); //false
arr2[0].name = "小红";
console.log(arr[0].name); //小明
console.log(arr2[0].name); //小红

浅复制(浅拷贝)的其他方式:

  • ...(展开运算符):
    • 将数组中的元素展开到另一个数组中作为函数的参数传递。
    • 也可以对数组进行浅复制。
    • 也可在前后进行添加操作。

对对象的浅复制:

  • const 新对象名 = Object.assign({ },被复制对象);(将被复制对象中的属性复制到新对象里并将新对象返回
  • ...对象名;(可进行添加操作,如果有重名属性会被覆盖)
const arr = ["小明", "小兰", "小方"];
const arr1 = [...arr];
console.log(arr1);
const arr2 = ["小红", ...arr, "小绿"];
console.log(arr2);
const obj = {
    name: "小明",
    age: 18
};
const obj1 = Object.assign({}, obj);
console.log(obj1);
const obj2 = { ...obj };
console.log(obj2);
const obj3 = { name: "小兰", ...obj, address: "南京" }; //小兰会被小明覆盖
console.log(obj3);

数组的方法(对原数组有破坏性)

  1. push():

    • 向数组的最后添加一个或多个元素,并返回新的长度。
  2. pop():

    • 删除并返回数组最后一个元素。
  3. unshift():

    • 向数组的开始添加一个或多个元素,并返回新长度。
  4. shift():

    • 删除并返回最开始的元素。
  5. splice():

    • 可以删除,插入,替换数组的元素。
    • 参数:
      • 被删除元素的起始位置。
      • 被删除元素的个数。
      • 要插入的元素。
  6. reverse():

    • 对数组中的元素进行反转。
const arr = ["小明", "小兰", "小方"];
arr.push("小红", "小绿"); //小明,小兰,小方,小红,小绿
arr.pop(); //小明,小兰,小方,小红
arr.unshift("小白", "小黑"); //小白,小黑,小明,小兰,小方,小红
arr.shift(); //小黑,小明,小兰,小方,小红
console.log(arr);
const arr1 = ["北京", "上海", "广州", "深圳"];
arr1.splice(1, 2, "南京"); //北京,南京,深圳
arr1.splice(2, 0, "西安", "杭州"); //北京,南京,西安,杭州,深圳
arr1.splice(2, 2); //北京,南京,深圳
console.log(arr1);
const arr2 = [1, 2, 3, 4, 5];
let result = arr2.reverse();
console.log(result); //5,4,3,2,1

数组去重练习

//去除数组中重复元素
const arr = [1, 2, 1, 1, 3, 4, 5, 5, 6, 7, 4];
/*方法一
for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
        if (arr[i] === arr[j]) {
            arr.splice(j, 1);
            j -= 1;
        };
    };
};
console.log(arr);
*/

/*方法二 
for (let i = 0; i < arr.length; i++) {
    let index = arr.indexOf(arr[i], i + 1);
    if (index != -1) {
        arr.splice(index, 1);
        i--;
    };
};
console.log(arr); 
*/

//不破坏原数组
const newArray = [];
for (let ele of arr) {
    if (newArray.indexOf(ele) === -1) {
        newArray.push(ele);
    };
};
console.log(newArray);

选择排序和冒泡排序

逻辑简单,运行缓慢,适合数据量小的排序。

const arr = [9, 5, 2, 8, 4, 6, 3, 5, 7, 1];
//选择排序
for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
        if (arr[i] > arr[j]) {
            let temp = arr[j];
            arr[j] = arr[i];
            arr[i] = temp;
        };
    };
};
console.log(arr);
const arr = [9, 5, 2, 8, 4, 6, 3, 5, 7, 1];
//冒泡排序
for (let i = 0; i < arr.length - 1; i++) {
    for (let j = 0; j < arr.length - 1 - i; j++) {
        if (arr[j] > arr[j + 1]) {
            let temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        };
    };
};
console.log(arr);

高阶函数

封装函数

如上文所写的排序代码仅仅局限应用于一个数组,可以将其封装为一个函数,将其中的数组作为形参,然后将其他任意数组作为实参调用此函数,就可以实现此功能的重复使用,而且大幅减少代码量。

高阶函数

如果一个函数的参数或返回值是函数,那么该函数称为高阶函数。

  1. 将一个函数作为另一个函数的参数传递时,这个函数就称为回调函数。
  • 通常回调函数都是匿名函数。
  • 使用回调函数可以动态的传递代码,提升代码灵活性。
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    };
};
let person = [
    new Person("小明", 21),
    new Person("小方", 18),
    new Person("小兰", 16),
    new Person("小红", 20)
];
function filter(arr, cb) {
    const newArray = [];
    for (let i = 0; i < arr.length; i++) {
        if (cb(arr[i])) {
            newArray.push(arr[i]);
        };
    };
    return newArray;
};
let result = filter(person, a => a.age <= 18);
const arr1 = [1, 5, 4, 2, 3, 9, 8, 6];
result = filter(arr1, a => a <= 6);
console.log(result);
  1. 将函数作为返回值可以动态的、在保留原函数功能的基础上添加新功能后生成新函数。(在不改变原函数的基础上添加功能)
function fn() {
    console.log("hello");
    return "hello";
};
function outer(cb) {
    return () => {
        console.log("记录日志");
        const result = cb();
        return result;
    };
};
let result = outer(fn);
result();
function test() {
    console.log("test");
    return "test";
};
let newTest = outer(test);
newTest();

闭包

闭包就是能访问到外部函数作用域中变量的函数。闭包是为了隐藏一些不想被其他人访问到的数据。

构成闭包的三个要件:

  1. 函数的嵌套。
  2. 内部函数要引用外部函数的变量。
  3. 内部函数作为返回值返回。
//闭包的简单例子

function fn() {
    let num = 0;
    return () => {
        num++;
        console.log(num);
    };
};
const result = fn();
console.log(result);
result();
result();
result();
result();
result();

闭包原理:函数的作用域在函数被创建时就已经确定(词法作用域)。和调用位置无关。闭包利用的就是词法作用域。

let a = "全局变量a";
function fn() {
    console.log(a);
};
function fn1() {
    let a = "fn1中的a";
    fn();
};
fn1(); //全局变量a
function fn2() {
    let a = "fn2中的a";
    function fn3() {
        console.log(a);
    };
    return fn3;
};
const result = fn2();
console.log(result);
result(); //fn2中的a

闭包的生命周期:

  • 从外部函数被调用开始产生,外部函数每次调用都会产生新的闭包,意味着闭包会占用一定的内存空间。
  • 从内部函数被销毁后结束(内部函数被垃圾回收了,闭包才会消失)

相较于类,闭包会比较浪费内存空间。当执行次数少时使用闭包,当需要创建大量实例时使用类。

递归: 递归的核心思想是将大问题分解为小问题,小问题解决后大问题也就解决了。

递归的两个要件:

  1. 基线条件。 ----- 递归的终止条件
  2. 递归条件。 ----- 如何对问题拆分
//阶乘求解
function jiecheng(num) {
    if (num === 1) {
        return 1;
    };
    return jiecheng(num - 1) * num;
};
const result = jiecheng(5);
console.log(result); //120
//斐波那契数列
/* 
    1 2 3 4 5 6 7  8  9  10
    1 1 2 3 5 8 13 21 34 55
*/
function fn(num) {
    if (num < 3) {
        return 1;
    };
    return fn(num - 1) + fn(num - 2);
};
const result = fn(6);
console.log(result); //8

数组的其他方法

sort():

  • sort用来对数组进行排序,会改变原数组。
  • 默认依据Unicode码进行升序排序。
  • 参数:可以通过传递一个回调函数来修改排序的升降。
    • (a,b) => a-b; 升序
    • (a,b) => b-a; 降序
const arr = [1, 2, 5, 4, 8, 6, 3, 9, 7, 10];
arr.sort((a, b) => a - b); //1,2,3,4,5,6,7,8,9,10
// arr.sort((a, b) => b - a);  //10,9,8,7,6,5,4,3,2,1
console.log(arr);

forEach():

  • 用来遍历数组。
  • 需要回调函数作为参数,数组有几个元素就调用几次。
  • 每次调用,都会将数组中的元素作为参数传递。
  • 回调函数有三个参数:
    • element :当前元素。
    • index :当前元素的索引。
    • array :遍历的数组。
const arr = [1, 2, 5, 4, 8, 6, 3, 9, 7, 10];
arr.forEach((element, index, array) => {
    console.log(element, index, array);
});

filter():

  • 将数组中的元素添加到新数组。非破坏性方法。
  • 需要一个回调函数作为参数,根据返回值来设置添加条件。
const arr = [1, 2, 5, 4, 8, 6, 3, 9, 7, 10];
const result = arr.filter((ele) => ele % 2 === 0);
console.log(result); //2,4,8,6,10

map():

  • 根据当前数组生成一个新数组。
  • 需要一个回调函数作为参数,会将返回值作为新数组的元素。
const arr1 = ["小明", "小红", "小方", "小兰"];
const arr2 = [1, 2, 5, 4, 8, 6, 3, 9, 7, 10];
const result1 = arr1.map((ele) => "<li> " + ele + "</li>");
const result2 = arr2.map((ele) => ele * 2);
console.log(result1); //['<li> 小明</li>', '<li> 小红</li>', '<li> 小方</li>', '<li> 小兰</li>']
console.log(result2); //[2, 4, 10, 8, 16, 12, 6, 18, 14, 20]

reduce():

  • 将数组所有元素合并为一个值。
  • 参数:
    • 通过回调函数来决定合并的方式。
    • 可选参数:初始值。
const arr = [1, 2, 5, 4, 8, 6];
const result = arr.reduce((a, b) => a + b , 10);
/* 
    1,2 ----3
    3,5 ----8
    8,4 ----12
    12,8 ---20
    20,6 ---26
*/
console.log(result); //46   26+10

可变参数

  • 可变参数可以接受任意数量的实参,并将其添加在一个新数组中。
  • 可变参数的命名可以自己指定,可变参数可以直接使用数组的方法。
  • 可变参数可以与普通参数一起使用,但是可变参数要放在最后。
  • 格式
    • 函数名(...可变参数){ };
function fn(a, b, ...args) {
    return args.reduce((a, b) => a + b);
};
const result = fn(1, 2, 4, 1);
console.log(result); //5

call、apply、bind方法

根据函数调用方式不同,函数中this的指向也不同:

  1. 以函数形式调用,this指向window对象。
  2. 以方法形式调用,this指向调用方法的对象。
  3. 构造函数中,this指向新建的对象。
  4. 箭头函数没有自己的this,只与函数外部的作用域有关。(箭头函数的this无法通过call、apply和bind方法来修改)
  5. 函数的call()和apply()方法的第一个参数就是函数的this。
  6. 函数的bind()方法的第一个参数就是函数的this,并且无法修改。

调用函数的call()和apply()方法,与普通调用函数一致,返回的都是函数对象。

格式:

  • 函数名.call();
  • 函数名.apply();

两个方法的第一个参数都是this的指向,如果函数有形参,那需要在第一个参数后开始编写实参。不同之处在于:

  • call()方法的实参直接写在第一个参数后。
  • apply()方法的实参写在第一个参数后的数组中。
function fn(a, b) {
    console.log(a, b, this);
};
const obj = { name: "小明", age: 18 };
fn.call(obj, 1, 2);
fn.apply(obj, [1, 2]);

函数的bind()方法会新建一个函数:

  • bind会为新函数绑定this(第一个参数)。
  • bind会为新函数绑定参数。
function fn(a, b) {
    console.log(a, b, this);
};
const obj = { name: "小明", age: 18 };
const newFn = fn.bind(obj, 1, 2); //将新函数的this绑定为Obj,将参数绑定为1,2
newFn(3, 4); //1,2,obj

内建对象

解构赋值

数组的解构: 数组的解构赋值也就是将数组元素拆开赋值给指定的变量。

const arr = [1, 2, 3];
[a, b, c] = arr;
console.log(a, b, c);  //解构赋值

解构数组时可以通过 ...参数 的方式来获取多余的参数,放在一个数组中。

const arr = [1, 2, 3, 4, 5, 6];
[a, b, c, ...d] = arr;
console.log(a, b, c, d); //1,2,3,[4,5,6]

可以通过解构赋值快速的交换两个变量的值。

let a1 = 10;
let a2 = 20;
[a1, a2] = [a1, a2];
console.log(a1, a2); //20,10
const arr = [30, 40];
[arr[0], arr[1]] = [arr[1], arr[0]];
console.log(arr); //[40,30]

可以通过以下方法设定默认值,如果数组中有该元素则被数组中元素覆盖,如若没有则变量的值就是默认值。

const arr = [1, 2, 3];
[a, b, c = 5, d = 10] = arr;
console.log(a, b, c, d); //1,2,3,10

若一个数组中的元素也是数组,那我们称该数组为二维数组。

const arr = [["小明", 18, "男"], ["小红", 12, "女"]];
[[name, age, gender], obj] = arr;
console.log(name, age, gender, obj); //小明,18,男,["小红", 12, "女"]

对象的解构: 与数组解构类似。

const obj = { name: "小明", age: 18, gender: "男" };
let { name, age, gender } = obj; //声明变量的同时解构对象
console.log(name, age, gender); //小明,18,男
//若想修改属性名,可以在属性名后加冒号重新命名。
let { name: a, age: b, gender: c, address: d = "南京" } = obj;
console.log(a, b, c, d); //小明,18,男,南京

对象的序列化

序列化是将对象转换为可存储的格式。JS中对象的序列化一般为将对象转换为JSON格式,也就是转换为字符串。

序列化的用途:

  • 用于不同语言之间数据的交换。
  • 用于编写配置文件。

序列化的方法:

  1. JS中有工具类JSON,对象序列化后的字符串称为JSON字符串。
    1. JSON静态方法,将对象转换为JSON字符串:JSON.stringify();
    2. JSON静态方法,将字符串转换为对象:JSON.parse();
  2. 手动写JSON字符串(常用于配置文件中)。
    1. JSON字符串有两种类型:
    • JSON对象:'{ }'
    • JSON数组:'[ ]'
    1. JSON字符串的属性名必须用双引号括起来。
    2. JSON中可以使用的属性值或元素(JS语言中独有的不行):
      1. 数字(Number)
      2. 字符串(String)
      3. 布尔值(Boolean)
      4. 空值(Null)
      5. 数组(Array)
      6. 对象(Object)
    3. JSON对象或数组的最后一个属性值或元素后不能加逗号。
const obj = {
    name: "小明",
    age: 18,
    gender: "男"
};
const str = JSON.stringify(obj);
console.log(typeof str, str); //string {"name":"小明","age":18,"gender":"男"}
const str1 = '{"name":"小方","age":18,"gender":"女"}';
const obj1 = JSON.parse(str);
const obj2 = JSON.parse(str1);
console.log(typeof obj1, obj1); //object
console.log(typeof obj2, obj2); //object
console.log(obj === obj1); //false

可以通过与JSON字符串的转换来实现深复制:

const obj = {
    name: "小明",
    age: 12,
    friend: {
        name: "小红",
        age: 13
    },
};
const obj1 = JSON.parse(JSON.stringify(obj));
obj.friend.name = "小方";
console.log(obj.friend.name); //小方
console.log(obj1.friend.name); //小红

Map(了解即可)

Map用来存储键值对结构的数据(key-value)。

Object所存储的数据也可以说是键值对结构。但是Map与Object存在著区别:

  1. Object对象的属性名必须是字符串或符号,如果传递了其他类型的属性名,JS解释器会自动将其转换为字符串。
  2. Map中任何类型的值都可以作为key。

创建:

  • new Map();

属性和方法:

  1. map.size(); ----- 获取Map中键值对的数量。
  2. map.set(key,value); ----- 向Map中添加键值对。
  3. map.get(key); ----- 根据key获取Map中对应的值。
  4. map.delete(key); ----- 删除指定键值对。
  5. map.has(key); ----- 检查Map中是否包含指定键值对。
  6. map.clear(); ----- 删除Map中全部键值对。
const map = new Map();
const obj = { name: "小方" };
map.set("name", "小明");
map.set("age", 18);
map.set(obj, 123);
console.log(map.get(obj));
console.log(map);
console.log(map.size); //3
console.log(map.delete("age")); //true
console.log(map.has("age")); //false
// map.clear();

将map转换为数组:

  • Array.from(map);
  • [...map];
const map = new Map();
map.set("name", "男");
map.set("age", 18);
map.set("gender", "男");
const arr = Array.from(map);
const arr1 = [...map];
console.log(arr);
console.log(arr1);

遍历map:

  • for(const [key value] of map){ };
  • map.forEach((value,key,entry) => { }); --- 三个参数为值,键以及键值对。
const map = new Map();
map.set("name", "男");
map.set("age", 18);
map.set({}, () => { });
for (const [key, value] of map) {
    console.log(key, value);
};
map.forEach((value, key, entry) => {
    console.log(value, key, entry);
});

获取所有的key,value,entry:

  • map.keys();
  • map.value();
  • map.entries();
const map = new Map();
map.set("name", "男");
map.set("age", 18);
map.set({}, () => { });
for (const key of map.keys()) {
    console.log(key);
};
for (const value of map.values()) {
    console.log(value);
};
for (const entry of map.entries()) {
    console.log(entry);
};

Set(了解即可)

Set用于创建一个集合,与数组类似,但是区别在于不能存储重复数据。

创建:

  • new Set( );
  • new Set([...]);(通过添加数组的方式创建可以轻松达到对数组的去重处理

方法:

  1. size ----- 获取元素数量。
  2. add( ); ----- 添加元素。
  3. has( ); ----- 判断元素是否在集合中。
  4. delete( ); ----- 删除元素。

Math

Math是一个工具类,为我们提供常用的数学常量和方法。

常用常量:

  • Math.PI; ----- 圆周率

常用方法:

  1. Math.abs(); ----- 绝对值
  2. Math.min(); ----- 最小值
  3. Math.max(); ----- 最大值
  4. Math.pow(); ----- x的y次幂
  5. Math.sqrt(); ----- 开方
  6. Math.floor(); ----- 向下取整
  7. Math.ceil(); ----- 向上取整
  8. Math.round(); ----- 四舍五入
  9. Math.trunc(); ----- 去除小数
  10. Math.random(); ----- 生成0到1之间的随机值,不哭哦0不包括1
    1. 生成0到x的任意值
      • Math.round(Math.random() * x);
    2. 生成x到y的任意值
      • Math.round(Math.random() * (y-x) + x);
console.log(Math.abs(-5)); //5
console.log(Math.min(1, 5, 6, 23, 4)); //1
console.log(Math.max(1, 5, 6, 23, 4)); //23
console.log(Math.pow(2, 3)); //8
console.log(Math.sqrt(4)); //2
console.log(Math.floor(-3.2)); //-4
console.log(Math.ceil(3.3)); //4
console.log(Math.round(3.5)); //4
console.log(Math.trunc(3.3)); //3
console.log(Math.round(Math.random() * 4 + 2)); //2到6的任意值

Date

JS中所有与时间有关的数据都由Date对象来表示。

创建:

  • new Date(); ----- 使用该方式创建的对象获得的是当前时间。
  • 可以在Date()构造函数中传表示时间的字符串来创建新的时间。
    • 月/日/年 时:分:秒
    • 年-月-日T时:分:秒

Date对象的方法:

  • getFullYear(); ----- 获取四位年份
  • getMonth(); ----- 获取月份的索引
  • getDate(); ----- 获取是几日
  • getDay(); ----- 获取是周几(0-6,周天为0)
  • getTime(); ----- 返回当前时间的时间戳。(时间戳是1970年1月1日0时0分0秒到当前时间所经历的毫秒数
  • 静态方法:Date.now(); ----- 获取当前时间戳
let d = new Date();
// d = new Date("2022-12-12T12:12:12");
console.log(d.getFullYear());
console.log(d.getMonth());
console.log(d.getDate());
console.log(d.getDay());
console.log(d.getTime());
console.log(Date.now());

日期的格式化:

  1. d.toLocaleDateString(); ----- 将日期转化为本地时间格式的字符串
  2. d.toLocaleTimeString(); ----- 将时间转化为本地时间格式字符串
  3. d.toLocaleString(); ----- 将年月日时间都转化为本地时间格式字符串

参数:

  1. 描述语言和国家信息的字符串。
    • zh-CN:中文中国
    • zh-HK:中文香港
    • en-US:英语英国
  2. 需要一个对象作为参数,通过对象添加属性来修改时间样式。
    • dateStyle ----- 日期的风格
    • timeStyle ----- 时间的风格
      • full
      • long
      • medium
      • short
    • hour12 ----- 是否采用12小时制。
      • true
      • false
    • weekday ----- 星期的表示方式。
      • long
      • short
      • narrow
    • ...等等可通过MDN查询。
let d = new Date();
console.log(d.toLocaleDateString());
console.log(d.toLocaleTimeString());
console.log(d.toLocaleString("zh-CN", { dateStyle: "long", timeStyle: "full" })); 

包装类

JS中一共有五个包装类:

  1. String ----- 字符串包装为String对象
  2. Number ----- 数值包装为Number对象
  3. Boolean ----- 布尔值包装为Boolean对象
  4. BigInt ----- 大整数包装为BigInt对象
  5. Symbol ----- 符号包装为Symbol对象

包装类可以将原始值临时的包装为一个对象,当对调用原始值的属性或方法时,JS解释器会临时将原始值包装为对应的对象,然后调用对象得到属性或方法。

let str = "很好";
str.name = "小明"; //临时将原始值包装为String对象
console.log(str.name); //undefined

字符串的方法:

字符串的方法

字符串本质就是字符数组,很多方法与数组类似,如length获取数组长度,也可以通过索引获取字符串中对应的字符。

常用方法:

  • length ----- 获取字符串长度
  • str.at(); ----- 根据索引获取字符,可以接受负索引
  • str.charAt(); ----- 根据索引获取字符,不接受负索引
  • str.concat(); ----- 用来连接两个或多个字符串
  • str.includes(); ----- 用来检查字符串中是否包含该字符,有则返回true,无则false
  • str.indexOf(); str.lastIndexOf(); ----- 与数组类似,检查字符串中是否有该字符
  • str.startsWith(); ----- 检查字符串是否以某字符开头
  • str.endsWith(); ----- 检查字符串是否以某字符结尾
  • str.padStart(); str.padEnd(); ----- 通过添加指定内容是字符串保持某个长度,第一个参数为长度,第二个参数为要添加的内容
  • str.replace(); ----- 替换字符串指定内容,只替换第一个
  • str.replaceAll(); ----- 替换字符串中所有指定内容
  • str.slice(); ----- 与数组类似,对字符串进行切片
  • str.substring(); ----- 截取字符串
  • str.split(); ----- 用来将字符串拆分为一个数组
  • str.toLowerCase(); ----- 将字符串转化为小写
  • str.toUpperCase(); ----- 将字符串转化为大写
  • str.trim(); ----- 去除字符串前后空格
  • str.trimStart(); ----- 去除前面空格
  • str.trimEnd(); ----- 去除后面空格

正则表达式

正则表达式就是一个规则,可以用来检查字符串是否符合定义的这个规则或者将符合规则的字符从字符串中提取出来,正则表达式也是对象。

创建:

  • (构造函数) new RegExp(); ----- 参数一:正则表达式;参数二:匹配模式
  • (字面量 )/正则表达式/匹配模式

方法:test(); ----- 检查字符串中是否符合规则

let reg = new RegExp("a", "i"); // i : 忽略大小写
let str = "abc";
let result = reg.test(str);
console.log(result); //true

正则表达式:

  1. 大部分字符可以直接写。
  2. | 在正则表达式中表示或。
  3. [](方括号) 表示或(字符集)。
    1. [A-Z]:任意大写字母
    2. [a-z]:任意小写字母
    3. [A-Za-z]:任意大小写字母
    4. [0-9]:任意数字
  4. [^]:表示除了。
    1. [^a]:表示除了a
  5. . 表示除了换行的任意字符。
  6. \ 转义字符。
  7. 其他字符集:
    1. \w -- 任意单词字符[A-Za-z0-9_]
    2. \W -- 除了任意单词字符(取反)[^A-Za-z0-9_]
    3. \d -- 任意数字[0-9]
    4. \D -- 除了任意数字[^0-9]
    5. \s -- 空格
    6. \S -- 除了空格
    7. \b -- 单词边界
    8. \B -- 除了单词边界
  8. 字符串开头和结尾:
    1. ^ 表示字符串的开头
    2. <span data-formula=" 表示字符串的结尾
    • /^abc" aria-hidden="true">/ :表示完全匹配,字符串只能是abc

量词:

  • {m} --- 正好m个
  • {m,} --- 至少m个
  • {m,n} --- m到n个
  • +:一个以上,相当于{1,}
  • *:任意数量
  • ?:0到1个,{0,1}
  • 这些量词只对前一个字母有效

re.exec();

  • 获取字符串中符合正则表达式的字符。
let re = /a(([a-z])c)/g;
let str = "abcajcakcalc";
let result = re.exec(str);
// console.log(result);
while (result) {
    console.log(result[0], result[1], result[2]);
    result = re.exec(str);
};

可以通过括号分组。i表示忽略大小写,g表示全局匹配。

//练习,输出字符串中的手机号码
let str = "adasdas15218493665dadasdsa13865489320fgdhgff17396458219";
let re = /1[3-9]\d{9}/g;
let re1 = /(1[3-9]\d)\d{4}(\d{4})/g;
let result1;
let result2;
while (result1 = re.exec(str)) {
    console.log(result1[0]);
};
console.log("-----------");
while (result2 = re1.exec(str)) {
    console.log(result2[1] + "****" + result2[2]);
};

字符串的正则方法:

  • str.split(/正则表达式/);
    • 根据正则表达式来进行拆分。
  • str.search(/正则表达式/);
    • 搜索符合正则表达式的字符第一次出现的位置。
  • str.replace(/正则表达式/,"要替换的字符");
    • 将符合正则表达式的字符替换为其他字符。
  • str.match(/正则表达式/);
    • 获取符合正则表达式的内容,与exec()方法相似,但是无法进行分组。
  • str.matchAll(/正则表达式/);
    • 获取符合正则表达式的内容,必须设置g 全局匹配。
    • 返回的是一个迭代器。
    • 可以通过for-in来遍历获取内容。

本文章使用limfx的vscode插件快速发布