6.标准库

153 阅读14分钟

标准库(标准API)

  • 库:liberary
  • API:应用程序编程接口,Application Programing Interface
  • 标准:ECMAScript标准

Object

静态成员

  • keys(某个对象),得到某个对象的所有属性名数组
  • values(某个对象),得到某个对象的所有属性值数组
  • entries(某个对象),得到某个对象的所有属性名和属性值的数组

实例成员

实例成员可以被重写

所有对象,都拥有Object的所有实例成员

  • toString方法:得到某个对象的字符串格式

默认情况下,该方法返回"[object Object]";

而对于Number对象来说,toString方法是被重写的,实现不太一样。

function MyNumber(n) {
        this.toString = function() {
            return "" + n;
        }
    }
  • valueOf方法:得到某个对象的值

默认情况下,返回该对象本身

在JS中,当自动的进行类型转换时,如果要对一个对象进行转换,实际上是先调用对象的valueOf方法,然后调用返回结果的toString方法,将得到的结果进行进一步转换。此处需要重新看视频。

下面的代码的输出是什么呢?

var obj = {
        x: 13,
        y: 34534,
        valueOf() {
            return 123;
        }
    }

    console.log(obj + 1);
    // 如果调用了valueOf已经得到了原始类型,则不再调用toString

上面的代码输出是124,而不是 1231,是因为对象先调用了valueOf,获取的对象已经是基本类型123了,就不会再调用toString方法了

Function

所有函数都具有Function中的实例成员

语法:arguments:在函数中使用,获取该函数调用时,传递的所有参数

arguments是一个类数组(也称为伪数组:没有通过Array构造函数创建的类似于数组结构的对象),伪数组会缺少大量的数组实例方法

arguments数组中的值,会与对应的形参映射 下面举例子讲解形参映射的问题

function test(a,b) {
        console.log(arguments);
    }

    test(23, 5, 6, 2, 233, 5, 6, 7);

1.argumnets可以获取到所有的参数

 function test(a, b) {
            arguments[0] = "abc";
            b = 123;
            console.log(a, b);
            console.log(arguments);
        }
 test(1,2);

image.png 我们发现两个值都改了,这叫映射。他们两个是一个东西,前提是一开始建立了映射。

再看下面这一种情况:

 test();

image.png

image.png

为什么是上面的没有互相修改呢?是因为没有在一开始通过test建立映射,映射失败了。只有test传了参数,argumnet这个伪数组里面有内容才能和形式参数之间建立映射。这里传递参数包括你传递了undefined等别的参数,完全啥都不写是建立不了映射的。

再看下面这一种情况:

 test(1);

这个只有第一个参数和形参a建立了映射,改变a或者形参另外一个都会跟着改变。

再看下面这一种情况:

 test(1,undefined);

这个情况,两个参数都建立了映射,改变a,b或者argument都会跟着改变。

下面的代码可以将arguments这个伪数组转化一个真的数组。

function test() {
        console.log(arguments);
        //将arguments转换为真数组
        var newArr = [].slice.call(arguments)
        console.log(newArr);
    }

    test(23, 5, 6, 2, 233, 5, 6, 7);

简单理解可以认为是将数组的slice方法给伪数组用了。其实类似于iOS里面的方法里面的target转发。

实例成员

  • length属性,得到函数形参数量
  • apply方法:调用函数,同时指定函数中的this指向,参数以数组传递
  • call方法:调用函数,同时指定函数中的this指向,参数以列表传递
  • bind方法:得到一个新函数,该函数中的this始终指向指定的值。

通常,可以利用apply、call方法,将某个伪数组转换伪真数组。

下面先举一个例子

 function sayHello(a, b) {
    console.log(this.name, this.age);
    console.log(a, b);
  }

var user1 = {
    name: "asfd",
    age: 123
};

var newFunc = sayHello.bind(user1, 1, 2);
//调用
newFunc();

sayHello.call(user1, 1, 2);

sayHello.apply(user1, [1, 2]);
        

分析一下上面的代码,sayHello如果是直接调用 比方说用下面的代码调用 sayHello(1,2),则这个函数里面的this是指向的是window的,这里我们用 bind(user1,1,2)则这里其实作用是将实际的调用者换成了user1这个对象,而后面的1,2,仍然是sayHello方法需要的参数。

下面我们比较一下三个的差别: 1.bind 和另外两个相比多一个括号,传递的参数直接跟在调用对象的后面 2.apply 和 call都是一个括号,call的参数传递方式和bind一样,而apply是另外用一个中括号去传递参数的。

伪数组转真数组的最常见做法

 function test() {
            console.log(arguments);
            //将arguments转换为真数组
            var newArr = [].slice.call(arguments)
            console.log(newArr);
        }

        test(23, 5, 6, 2, 233, 5, 6, 7);

1.arguments 是伪数组,里面并没有slice这个方法。[] 这个是一个空数组,空数组可以调用slice方法 slice 方法的作用是什么?slice(1,3)表示从数组中下标为1的开始取,然后取到下标为2的元素,如果直接写slice()表示整个数组取出来。而slice方法里面有this的指向,这里将this的指向为arguments。这样其实就相当于对arguments进行这个操作,最后得到一个真数组。

2.更改this指向的核心目的其实就是想用一个本身和自己没关系,也不能调的方法。

Array构造器

凡是通过Array构造函数创建的对象,都是数组

创建方法 new Array(length) 创建长度为length的数组。

静态成员

  • from方法:可以将一个伪数组转换为真数组,ES6才出现的方法。
  • isArray方法:判断一个给定的数据,是否为一个真数组
  • of方法:类似于中括号创建数组,依次赋予数组每一项的值
function test(){
        console.log(Array.isArray(arguments));
        var newArr = Array.from(arguments);
        console.log(newArr, Array.isArray(newArr));
    }

test(1,4,6,57,89,33)

实例成员

  • fill方法:用某个数据填充数组,比方说原数组有5项,现在可以使用fill(1),现在数组里面所有项都是1了。
  • pop :删除数组的最后一个元素并返回删除的元素。
  • push 向数组的末尾添加一个或更多元素,并返回新的长度
  • reverse:将当前数组颠倒顺序
  • shift 1.将数组的第一项删除掉,2.方法的返回值,返回第一个元素。
  • sort:对数组进行排序,不能直接使用,自带的排序只是按照第一位进行排序的,也就是可能会出现 12 小于 2 的情况,如果需要排序需要传递一个函数
 arr.sort(function(a, b) {
        return a - b;
    });
  • splice 选取数组的一部分,并返回一个新数组。
  • unshift 向数组的开头添加一个或更多元素,并返回新的长度。

sort的使用

  var arr = [3, 211, 32, 11, 5, 4];
  arr.sort();
  console.log(arr);

上面的排序结果是:

image.png

上面的排序结果不是按照我们的想法,是因为上面的是按照编码大小取比较。就是说按照前面字符编码大小从第一位开始比较,如果第一位已经比较出来,就不继续往下比较了。

var arr = [3, 211, 32, 11, 5, 4];
arr.sort(function(a, b) {
    return a - b;
});
console.log(arr);

上面的function(a, b) < 0, a排在b前面。 function(a, b) = 0, 位置不变。 function(a, b) > 0, b排在a前面。

纯函数、无副作用函数:不会导致当前对象发生改变

  • concat 连接两个或更多的数组,并返回结果
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr3 = [7, 8, 9];

var newArr = arr1.concat(arr2, arr3);
console.log(newArr);
  • includes: 数组中是否包含满足条件的元素。 是否包含是使用的严格相等,对于对象,必须是同一对象才行。
 var arr = [32, 6, 67, 3, 23, 4];
// 从数组下标3的位置开始寻找,目标是67
console.log(arr.includes(67, 3));

var arr = [{        x: 1,        y: 2    },    {        x: 3,        y: 4    }];
console.log(arr.includes({
    x: 1,
    y: 2
}));

image.png 官方文档中[,] 代表这个参数是可选的,可以传也可以不传。

  • join :把数组的所有元素放入一个字符串。 这个方法可以传递参数,指定字符之间是用什么相连在一起的。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
var energy = fruits.join();
//var energy = fruits.join("-");
console.log(energy);
  • slice 选取数组的一部分,并返回一个新数组。

  • indexOf 搜索数组中的元素,并返回它所在的位置。某个元素第一次出现的下标。没有找到返回 -1

  • lastIndexOf 搜索数组中的元素,并返回它最后出现的位置。某个元素最后一次出现的下标。没有找到返回 -1

  • forEach: 遍历数组

var arr = [234, 65, 2, 423, 5];
arr.forEach(function(item,index,array){
    console.log(item,index,array);
});

forEach内部用的函数可以传递三个参数,item 是当前的迭代的元素,index是下标,array是当前的数组。

  • every:是否所有元素都满足条件
  • some:是否至少有一个元素满足条件
var arr = [37, 25, 48, 55, 30];
//判断是否所有同学都及格
// var result = arr.every(function(item) {
//     return item >= 60;
// });
// console.log(result);

//判断是否至少有一个同学及格
console.log(arr.some(function(item) {
    return item >= 60;
}));

传递的函数同样有三个参数,item,index,array,上面只用了item。

  • filter:过滤,得到满足条件的元素组成的新数组
var arr = [77, 25, 88, 55, 30];
//得到所有及格的分数
var newArr = arr.filter(function(item) {
    return item >= 60;
});

console.log(newArr);
  • find: 查找第一个满足条件的元素,返回元素本身,如果没有找到,返回undefined
  • findIndex: 查找第一个满足条件的元素,返回元素的下标
 var arr = [{
            name: "a",
            age: 11,
            score: 55
        }, {
            name: "b",
            age: 12,
            score: 65
        }, {
            name: "c",
            age: 22,
            score: 85
        }];
        //得到及格的学生(找第一个的下标)
        var index = arr.findIndex(function(item) {
            return item.score >= 60
        });
        console.log(index);
        
         //得到及格的学生(找第一个)
        // var result = arr.find(function(item) {
        //     return item.score >= 60
        // });
        // console.log(result);

        //得到及格的学生
        // var result = arr.filter(function(item) {
        //     return item.score >= 60
        // });

        // console.log(result);
  • map:映射,将数组的每一项映射称为另外一项
var arr = [55, 66, 22, 33, 44, 88];

//得到一个新数组,新数组的每一项是一个对象
//对象中包含两个属性:name、score

var newArr = arr.map(function(item, i) {
    return {
        name: "学生" + (i + 1),
        score: item
    }
});

//得到一个学生的姓名数组
newArr = newArr.map(function(item) {
    return item.name;
});

console.log(newArr);
  • reduce:统计,累计

reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素。 reduce 一共可以传递两个参数,第一个是callback 回调函数,一个是initialValue,初始值,给回调函数用的。 initialValue 可以传也可以不传,不传的时候当数组中没有一个元素时候执行reduceh会报错,当只有一个的时候,回调函数不会被执行。

回调函数接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。

callback (执行数组中每个值的函数,包含四个参数)

1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue),函数必须的参数)
2、currentValue (数组中当前被处理的元素,函数必须的参数)
3、index (当前元素在数组中的索引,非必须的参数)
4array (调用 reduce 的数组,非必须的参数)

initialValue (作为第一次调用 callback 的第一个参数。)

var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
})

var sum = arr.reduce(function(prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
},0)
这里0可以填,可以不填。

上面还可以简写为
var sum = arr.reduce((a,b)=> a+b,0);

console.log(arr, sum);

特别需要注意的点:

var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var arr3 = [7, 8, 9];

var newArr = arr1.concat(arr2, arr3);
console.log(newArr);
var arr = [1, 2];

var sum = arr.reduce(function(s, item) {
    console.log("回调", s, item);
    return s + item;
}, 0);
console.log(sum);
// 链式编程:每一个函数调用返回的类型一致

    var arr = [22, 33, 44, 55, 66, 77, 88];

    // 先对数组进行随机排序
    // 只取及格的分数
    // 得到学生对象的数组(每个学生对象包含姓名和分数)

    var result = arr.sort(function() {
        return Math.random() - 0.5;
    }).filter(function(item) {
        return item >= 60;
    }).map(function(item, i) {
        return {
            name: `学生${i+1}`,
            score: item
        }
    });
    console.log(result);

1.concat一次可以把多个数组合到一个数组中 2.includes除了可以查找基本元素,还可以查找对象.还可以设定可以从某个位置开始查找。 3.forEach循环的时候可以设定在循环的调用某个函数 4.every 和some 判断里面的元素是否满足某个条件 5.filter 过滤,筛选。可以写一个函数,通过函数去判断元素是否满足条件,最后把满足条件的元素放到一个数组中。 6.findIndex 和filter类似,也可以从对象中筛选。 7.Map可以将这样一个数组映射成另外一个数组。

array 的slice 和splice方法使用

slice 单词的意思是切片(不破坏原物),slice 可以参数可以不传参数,代表从开头开始截取,截取到末尾。可以传一个参数,如果参数如正数,代表从开头开始数。如果是负数,则从末尾开始数。一个数代表从当前位置到末尾。如果是传递两个参数,代表从当前位置开始数,到结束的位置,不包含结束的位置。

splice 是拼接(修改原物)这个方法可以传递两个,三个或者三个以上。传递两个参数代表的是从哪个位置开始删除元素,删除几个元素。从第三个开始表示从当前的位置插入多少个元素。

const fruits = ['apple', 'banana', 'orange', 'grape', 'kiwi']

// 从索引1开始到索引3(不包含)
const result1 = fruits.slice(1, 3)
console.log(result1)        // ['banana', 'orange']
console.log(fruits)         // ['apple', 'banana', 'orange', 'grape', 'kiwi'] - 原数组不变

// 从索引2开始到结尾
const result2 = fruits.slice(2)
console.log(result2)        // ['orange', 'grape', 'kiwi']

// 负数索引:从倒数第2个到倒数第1个
const result3 = fruits.slice(-2, -1)
console.log(result3)        // ['grape']

// 场景1:数组浅拷贝
const original = [1, 2, 3, 4, 5]
const copy = original.slice()
console.log(copy)           // [1, 2, 3, 4, 5]
console.log(copy === original) // false - 不是同一个数组

// 场景2:获取数组的一部分
const searchResults = ['result1', 'result2', 'result3', 'result4', 'result5']
const firstThree = searchResults.slice(0, 3)  // 前3条结果
const lastTwo = searchResults.slice(-2)       // 后2条结果

// 场景3:分页处理
function getPage(array, pageSize, pageNumber) {
  const start = (pageNumber - 1) * pageSize
  const end = start + pageSize
  return array.slice(start, end)
}

const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(getPage(data, 3, 1))  // [1, 2, 3] - 第1页
console.log(getPage(data, 3, 2))  // [4, 5, 6] - 第2页

// 从索引1开始删除2个元素
const deleted = fruits.splice(1, 2)
console.log(deleted)        // ['banana', 'orange'] - 被删除的元素
console.log(fruits)         // ['apple', 'grape', 'kiwi'] - 原数组被修改

// 删除最后一个元素
const lastItem = fruits.splice(-1, 1)
console.log(lastItem)       // ['kiwi']
console.log(fruits)         // ['apple', 'grape']

const numbers = [1, 2, 5, 6]

// 在索引2处插入3和4(删除0个元素)
numbers.splice(2, 0, 3, 4)
console.log(numbers)        // [1, 2, 3, 4, 5, 6]

// 在开头插入0
numbers.splice(0, 0, 0)
console.log(numbers)        // [0, 1, 2, 3, 4, 5, 6]

const colors = ['red', 'green', 'blue', 'yellow']

// 从索引1开始,删除2个元素,并插入新元素
const replaced = colors.splice(1, 2, 'purple', 'orange')
console.log(replaced)       // ['green', 'blue'] - 被替换的元素
console.log(colors)         // ['red', 'purple', 'orange', 'yellow']

原始类型包装器

  • new 包装器(值):返回的是一个对象
  • 包装器(值):返回的是一个原始类型

Number

静态成员

  • isNaN 检测指定参数是否为 NaN。
  • isFinite 检测指定参数是否为无穷大
  • isInteger:判断一个数据是否是整数
  • parseFloat: 将一个数据转换为小数
  • parseInt:将以一个数据转换为整数,直接舍去小数部分

parseInt、parseFloat要求参数是一个字符串,如果不是字符串,则会先转换为字符串。 从字符串开始位置进行查找,找到第一个有效的数字进行转换,如果没有找到,则返回NaN,左右空白字符会忽略

parseInt,可以传入第二个参数,表示将给定的字符串,识别为多少进制。

上面都是类似用下面方法调用 Number.isFinite(1);

实例成员

  • toFixed方法:会有四舍五入
  • toPrecision:以指定的精度返回一个数字字符串
  var a = 111;
  a.toFixed(2);

Boolean

String

静态成员

  • fromCharCode:通过unicode编码创建字符串

实例成员

  • length:字符串长度

字符串是一个伪数组

JavaScript 常见字符串方法总结

  1. charAt:返回指定位置的字符。

    • 示例:'hello'.charAt(1) 返回 'e'
  2. charCodeAt:返回指定位置字符的 Unicode 编码。

    • 示例:'hello'.charCodeAt(1) 返回 101(字母 'e' 的 Unicode 编码)。
  3. concat:连接两个或更多字符串,并返回新的字符串。

    • 示例:'hello'.concat(' world') 返回 'hello world'
  4. includes:检查字符串中是否包含指定的子字符串。

    • 示例:'hello'.includes('ell') 返回 true
  5. endsWith:判断字符串是否以指定的子字符串结尾(区分大小写)。

    • 示例:'hello'.endsWith('lo') 返回 true
  6. startsWith:检查字符串是否以指定的子字符串开头。

    • 示例:'hello'.startsWith('he') 返回 true
  7. indexOf:返回指定子字符串在字符串中首次出现的位置。

    • 示例:'hello'.indexOf('l') 返回 2
  8. lastIndexOf:从后向前搜索字符串,返回子字符串最后出现的位置。

    • 示例:'hello'.lastIndexOf('l') 返回 3
  9. padStart:在当前字符串的开头填充指定的字符,直到字符串达到给定的长度。

    • 示例:'5'.padStart(3, '0') 返回 '005'
  10. padEnd:在当前字符串的结尾填充指定的字符,直到字符串达到给定的长度。

    • 示例:'5'.padEnd(3, '0') 返回 '500'
  11. repeat:复制字符串指定次数,并将它们连接在一起返回。

    • 示例:'ha'.repeat(3) 返回 'hahaha'
  12. slice:从某个位置开始,取到某个位置(可以是负数)。

    • 示例:'hello'.slice(1, 3) 返回 'el'
  13. substr:从某个位置开始,取指定长度的字符(位置可以是负数)。

    • 示例:'hello'.substr(1, 3) 返回 'ell'
  14. substring:从某个位置取到某个位置,不能为负数,参数顺序可以调换。

    • 示例:'hello'.substring(1, 3) 返回 'el'
  15. toLowerCase:将字符串转换为小写。

    • 示例:'HELLO'.toLowerCase() 返回 'hello'
  16. toUpperCase:将字符串转换为大写。

    • 示例:'hello'.toUpperCase() 返回 'HELLO'
  17. split:根据指定分隔符将字符串分割为数组。

    • 示例:'a,b,c'.split(',') 返回 ['a', 'b', 'c']
  18. 字符串索引:使用 字符串[index] 直接获取指定位置的字符。

    • 示例:'hello'[1] 返回 'e'

Math对象

提供了一系列与数学相关的成员

常量:永远不会变化的数据。常量一般命名时所有字母大写,如果有多个单词,用下划线分割。

  • random方法: 产生一个0~1之间的随机数
  • PI属性:得到圆周率
  • abs方法:求绝对值
  • floor方法:对一个数向下取整
  • ceil方法:对一个数向上取整
  • max方法:得到一组数字的最大值;如果无参,得到-Infinity
  • min方法:得到一组数字的最小值;如果无参,得到Infinity
  • pow方法:求一个数字的幂次方
  • round方法:得到一个四舍五入的整数

Date构造函数

术语

  1. 时间单位

年(year) 月(month) 日(date) 小时(hour) 分钟(minute) 秒(second) = 1000ms 毫秒(millisecond,ms) = 1000 us 微秒(microsecond,us) = 1000 ns 纳秒(nanosecond,ns)

  1. UTC和GMT

世界划分为24个时区,北京在东8区,格林威治在0时区。

GMT:Greenwish Mean Time 格林威治世界时。太阳时,精确到毫秒。 UTC:Universal Time Coodinated 世界协调时。以原子时间为计时标准,精确到纳秒。

UTC和GMT之间误差不超过0.9秒

GMT+0800 东8区

  1. 时间戳

数字

1970-1-1 凌晨 到 某个时间 所经过的毫秒数

创建时间对象

  • 直接调用函数(不适用new),忽略所有参数,直接返回当前时间的字符串。
  • new Date(): 创建日期对象
  1. 无参,当前时间
  2. 1个参数,参数为数字,表示传入的是时间戳
  3. 两个参数以上,分别表示:年、月、日、时、分、秒、毫秒

注意:月份的数字从0开始计算,所以getMonth() + 1 才是真实的月份

如果缺失参数,日期部分默认为1,时分秒毫秒默认为0。

月、日、时、分、秒、毫秒,均可以传递负数,如果传递负数,会根据指定日期进行计算。

实例成员

  • getDate方法:得到日期部分

  • getDay方法:得到星期几,0表示星期天

  • getFullYear方法:得到年份

  • getHours方法:得到小时部分

  • getMinutes方法:得到分钟部分

  • getSeconds方法:得到秒部分

  • getMilliseconds方法:得到毫秒部分

  • getTime方法:得到时间戳

  • getMonth方法:得到月,从0开始计算

  • setDate方法:设置日期

  • setMonth方法:设置月份

  • setFullYear方法:设置年

  • setMinutes方法

  • setSeconds方法

  • setMilliseconds方法

  • setTime方法:重新设置时间戳

  • toDateString方法:将日期部分转换为可读的字符串。

  • toISOString方法:将整个对象转换为ISO标准的字符串格式。

  • toLocaleDateString方法:根据当前系统的地区设置,将日期部分转换为可读的字符串

  • toLocaleString方法:根据当前系统的地区设置,将整个日期对象转换为可读的字符串

  • toLocaleTimeString方法:根据当前系统的地区设置,将时间部分转换为可读的字符串

日期的运算

日期对象重写了Object中的valueOf方法,返回的是一个数字,表示时间戳

因此,日期对象可以进行数学运算

正则表达式

正则表达式是国际标准,跨越语言

正则表达式是一个规则,用于验证字符串。

基础

  1. 字面量匹配

规则中直接书写字面量字符

  1. 特殊字符
.    查找单个字符,除了换行和行结束符。 
^    匹配字符串的开始。
$    匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n''\r'。要匹配 $ 字符本身,请使用 \$。

3. 转义符 有时需要将特殊含义的符号转化为没有特殊含义,或者没有特殊含义的转化特殊的含义的字符。

\n   匹配一个换行符
\r   匹配一个回车符
\t   匹配一个制表符
\s   匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S   匹配任何非空白字符
\b   匹配一个单词边界,即字与空格间的位置。
\B   非单词边界匹配。
\d   匹配任意一个阿拉伯数字(09)
\D   匹配非数字
\w   匹配字母、数字、下划线。等价于 [A-Za-z0-9_]
\W   和\w相反
\u 按照Unicode去匹配

转义符可以将特殊字符转义

  1. 字符集
[ABC]  作用是匹配A字符,B字符,C字符,注意不是匹配 ABC 字符
[^ABC] 作用是匹配除了ABC以外的所有字符
[A-Z]  作用[A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母。 
[0-9]  作用是匹配数字。

匹配中文: [\u4e00-\u9FA5] 根据Unicode 匹配中文

  1. 量词

前面的规则出现的次数

* 出现0次或者多次
+ 出现一次或者多次
? 出现0次或者一次
{n}: 匹配n个
{n,}: 匹配>=n个
{n,m}: 匹配n-m个

\d[a-z]{3} 只能匹配 1aaa 这种类型的,3代表的[a-z]出现三次 (\d[a-z]){3}代表 1abc1abc1abc

6.或者 多个规则之间,使用或者 |,表示多个规则任选其一。

abc|123 abc或者123 都能匹配

JS中的应用

js中,正则表达式表现为一个对象,该对象是通过构造函数RegExp

创建正则对象

  1. 字面量模式
var reg = /\d+?/;
字面量创建的方式是 / / 里面写正则表达式

对应的标志位有 g:全局匹配 找到所有的匹配项,而不是在第一个匹配后停止 i 忽略大小写 m 多行,将开始和结束标志符在多行上工作 u

  1. 构造函数模式
 var reg = /\d+?/g;
 var reg1 = new RegExp("\d+?","g");
 var reg2 = new RegExp(reg);

如果要放多个标志位

var reg = /\d+?/gi;
var reg1 = new RegExp("\d+?","gi");
var reg2 = new RegExp(reg);

正则实例成员

拿到正则表达式对象,可以通过取正则表达式对象的属性去获取一些东西。

  • global 全局匹配:找到所有的匹配项,而不是在第一个匹配后停止
  • ignoreCase 忽略大小写
  • multiline 多行,将开始和结束标志符在多行上工作。
  • source
  • test方法:验证某个字符串是否满足规则
  • exec方法:execute,执行匹配,得到匹配结果。得到的是一个对象

正则表达式,默认情况下,适用贪婪模式 在量词后,加上?,表示进入非贪婪模式

什么叫贪婪模式还是非贪婪模式? 比方说 /\d+/g 对于字符串 "1234abc123aaa"应该怎么处理呢? 每次如果只匹配 1,2,3,4是满足的正则表达式,也可能一次直接匹配 1234。一次直接匹配到1234 是贪婪模式,而每次只匹配到1,2,3,4就是非贪婪模式。

下面来讲讲全局匹配和不是全局匹配是怎么匹配的?

var reg = /\d+?/g;
var s = "1234abc123aaa";
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);
console.log(s, reg.lastIndex, reg.test(s), reg.lastIndex);

全局匹配是从第一位开始匹配,匹配到了后停止,下一次还是从上一次匹配结束的位置开始,直到最后匹配不到为止。这种结束后再从第一个位置开始匹配。 而非全局匹配是每次开始去匹配。

所以可以用下面的代码来计算匹配的次数

var n = 0;
while (reg.test(s)) {
   n++;
}

console.log(`匹配了${n}次`);
var reg = /\d+/g;
var s = "1234abc123aaa";

//得到所有的匹配结果和位置,下面相当于 window.result = reg.exec(s),因为是全局搜索模式,所以可以获取到匹配的次数。
while (result = reg.exec(s)) {
    console.log(`匹配结果:${result[0]},出现位置:${result.index}`);
}

字符串对象中的正则方法

  • split
  • replace
  • search
  • match

进阶

捕获组

用小括号包裹的部分叫做捕获组,捕获组会出现在匹配结果中

var reg = /(\d[a-z])([a-z]+)/g;
var s = "2afsdf-5fdgdfg-9asddf";
while (result = reg.exec(s)) {
    console.log(result);
}

捕获组的用处是整个大块的匹配到了,把匹配到一整块的一小部分也拿到了,这时候如果要处理这一块就方便了。

捕获组可以命名,叫做具名捕获组

正常的捕获组

var s = "2015-5-1, 2019-6-19, 2000-04-28";
//得到每一个日期,并得到每个日期的年月日
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
while (result = reg.exec(s)) {
//捕获组 ,捕获组1,捕获组2,捕获组3
console.log(result[0],result[1],result[2],result[3]);
}

由于result[1],result[2]这样可读性不好,要使用用捕获组命名。 在捕获组前面使用 ?<名字> 来进行命名

var s = "2015-5-1, 2019-6-19, 2000-04-28";
//得到每一个日期,并得到每个日期的年月日
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
while (result = reg.exec(s)) {
//捕获组 ,捕获组1,捕获组2,捕获组3
console.log(result[0],result[1],result[2],result[3]);
}
var s = "2015-5-1, 2019-6-19, 2000-04-28";
//得到每一个日期,并得到每个日期的年月日
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
while (result = reg.exec(s)) {
//捕获组 ,捕获组1,捕获组2,捕获组3
console.log(result[0],result[1],result[2],result[3]);
}
var s = "2015-5-1, 2019-6-19, 2000-04-28";
//得到每一个日期,并得到每个日期的年月日
var reg = /(?<year>\d{4})-(?<month>\d{1,2})-(?<day>\d{1,2})/g;
while (result = reg.exec(s)) {
console.log(result[0],result.groups.year,result.groups.month,result.groups.day);
}

通过groups.名字去取值

非捕获组 有时我们小括号只想当做一个整体,而不想捕获的时候,我们使用非捕获组,非捕获组我们使用 (?: xxxxx) ,在小括号开始的地方使用?:.

var s = "2015-5-1, 2019-6-19, 2000-04-28";
//得到每一个日期,并得到每个日期的年月日
var reg = /(?:\d{4})-(?:\d{1,2})-(\d{1,2})/g;
while (result = reg.exec(s)) {
    console.log(result);
}

字符串中replace 使用捕获组

1表示第一个捕获组,1 表示第一个捕获组, 2 表示第二个捕获组 $3表示第三个捕获组

var s = "2015-5-1,- 2019-6-19,- 2000-04-28";
var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g;
s = s.replace(reg, "$1/$2/$3")
console.log(s);

反向引用

在正则表达式中,使用某个捕获组,\捕获组编号

下面的意思就是说先匹配两个数字,然后再重复捕获组1一次,这是整个正则匹配的条件。

var reg = /(\d{2})\1/;
var s = "1313";
console.log(reg.test(s));

正向断言(预查)

检查某个字符后面的字符是否满足某个规则,该规则不成为匹配结果,并且不称为捕获组

负向断言(预查)

检查某个字符后面的字符是否不满足某个规则,该规则不成为匹配结果,并且不称为捕获组

错误处理

JS中的错误分为:

  1. 语法错误:会导致整个脚本块无法执行。
  2. 运行错误
    1. 运行报错:会导致当前脚本块后续代码无法执行
    2. 运行结果不符合预期

调试错误

  1. 控制台打印

  2. 断点调试 断点调试可以分为两种,一种是chrome 自带的调试工具,具体文档 chrome 官方调试文档 还有一种是使用VsCode 去调试。

抛出错误

错误在js中本质上是一个对象,抛出错误的语法为:

throw 错误对象;

错误对象的构造函数为Error

捕获错误

try{
    //代码块1
}
catch(错误对象){
    //代码块2
}
finally{
    //代码块3
}

当运行代码1的时候,如果发生错误,立即停止代码1的执行,转而执行代码2错误对象为抛出的错误对象。无论代码1和代码2是否,最终都将执行代码3