JavaScript
JavaScript书写格式
1.行内样式: 写在标签内部
2.内嵌样式(内联样式) : 写在一对head标签中
3.外链样式: 写在一个单独的.js文件中, 再导入进来
JavaScript书写格式注意点
1.不推荐直接将JavaScript代码书写到标签内部
2.默认情况下浏览器会从上至下的解析网页, 所以如果将JavaScript写到一对head标签中, 并且需要通过JavaScript代码操作界面上的元素, 那么就不能直接书写JavaScript代码, 否则无效
2.1如果想将JavaScript写到一对head标签中, 并且需要在JavaScript代码中操作界面上的元素, 那么必须加上window.onload = function(){操作界面元素的JavaScript}
2.2window.onload的含义: 等到界面上所有的内容都加载完毕再执行{}中的代码
2.3由于默认情况下浏览器会从上至下的解析网页, 所以如果想通过JavaScript操作界面上的元素只需要等到元素被加载解析之后操作就可以了, 所以我们还可以将JavaScript代码写到body结束标签的前面
3.如果通过外链式导入.js文件, 并且需要在.js文件中操作界面上的元素, 那么如果是在head标签中导入的, 必须在.js文件中加上window.onload. 如果是在body结束标签前面导入的, 那么就不用添加window.onload
4.如果需要在一对script标签中编写JavaScript代码, 那么就不能同时通过script标签再导入其它的.js文件, 否则书写的JavaScript代码无效
javaScript常见输出方式
1.通过弹窗的形式来输出
alert(需要输出的内容);
confirm(需要输出的内容);
prompt(需要输出的内容);
2.通过网页内容区域的形式来输出
document.write(需要输出的内容);
注意点:
如果需要输出的内容不是数字, 那么就必须通过单引号或者双引号括起来
3.通过开发者工具控制台的形式来输出
console.log(需要输出的内容); // 普通输出
console.warn(需要输出的内容); // 警告输出
console.error(需要输出的内容); // 错误输出
注意点:
如果需要输出的内容不是数字, 那么就必须通过单引号或者双引号括起来
JavaScript中数据
常量
表示一些固定不变的数据
整型常量 实型常量 字符串常量 布尔常量 自定义常量
变量
变量表示一些可以被修改的数据
如何定义一个变量
如何定义一个变量
在JavaScript中可以通过定义变量的方式来生成储物格, 也就是告诉浏览器, 我们需要一块内存空间
var 变量名称;
在JavaScript中第一次给变量赋值, 我们称之为"变量的初始化"
var num;
num = 321; // "变量的初始化"
num = 888; // 不是"变量的初始化"
3.如果一个变量没有进行初始化, 那么变量中存储的是什么呢?
// 在JavaScript中如果定义了一个变量,但是没有进行初始化, 那么变量中存储的是undefined
var num;
console.log(num);
注意点
1.在JavaScript中变量之间是可以相互赋值的
2.在JavaScript中如果定义了同名的变量, 那么后定义的变量会覆盖先定义的变量
3.在老版本的标准的(ES6之前)JavaScript中可以先使用变量, 再定义变量, 并不会报错
由于JavaScript是一门解释型的语言, 会边解析边执行, 浏览器在解析JavaScript代码之前还会进行一个操作"预解析(预处理)"
预解析(预处理)步骤:
将当前JavaScript代码中所有变量的定义和函数的定义放到所有代码的最前面
JavaScript数据类型
基本数据类型
Number 数值类型
在JavaScript中无论是整数还是小数都是属于数值类型的
String 字符串类型
在JavaScript中无论是通过单引号还是通过双引号括起来的内容都是属于字符串类型的
Boolean 布尔类型
在JavaScript中布尔类型比较特殊, 只有两个取值true/false
Undefined 未定义类型
在JavaScript中未定义类型比较特殊, 只有一个取值undefined
Null 空类型
引用数据类型
Object 对象类型
转换为字符串类型
在JavaScript中如果想将以上的四种基本数据类型转换为字符串类型, 常用的方法有三种
1.对于Number类型和Boolean类型来说, 可以通过 变量名称.toString()的方式来转换
2.可以通过String(常量or变量);转换为字符串
3.还可以通过 变量or常量 + “” / 变量or常量 + ''转换为字符串
转换为数值类型
在JavaScript中如果想将以上的四种基本数据类型转换为数值类型, 常用的方法有三种
1.通过Number(常量or变量);方式来转换
2.还可以通过数学运算中的+号和-号来转换
3.还可以通过parseInt(需要转换的字符串)/parseFloat(需要转换的字符串)
转换为布尔类型
在JavaScript中如果想将基本数据类型转换为布尔类型, 那么只需要调用Boolean(常量or变量)
JavaScript运算符
算术运算符
+ - * / %
算术运算符的优先级和结合性
* / % 优先级要高于 + -
无论是+ - * / %都是左结合性(从左至右计算)
加法运算的注意点
1.1任何非数值类型的数据在参与加法运算之前, 都会被自动的转换成数值类型之后, 再参与运算
1.2任何数据和NaN进行运算, 结果都是NaN
1.3任何数据和字符串相加, 都会被先转换成字符串之后再运算
减法运算的注意点
1.1任何非数值类型的数据在参与加法运算之前, 都会被自动的转换成数值类型之后, 再参与运算
1.2任何数据和NaN进行运算, 结果都是NaN
1.3任何数据和字符串相减, 都会先把字符串转换成数值类型之后再运算
乘法和除法运算的注意点
和减法运算的注意点一模一样
模(取余)运算注意点
格式: m%n = 余数
4.1如果m>n的, 那么就正常取余
4.2如果m<n的, 那么结果就是m
4.3如果n是0, 那么结果就是NaN
4.4取余运算结果的正负性, 取决于m而不是n
赋值运算符
什么是赋值运算符?
赋值运算符就是将等号右边的值存储到等号左边的变量中
赋值运算符的优先级和结合性
赋值运算符的优先级低于算数运算符
赋值运算符的结合性是右结合性(从右至左的计算)
赋值运算符的左边只能放变量, 不能放常量
自增自减运算符
自增运算符: ++
自减运算符: –
增和自减写在变量的前面和后面的区别?
写在变量的后面, 表示变量先参与其它的运算, 然后再自增或者自减
写在变量的前面, 表示变量先自增或者自减, 然后再参与其它的运算
自增自减运算符只能出现在变量的前面或者后面, 不能出现在常量或者表达式的前面或者后面
关系运算符
> < >= <= == != === !==
关系运算符的注意点
3.1对于非数值类型的数据, 会先转换成数值类型, 再进行判断
3.2对于关系运算符来说, 任何数据和NaN进行比较, 返回值都是false
3.3如果参与比较的都是字符串类型, 那么不会转换成数值类型再比较, 而是直接比较字符对应的Unicode编码
3.4特殊比较的结果
关系运算符的结合性和优先级
关系运算符都是左结合性(从左至右的运算)
关系运算符中 > < >= <= 的优先级高于 == != === !==
逻辑运算符
逻辑与 &&
格式: 条件表达式A && 条件表达式B
返回值: true false
特点: 一假则假
逻辑或 ||
格式: 条件表达式A || 条件表达式B
返回值: true false
特点: 一真则真
逻辑非 !
格式: !条件表达式
返回值: true false
特点: 真变假, 假变真
逻辑运算符的优先级和结合性
逻辑运算符的结合性是左结合性(从左至右的运算)
在逻辑运算中&&的优先级高于||
逻辑短路现象
条件A && 条件B
由于逻辑与运算的规则是一假则假, 所以只要条件A是假, 那么条件B就不会运算
条件A || 条件B
由于逻辑或运算的规则是一真则真, 所以只要条件A是真, 那么条件B就不会运算
逗号运算符
在JavaScript中逗号运算符一般用于简化代码
逗号运算符优先级和结合性
逗号运算符的结合性是左结合性(从左至右的运算)
逗号运算符的优先级是所有运算符中最低的
逗号运算符的运算符结果就是最后一个表达式的结果
三目运算符
三目运算符又称之为条件运算符
条件表达式 ? 结果A : 结果B;
在三目运算符中当条件为真的时候, 就会返回结果A
在三目运算符中当条件为假的时候, 就会返回结果B
if switch while dowhile
变量作用域
在JavaScript中定义变量有两种方式
ES6之前: var 变量名称;
ES6开始: let 变量名称;
什么是全局变量
全局变量就是定义在{}外面的变量, 我们就称之为全局变量
什么是局部变量
局部变量就是定义在{}里面的变量, 我们就称之为局部变量
全局变量和局部变量的区别
如果是全局变量, 那么有效范围是从定义变量的那一行开始直到文件的末尾都可以使用
如果是局部变量, 那么有效范围是从定义变量的那一行开始直到大括号结束为止(只有在大括号中才能使用)
for循环
for循环的特点
for循环的特点和while循环的特点一样, 只有条件表达式为真, 才会执行循环体
什么是break关键字?
break关键字可以用于switch语句和循环结构中
在switch语句中break关键字的作用是立即结束当前的switch语句
在循环结构中break关键字的作用也是立即结束当前的循环结构
什么是continue关键字?
continue关键字只能用于循环结构
在循环结构中continue关键字的作用是跳过本次循环, 进入下一次循环
数组
数组就是专门用于存储一组数据的
注意点: 和我们前面学习的Number/String/Boolean/Null/undefined不同(基本数据类型)
而我们今天学习的数组(Array)不是基本数据类型, 是引用数据类型(对象类型)
如何创建一个数组?
let 变量名称 = new Array(size);
数组注意点
1.和其它编程语言不同, 如果数组对应的索引中没有存储数据, 默认存储的就是undefined
2.和其它编程语言不同, JavaScript中访问了数组中不存在的索引不会报错, 会返回undefined
3.和其它编程语言不同, 当JavaScript中数组的存储空间不够时数组会自动扩容
4.和其它编程语言不同, JavaScript的数组可以存储不同类型数据
5.和其它编程语言不同, JavaScript中数组分配的存储空间不一定是连续的
6.创建数组的其它方式
1通过构造函数创建数组
let 变量名称 = new Array(size); 创建一个指定大小数组
2通过字面量创建数组
let 变量名称 = []; 创建一个空数组
数组的遍历
数组的遍历就是依次取出数组中存储的所有数据, 我们就称之为数组的遍历
数组的解构赋值
解构赋值是ES6中新增的一种赋值方式
在数组的解构赋值中, 等号左边的格式必须和等号右边的格式一模一样, 才能完全解构
// let [a, b, c] = [1, 3, 5];
// let [a, b, c] = [1, 3, [2, 4]];
数组增删改查
增
1、push()
可接收任意数量的参数,把它们逐个添加至数组末尾,并返回修改后数组的长度
2、unshift()
该方法与push()类似,也可接收任意数量的参数,只不过是将参数逐个添加至数组前端而已,同样返回新数组长度
3、concat()
该方法与push()方法有点类似,同样是将元素添加至数组末尾,只不过这个数组已经不是原来的那个数组了,而是其副本,所以concat()操作数组后会返回一个新的数组。具体用法如下:
① 不传参数,返回当前数组副本
② 传递一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中
③ 传递非数组参数,这些参数就会被直接添加到结果数组的末尾
4、splice()
plice()可以向数组指定位置添加任意数量的元素,需要传入至少3个参数: 起始位置、0(要删除的元素个数)和要添加的元素。
依然接着上面的例子继续:
arr.splice(3,0,0.2,0.4,0.6,0.8);``console.log(arr); ``// [-2, -1, 0, 0.2, 0.4, 0.6, 0.8, 1, 2, 3]
可以看出,splice()与push()和unshift()一样是直接在原数组上修改的。
删
1、pop()
与push()方法配合使用可以构成后进先出的栈,该方法可从数组末尾删除最后一项并返回该项。
2、shift()
与push()方法配合使用可以构成先进先出的队列,该方法可删除数组第一项并返回该项
3、slice()
该**slice()
**方法将数组一部分的浅表副本返回到一个新的数组对象中,该对象选自start
to end
(end
不包括),其中start
和end
表示该数组中各项的索引。原始数组将不会被修改。
可以使用一个负索引,指示与序列末尾的偏移量。slice(-2)
提取序列中的最后两个元素
可以使用一个负索引,指示与序列末尾的偏移量。slice(2,-1)
从序列中的倒数第二个元素提取第三个元素。
4、splice()
改
splice()
查
indexOf()和lastIndexOf()
这两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中,indexOf()从数组的开头(位置0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。
当找不到该元素时,返回 -1 ,lastIndexOf()方法同理。
数组常用方法
Array.concat()
该concat()
方法用于合并两个或多个数组。此方法不更改现有数组,而是返回一个新数组。
Array.copyWithin()
该**copyWithin()**
方法将数组的一部分复制到同一数组中的另一个位置,并在不修改其长度的情况下返回它。
arr.copyWithin(target[, start[, end]])
Array.entries()
该**entries()**
方法返回一个新**Array Iterator**
对象,该对象包含数组中每个索引的键/值对。
const array1 = ['a', 'b', 'c']
const iterator1 = array1.entries();
console.log(iterator1.next());
Array.keys()
该**keys()**
方法返回一个新**Array Iterator**
对象,该对象包含数组中每个索引的键。
const array1 = ['a', 'b', 'c'];
const iterator = array1.keys();
for (const key of iterator) {
console.log(key);
}
// expected output: 0
// expected output: 1
// expected output: 2
Array.values()
该**values()
方法返回一个新Array Iterator
**对象,该对象包含数组中每个索引的值。
const array1 = ['a', 'b', 'c'];
const iterator = array1.values();
for (const value of iterator) {
console.log(value);
}
// expected output: "a"
// expected output: "b"
// expected output: "c"
Array.every()
该**every()
**方法测试数组中的所有元素是否通过提供的功能实现的测试。它返回一个布尔值。
const isBelowThreshold = (currentValue) => currentValue < 40;
const array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold));
// expected output: true
Array.fill()
该**fill()**
方法将数组中的所有元素都更改为静态值,从开始索引(默认0
)到结束索引(默认array.length
)。它返回修改后的数组。
Array.filter()
该**filter()
方法创建一个新数组,**其中所有元素都通过了由提供的功能实现的测试。
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
Array.find()
该**find()**
方法返回提供的数组中满足提供的测试功能的第一个元素的值。
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found);
Array.findIndex()
该**findIndex()**
方法返回满足提供的测试功能的数组中第一个元素的索引。否则,返回,表明没有元素通过测试。-1
Array.flat()
该**flat()**
方法创建一个新数组,其中所有子数组元素都以递归方式连接到该数组中,直到达到指定的深度。
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]
Array.includes()
该**includes()**
方法确定数组在其条目中是否包括某个值,该值是返回值true
还是false
适当的值。
const array1 = [1, 2, 3];
console.log(array1.includes(2));
// expected output: true
Array.join()
该**join()**
方法通过串联数组(或类似数组的对象)中的所有元素(以逗号或指定的分隔符字符串分隔)来创建并返回新字符串。如果数组只有一个项目,则将不使用分隔符而返回该项目。
const elements = ['Fire', 'Air', 'Water'];
console.log(elements.join());
// expected output: "Fire,Air,Water"
Array.map()
该**map()**
方法创建一个新数组,其中填充了在调用数组中每个元素上调用提供的函数的结果。
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
Array.reduce()
该**reduce()**
方法在数组的每个元素上执行(提供的)reduce函数,从而得到单个输出值。
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
Array.reverse()
该**reverse()**
方法将数组反转*就位*。第一个数组元素成为最后一个,最后一个数组元素成为第一个。
const array1 = ['one', 'two', 'three'];
console.log('array1:', array1);
// expected output: "array1:" Array ["one", "two", "three"]
Array.some()
该**some()
**方法测试数组中的至少一个元素是否通过了由提供的功能实现的测试。它返回一个布尔值。
const array = [1, 2, 3, 4, 5];
// checks whether an element is even
const even = (element) => element % 2 === 0;
函数
函数是专门用于封装代码的, 函数是一段可以随时被反复执行的代码块
函数格式
function 函数名称(形参列表){
被封装的代码;
}
函数注意点
1.一个函数可以有形参也可以没有形参(零个或多个)
2.一个函数可以有返回值也可以没有返回值
3.函数没有通过return明确返回值, 默认返回undefined
4.return的作用和break相似, 所以return后面不能编写任何语句(永远执行不到)
5.调用函数时实参的个数和形参的个数可以不相同
6.JavaScript中的函数和数组一样, 都是引用数据类型(对象类型)
函数arguments
arguments的作用
保存所有传递给函数的实参 伪数组
函数扩展运算符
扩展运算符在等号左边, 将剩余的数据打包到一个新的数组中
let [a, ...b] = [1, 3, 5]; a = 1; b = [3, 5];
扩展运算符在等号右边, 将数组中的数据解开
扩展运算符在函数的形参列表中的作用
将传递给函数的所有实参打包到一个数组中
注意点: 和在等号左边一样, 也只能写在形参列表的最后
函数形参默认值
在ES6之前可以通过逻辑运算符来给形参指定默认值
格式: 条件A || 条件B
function getSum(a, b) {
a = a || "指趣学院";
b = b || "知播渔教育";
console.log(a, b);
}
从ES6开始, 可以直接在形参后面通过=指定默认值
注意点: ES6开始的默认值还可以从其它的函数中获取
function getSum(a = "指趣学院", b = getDefault()) {
console.log(a, b);
}
匿名函数
匿名函数就是没有名称的函数
匿名函数不能够只定义不使用
匿名函数的应用场景
3.1作为其他函数的参数
3.2作为其他函数的返回值
3.3作为一个立即执行的函数
箭头函数
箭头函数是ES6中新增的一种定义函数的格式
目的: 就是为了简化定义函数的代码
箭头函数的注意点
4.1在箭头函数中如果只有一个形参, 那么()可以省略
4.2在箭头函数中如果{}中只有一句代码, 那么{}也可以省略
递归函数
递归函数就是在函数中自己调用自己, 我们就称之为递归函数
递归函数在一定程度上可以实现循环的功能
递归函数的注意点
每次调用递归函数都会开辟一块新的存储空间, 所以性能不是很好
函数变量作用域
定义变量
在JavaScript中定义变量有两种方式
ES6之前: var 变量名称;
ES6开始: let 变量名称;
1、通过var定义变量,可以重复定义同名的变量,并且后定义的会覆盖先定义的
如果通过let定义变量, "相同作用域内"不可以重复定义同名的变量
2、通过var定义变量, 可以先使用后定义(预解析)
通过let定义变量, 不可以先使用再定义(不会预解析)
3、是否能被{}限制作用域
无论是var还是let定义在{}外面都是全局变量
将var定义的变量放到一个单独的{}里面, 还是一个全局变量
将let定义的变量放到一个单独的{}里面, 是一个局部变量
作用域
1.在JavaScript中{}外面的作用域, 我们称之为全局作用域
2.在JavaScript中函数后面{}中的的作用域, 我们称之为"局部作用域"
3.在ES6中只要{}没有和函数结合在一起, 那么应该"块级作用域"
4.块级作用域和局部作用域区别
4.1在块级作用域中通过var定义的变量是全局变量
4.2在局部作用域中通过var定义的变量是局部变量
5.无论是在块级作用域还是在局部作用域, 省略变量前面的let或者var就会变成一个全局变量
注意点: 在不同的作用域范围内, let是可以出现同名的变量的
注意点: 只要出现了let, 在相同的作用域内, 就不能出现同名的变量
作用域链
ES6之前作用域链
1.1.全局作用域我们又称之为0级作用域
2.2.定义函数开启的作用域就是1级/2级/3级/…作用域
2.3.JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
0 —> 1 ----> 2 ----> 3 ----> 4
2.4.除0级作用域以外, 当前作用域级别等于上一级+1
3.变量在作用域链查找规则
3.1先在当前找, 找到就使用当前作用域找到的
3.2如果当前作用域中没有找到, 就去上一级作用域中查找
3.3以此类推直到0级为止, 如果0级作用域还没找到, 就报错
ES6作用域链
1.1.全局作用域我们又称之为0级作用域
2.2.定义函数或者代码块都会开启的作用域就是1级/2级/3级/…作用域
2.3.JavaScript会将这些作用域链接在一起形成一个链条, 这个链条就是作用域链
0 —> 1 ----> 2 ----> 3 ----> 4
2.4.除0级作用域以外, 当前作用域级别等于上一级+1
3.变量在作用域链查找规则
3.1先在当前找, 找到就使用当前作用域找到的
3.2如果当前作用域中没有找到, 就去上一级作用域中查找
3.3以此类推直到0级为止, 如果0级作用域还没找到, 就报错
*/
-预解析
预解析规则
2.1将变量声明和函数声明提升到当前作用域最前面
2.2将剩余代码按照书写顺序依次放到后面
注意点
通过let定义的变量不会被提升(不会被预解析)
下列程序的执行结果 :
if(true){
function demo() {
console.log("hello demo1");
}
}else{
function demo() {
console.log("hello demo2");
}
}
demo(); // 高级hello demo1 低级hello demo2
/*
function demo() {
console.log("hello demo1");
}
function demo() {
console.log("hello demo2");
}
if(true){}else{}
demo();
*/
- 在ES6之前没有块级作用域, 并且没有将这两个函数定义到其它的函数中,
- 所以这两个函数应该属于全局作用域
注意点 : - 在高级浏览器中, 不会对{}中定义的函数进行提升
- 只有在低级浏览器中, 才会按照正常的方式解析
练习2
如果变量名称和函数名称同名, 那么函数的优先级高于变量
console.log(value); // 会输出函数的定义
var value = 123;
function value() {
console.log("fn value");
}
console.log(value); // 123
/*
function value() {
console.log("fn value");
}
console.log(value);
var value;
value = 123;
console.log(value);
*/
对象
面向对象(Object Oriented,OO)是软件开发方法
面向对象是一种对现实世界抽象的理解,是计算机编程技术发展到一定阶段后的产物
Object Oriented Programming-OOP ——面向对象编程
创建默认对象
JavaScript中提供了一个默认的类Object, 我们可以通过这个类来创建对象
创建对象的第一种方式
let obj = new Object();
创建对象的第二种方式
let obj = {}
创建对象的第三种方式
let obj = {
name: "lnj",
age: 33,
say: function () {
console.log("hello world");
}
};
函数和方法区别
1.什么是函数?
函数就是没有和其它的类显示的绑定在一起的, 我们就称之为函数
2.什么是方法?
方法就是显示的和其它的类绑定在一起的, 我们就称之为方法
3函数和方法的区别
3.1函数可以直接调用, 但是方法不能直接调用, 只能通过对象来调用
3.2函数内部的this输出的是window, 方法内部的this输出的是当前调用的那个对象
4.无论是函数还是方法, 内部都有一个叫做this的东东
this是什么? 谁调用了当前的函数或者方法, 那么当前的this就是谁
工厂函数
工厂函数就是专门用于创建对象的函数, 我们就称之为工厂函数
function createPerson(myName, myAge) {
let obj = new Object();
obj.name = myName;
obj.age = myAge;
obj.say = function () {
console.log("hello world");
}
return obj;
}
let obj1 = createPerson("lnj", 34);
let obj2 = createPerson("zs", 44);
console.log(obj1);
console.log(obj2);
构造函数
构造函数和工厂函数一样, 都是专门用于创建对象的
构造函数本质上是工厂函数的简写
function Person(myName, myAge) {
// let obj = new Object(); 1.1 // 系统自动添加的
// let this = obj; 1.2// 系统自动添加的
this.name = myName;
this.age = myAge;
this.say = function () {
console.log("hello world");
}
// return this; //1.3 系统自动添加的
}
new Person("lnj", 34);
当我们new Person(“lnj”, 34);系统做了什么事情
1.1会在构造函数中自动创建一个对象
1.2会自动将刚才创建的对象赋值给this
1.3会在构造函数的最后自动添加return this;
prototype特点
JavaScript 规定,每一个构造函数都有一个prototype 属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
prototype特点
1.1存储在prototype中的方法可以被对应构造函数创建出来的所有对象共享
1.2prototype中除了可以存储方法以外, 还可以存储属性
1.3prototype如果出现了和构造函数中同名的属性或者方法, 对象在访问的时候, 访问到的是构造函中的数据
prototype应用场景
prototype中一般情况下用于存储所有对象都相同的一些属性以及方法
如果是对象特有的属性或者方法, 我们会存储到构造函数中
对象三角恋关系
1.每个"构造函数"中都有一个默认的属性, 叫做prototype
prototype属性保存着一个对象, 这个对象我们称之为"原型对象"
2.每个"原型对象"中都有一个默认的属性, 叫做constructor
constructor指向当前原型对象对应的那个"构造函数"
3.通过构造函数创建出来的对象我们称之为"实例对象"
每个"实例对象"中都有一个默认的属性, 叫做__proto__
__proto__指向创建它的那个构造函数的"原型对象"
函数对象原型关系
1.所有的构造函数都有一个prototype属性, 所有prototype属性都指向自己的原型对象
2,所有的原型对象都有一个constructor属性, 所有constructor属性都指向自己的构造函数
3.所有函数都是Function构造函数的实例对象
4.所有函数都是对象, 包括Function构造函数
5.所有对象都有__proto__属性
6.普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"
7.所有对象的__proto__属性最终都会指向"Object原型对象"
8."Object原型对象"的__proto__属性指向NULL
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D7iZmMPx-1604331278014)(%E5%8E%9F%E5%9E%8B.PNG)]
原型链
1.对象中__proto__组成的链条我们称之为原型链
2.对象在查找属性和方法的时候, 会先在当前对象查找
如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
如果找到Object原型对象都没有找到, 就会报错
封装性
封装性
就是隐藏实现细节,仅对外公开接口
为什么要封装?
4.1不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,别人可以任意的修改你的属性
4.2封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改. 封装是面向对象设计本质(将变化隔离)。这样降低了数据被误用的可能 (提高安全性和灵活性)
属性方法
在JavaScript中属性和方法分类两类
1.1实例属性/实例方法
在企业开发中通过实例对象访问的属性, 我们就称之为实例属性
在企业开发中通过实例对象调用的方法, 我们就称之为实例方法
1.2静态属性/静态方法
在企业开发中通过构造函数访问的属性, 我们就称之为静态属性
在企业开发中通过构造函数调用的方法, 我们就称之为静态方法
继承
想要继承,就必须要提供个父类(继承谁,提供继承的属性)
一、原型链继承
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
二、借用构造函数继承
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
三、组合继承(组合原型链继承和借用构造函数继承)(常用)
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
四、原型式继承
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
五、寄生式继承
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
六、寄生组合式继承(常用)
寄生:在函数内返回对象然后调用
组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参
重点:修复了组合继承的问题
继承这些知识点与其说是对象的继承,更像是函数的功能用法,如何用函数做到复用,组合,这些和使用继承的思考是一样的。上述几个继承的方法都可以手动修复他们的缺点,但就是多了这个手动修复就变成了另一种继承模式。
这些继承模式的学习重点是学它们的思想,不然你会在coding书本上的例子的时候,会觉得明明可以直接继承为什么还要搞这么麻烦。就像原型式继承它用函数复制了内部对象的一个副本,这样不仅可以继承内部对象的属性,还能把函数(对象,来源内部对象的返回)随意调用,给它们添加属性,改个参数就可以改变原型对象,而这些新增的属性也不会相互影响。
bind-call-apply
1.bind方法作用
修改函数或者方法中的this为指定的对象, 并且会返回一个修改之后的新函数给我们
注意点: bind方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
2.call方法作用
修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数
注意点: call方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面
3.apply方法作用
修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数
注意点: apply方法除了可以修改this以外, 还可以传递参数, 只不过参数必须通过数组的方式传递
多态
多态是指事物的多种状态
多态在编程语言中的体现
父类型变量保存子类型对象, 父类型变量当前保存的对象不同, 产生的结果也不同
ES6类和对象
class Person{
// 当我们通过new创建对象的时候, 系统会自动调用constructor
// constructor我们称之为构造函数
constructor(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 实例属性
// name = "lnj";
// age = 34;
// 实例方法
say(){
console.log(this.name, this.age);
}
// 静态属性(es6不支持这样写静态属性 只有外部添加)
static num = 666;
// 静态方法
static run() {
console.log("run");
}
}
注意点:
如果通过class定义类, 那么不能自定义这个类的原型对象
如果想将属性和方法保存到原型中, 只能动态给原型对象添加属性和方法
ES6继承
ES6之前的继承
// 1.在子类中通过call/apply方法借助父类的构造函数
// 2.将子类的原型对象设置为父类的实例对象
ES6开始的继承
class Person{
constructor(myName, myAge){
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
}
say(){
console.log(this.name, this.age);
}
}
/*
1.在ES6中如何继承
1.1在子类后面添加extends并指定父类的名称
1.2在子类的constructor构造函数中通过super方法借助父类的构造函数
*/
// 以下代码的含义: 告诉浏览器将来Student这个类需要继承于Person这个类
class Student extends Person{
constructor(myName, myAge, myScore){
// 1.在子类中通过call/apply方法借助父类的构造函数
// Person.call(this, myName, myAge);
super(myName, myAge);
this.score = myScore;
}
study(){
console.log("day day up");
}
}
let stu = new Student("zs", 18, 98);
stu.say();
获取对象类型
let arr = new Array();
console.log(arr);
// console.log(typeof arr); // object
console.log(arr.constructor.name); // Array
instanceof关键字
instanceof用于判断 “对象” 是否是指定构造函数的 “实例”
instanceof注意点
只要 构造函数的原型对象 出现在实例对象的原型链中都会返回true
isPrototypeOf属性
isPrototypeOf用于判断 一个对象是否是另一个对象的原型
isPrototypeOf注意点
只要调用者在传入对象的原型链上都会返回true
判断对象属性
in的特点: 只要类中或者原型对象中有, 就会返回true
console.log(“name” in p); // true
判断某一个对象自身是否拥有某一个属性
console.log(p.hasOwnProperty(“name”));
/特点: 只会去类中查找有没有, 不会去原型对象中查找
对象增删改查
增加©
// p.name = "lnj";
p["name"] = "zs";
删除®
// delete p.name;
// delete p["name"];
修改(U)
// p.name = "lnj";
// p["name"] = "ww";
查询(D)
// console.log(p.name);
// console.log(p["name"]);
对象遍历
在JS中可以通过高级for循环来遍历对象
以下代码的含义: 将指定对象中所有的属性和方法的名称取出来了依次的赋值给key这个变量
for in
主要用于遍历对象的可枚举属性,包括自有属性、继承自原型的属性
Object.keys
此方法返回一个数组,元素均为对象自有可枚举的属性
Object.getOwnProperty
此方法用于返回对象的自有属性,包括可枚举和不可枚举的属性
深拷贝和浅拷贝
深拷贝
修改新变量的值不会影响原有变量的值
默认情况下基本数据类型都是深拷贝
浅拷贝
修改新变量的值会影响原有的变量的值
默认情况下引用类型都是浅拷贝
深拷贝的方法
JSON转换
var targetObj = JSON.parse(JSON.stringify(copyObj))
let arr4 = JSON.parse(JSON.stringify(arr))
缺点:
(1)如果对象里有函数,函数无法被拷贝下来
(2)无法拷贝copyObj对象原型链上的属性和方法
(3)当数据的层次很深,会栈溢出
递归拷贝
function deepCopy(target,source) {
// 1.通过遍历拿到source中所有的属性
for(let key in source){
// 2.取出当前遍历到的属性对应的取值
let sourceValue = source[key];
// 3.判断当前的取值是否是引用数据类型
if(sourceValue instanceof Object){
//获取当前值的对象构造函数名同时new给当前的key
let subTarget = new sourceValue.constructor
target[key]=subTarget
//递归进行拷贝
deepCopy(subTarget,sourceValue)
}else{
target[key]=sourceValue
}
}
}
字符串常用方法
charAt(x)
/*
charAt() 方法从一个字符串中返回指定的字符。
参数:
index:一个介于0 和字符串长度减1之间的整数。 (0~length-1)
返回值:
返回查询到的字符
找不到返回的是空字符串而不是undefined或者是对应的编码值
*/
str.charAt(index)
2. charCodeAt(x)
/*
charCodeAt:获取指定支付的ASCII码值(Unicode编码值)
参数:
n[number]获取字符指定的索引
返回值:
返回查找到的字符
找不到返回的是空字符串而不是undefined或者是对应的编码值
*/
str.charCodeAt(index)
3. concat(str1,str2)
/*
concat() 方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。
参数:
string2...stringN
和原字符串连接的多个字符串
返回值:
新的字符串
*/
str.concat(string2, string3[, ..., stringN])
4. fromCharcode()
/*
fromCharcode(c1,c2)返回由指定的UTF-16代码单元序列创建的字符串。
参数:
num1, ..., numN
一系列UTF-16代码单元的数字。 范围介于0到65535(0xFFFF)之间。 大于0xFFFF的数字将被截断。 不进行有效性检查。
返回值:
一个长度为N的字符串,由N个指定的UTF-16代码单元组成
*/
String.fromCharCode(num1, ..., numN)
//示例:
String.fromCharCode(65, 66, 67); // returns "ABC"
5. indexOf()
/*
indexOf() 方法返回调用它的 String 对象中第一次出现的指定值的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1。
参数:
searchValue
一个字符串表示被查找的值。如果没有提供确切地提供字符串,searchValue 会被强制设置为 "undefined", 然后在当前字符串中查找这个值。
fromIndex 可选
表示开始查找的位置。可以是任意整数,默认值为 0。如果 fromIndex 小于 0,则查找整个字符串(等价于传入了 0)。如果 fromIndex 大于等于 str.length,则必返回 -1。
*/
str.indexOf(searchValue, fromIndex)
//示例:
"Blue Whale".indexOf("Blue"); // 返回 0
"Blue Whale".indexOf("Blute"); // 返回 -1
"Blue Whale".indexOf("Whale", 0); // 返回 5
"Blue Whale".indexOf("Whale", 5); // 返回 5
6. lastIndexOf()
/*
lastIndexOf() 方法返回指定值在调用该方法的字符串中最后出现的位置,如果没找到则返回 -1。length为需要检索字符串的长度,默认值为str.length。
参数:
searchValue
一个字符串,表示被查找的值。如果searchValue是空字符串,则返回fromIndex。
*/
str.lastIndexOf(searchValue[, length])
7. match()
/*
match() 方法检索返回一个字符串匹配正则表达式的的结果。
参数:
regexp
一个正则表达式对象。如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为一个 RegExp 。如果你没有给出任何参数并直接使用match() 方法 ,你将会得到一个包含空字符串的 Array :[""] 。
返回值:
如果使用g标志,则将返回与完整正则表达式匹配的所有结果(Array),但不会返回捕获组,或者未匹配 null。
如果未使用g标志,则仅返回第一个完整匹配及其相关的捕获组(Array)。 在这种情况下,返回的项目将具有如下所述的其他属性,或者未匹配 null。
*/
str.match(regexp)
8. replace()
/*
replace() 方法返回一个由替换值替换一些或所有匹配的模式后的新字符串。
*/
str.replace(regexp|substr, newSubStr|function)
9. search()
/*
search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,如果找到,返回与 regexp 相匹配的子串的起始位置,否则返回 -1。
*/
//search(regexp)
var intRegex = /[0-9 -()+]+$/;
var myNumber = '999';
var isInt = myNumber.search(intRegex);
console.log(isInt);
//output: 0
10. slice()
/*
slice()方法可提取字符串的某个部分,返回一个新的字符串。包括字符串从start开始(包括start)到end结束(不包括end)为止的所有字符。
*/
//slice(start, end)
var text="excellent"
text.slice(0,4) //returns "exce"
text.slice(2,4) //returns "ce"
11. split()
/*
split() 方法用于把一个字符串分割成字符串数组,返回一个字符串数组返回的数组中的字串不包括 delimiter自身。可选的“limit”是一个整数,允许各位指定要返回的最大数组的元素个数。
*/
//substr(start, [length])
//原文没有,新加的
var text = "hello";
text.split(""); //可返回 ["h", "e", "l", "l", "o"]
text.split("", 3); //可返回 ["h", "e", "l"]
12. substr(start, [length])
/*
substr()方法可在字符串中抽取从 start 下标开始的指定数目的字符。返回一个新的字符串,包含从 start(包括 start 所指的字符) 处开始的 length 个字符。如果没有指定 length,那么返回的字符串包含从 start 到该字符串的结尾的字符。
*/
//substr(from, to)
var text="excellent"
text.substr(0,4) //returns "exce"
text.substr(2,4) //returns "cell"
13. substring(from, [to])
/*
substring() 方法用于提取字符串中介于两个指定下标之间的字符,方法返回的子串包括 start 处的字符,但不包括 stop 处的字符,to 可选,如果省略该参数,那么返回的子串会一直到字符串的结尾。
*/
//substring(from, [to])
var myString = 'javascript rox';
myString = myString.substring(0,10);
console.log(myString)
//output: javascript
14. toLowerCase()
/*
toLowerCase() 方法用于把字符串转换为小写。
*/
//toLowerCase()
var myString = 'JAVASCRIPT ROX';
myString = myString.toLowerCase();
console.log(myString)
//output: javascript rox
15. toUpperCase()
/*
toUpperCase() 方法用于把字符串转换为大写。
*/
//toUpperCase()
var myString = 'javascript rox';
myString = myString.toUpperCase();
console.log(myString)
//output: JAVASCRIPT ROX
16. includes()
/*
includes() 方法用于检查字符串是否包含指定的字符串或字符。
*/
//includes()
var mystring = "Hello, welcome to edureka";
var n = mystring.includes("edureka");
//output: True
17. endsWith()
/*
endsWith()函数检查字符串是否以指定的字符串或字符结束。
*/
//endsWith()
var mystr = "List of javascript functions";
var n = mystr.endsWith("functions");
//output: True
18. repeat()
/*
repeat() 构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本。
*/
//repeat()
var string = "Welcome to Edureka";
string.repeat(2);
//output: Welcome to Edureka Welcome to Edureka
19. valueOf()
/*
valueOf() 方法返回一个String对象的原始值(primitive value),该值等同于String.prototype.toString()。
*/
/valueOf()
var mystr = "Hello World!";
var res = mystr.valueOf();
//output: Hello World!
20. trim()
/*
trim() 方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符 (space, tab, no-break space 等) 以及所有行终止符字符(如 LF,CR)。
*/
//trim()
var str = " Hello Edureka! ";
alert(str.trim());
21.**String.padStart()**String.padEnd()
str.padStart(targetLength [, padString])
targetLength
当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
padString 可选
填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "(U+0020)
const str1 = '5';
console.log(str1.padStart(2, '0'));
// expected output: "05"
基本数据类型和基本包装类型
有哪些基本数据类型?
字符串类型 / 数值类型 / 布尔类型 / 空类型 / 未定义类型
以前之所以能够访问基本数据类型的属性和方法, 是因为
在运行的时候系统自动将基本数据类型包装成了对象类型
ECMAScript 还提供了 3 个特殊的引用类型:Boolean、Number 和String
JavaScript-三大对象
JavaScript中提供三种自带的对象, 分别是"本地对象"/“内置对象”/“宿主对象”
宿主就是指JavaScript运行环境, js可以在浏览器中运行, 也可以在服务器上运行(nodejs)
1.本地对象
与宿主无关,无论在浏览器还是服务器中都有的对象
就是ECMAScript标准中定义的类(构造函数)。
在使用过程中需要我们手动new创建
例如:Boolean、Number、String、Array、Function、Object、Date、RegExp等。
2.内置对象
与宿主无关,无论在浏览器还是服务器中都有的对象
ECMAScript已经帮我们创建好的对象。
在使用过程中无需我们手动new创建
例如:Global、Math、JSON
3.宿主对象
对于嵌入到网页中的JS来说,其宿主对象就是浏览器, 所以宿主对象就是浏览器提供的对象
包含: Window和Document等。
所有的DOM和BOM对象都属于宿主对象。
Math
Math
是一个内置对象,它拥有一些数学常数属性和数学函数方法。Math
不是一个函数对象。
Math
用于 Number
类型。它不支持 BigInt
。
1,Math.abs()
获取绝对值
Math.abs(-12) = 12
2,Math.ceil() and Math.floor()
向上取整和向下取整
console.log(Math.ceil(12.03));//13
console.log(Math.ceil(12.92));//13
console.log(Math.floor(12.3));//12
console.log(Math.floor(12.9));//12
3,Math.round()
四舍五入
注意:正数时,包含5是向上取整,负数时包含5是向下取整。
1、Math.round(-16.3) = -16
2、Math.round(-16.5) = -16
3、Math.round(-16.51) = -17
4,Math.random()
取[0,1)的随机小数
案例1:获取[0,10]的随机整数
console.log(parseInt(Math.random()*10));//未包含10
console.log(parseInt(Math.random()*10+1));//包含10
案例2:获取[n,m]之间的随机整数
Math.round(Math.random()*(m-n)+n)
5,Math.max() and Max.min()
获取一组数据中的最大值和最小值
console.log(Math.max(10,1,9,100,200,45,78));
console.log(Math.min(10,1,9,100,200,45,78));
6,Math.PI
获取圆周率π 的值
console.log(Math.PI);
7,Math.pow() and Math.sqrt()
Math.pow()获取一个值的多少次幂
Math.sqrt()对数值开方
1.Math.pow(10,2) = 100;
2.Math.sqrt(100) = 10;
[](javascript:void(0)😉
//例子:自己定义一个对象,实现系统的max的方法 function Mymax() { //添加了一个方法 this.getMax = function () { //假设这个数是最大值 var max = arguments[0]; for (var i = 0; i < arguments.length; i++) { if (max < arguments[i]) { max = arguments[i]; } } return max; }; } // 实例对象 var my = new Mymax(); console.log(my.getMax(9, 5, 6, 32)); console.log(Math.max(9, 5, 6, 32));
正则表达式
正则表达式是用于匹配字符串中字符组合的模式,在 JavaScript中,正则表达式也是对象。
- 正则表达式是在宿主环境下运行的,如
js/php/node.js
等
创建正则
字面量创建
使用//
包裹的字面量创建方式是推荐的作法,但它不能在其中使用变量
let hd = "houdunren.com";
console.log(/u/.test(hd));//true
对象创建
let reg = new RegExp(web);
console.log(reg.test(hd)); //true
选择符
|
这个符号带表选择修释符,也就是 |
左右两侧有一个匹配到就可以。
let tel = "010-12345678";
/正确结果:所以需要放在原子组中使用
console.log(tel.match(/(010|020)\-\d{7,8}/));
字符转义
转义用于改变字符的含义,用来对某个字符有多种语义时的处理。
假如有这样的场景,如果我们想通过正则查找/
符号,但是 /
在正则中有特殊的意义。如果写成///
这会造成解析错误,所以要使用转义语法 /\//
来匹配。
const url = "https://www.houdunren.com";
console.log(/https:\/\//.test(url)); //true
字符边界
使用字符边界符用于控制匹配内容的开始与结束约定。
边界符 | 说明 |
---|---|
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束,忽略换行符 |
元子字符
字符列表
元字符 | 说明 | 示例 |
---|---|---|
\d | 匹配任意一个数字 | [0-9] |
\D | 与除了数字以外的任何一个字符匹配 | [^0-9] |
\w | 与任意一个英文字母,数字或下划线匹配 | [a-zA-Z_] |
\W | 除了字母,数字或下划线外与任何字符匹配 | [^a-zA-Z_] |
\s | 任意一个空白字符匹配,如空格,制表符\t ,换行符\n | [\n\f\r\t\v] |
\S | 除了空白符外任意一个字符匹配 | [^\n\f\r\t\v] |
. | 匹配除换行符外的任意字符 |
let hd = "houdunren 2010";
console.log(hd.match(/\d/g)); //["2", "0", "1", "0"]
原子表
在一组字符中匹配某个元字符,在正则表达式中通过元字符表来完成,就是放到[]
(方括号)中。
[#](https://houdunren.gitee.io/note/js/14 正则表达式.html#使用语法)使用语法
原子表 | 说明 |
---|---|
[] | 只匹配其中的一个原子 |
[^] | 只匹配"除了"其中字符的任意一个原子 |
[0-9] | 匹配0-9任何一个数字 |
[a-z] | 匹配小写a-z任何一个字母 |
[A-Z] | 匹配大写A-Z任何一个字母 |
实例操作
使用[]
匹配其中任意字符即成功,下例中匹配ue
任何一个字符,而不会当成一个整体来对待
const url = "houdunren.com";
console.log(/ue/.test(url)); //false
console.log(/[ue]/.test(url)); //true
原子组
- 如果一次要匹配多个元子,可以通过元子组完成
- 原子组与原子表的差别在于原子组一次匹配多个元子,而原子表则是匹配任意一个字符
- 元字符组用
()
包裹
下面使用原子组匹配 h1
标签,如果想匹配 h2
只需要把前面原子组改为 h2
即可。
const hd = `<h1>houdunren.com</h1>`;
console.log(/<(h1)>.+<\/\1>/.test(hd)); //true
基本使用
没有添加 g
模式修正符时只匹配到第一个,匹配到的信息包含以下数据
变量 | 说明 |
---|---|
0 | 匹配到的完整内容 |
1,2… | 匹配到的原子组 |
index | 原字符串中的位置 |
input | 原字符串 |
groups | 命名分组 |
在match
中使用原子组匹配,会将每个组数据返回到结果中
- 0 为匹配到的完成内容
- 1/2 等 为原子级内容
- index 匹配的开始位置
- input 原始数据
- groups 组别名
重复匹配
基本使用
如果要重复匹配一些内容时我们要使用重复匹配修饰符,包括以下几种。
符号 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
因为正则最小单位是元字符,而我们很少只匹配一个元字符如a、b所以基本上重复匹配在每条正则语句中都是必用到的内容。
默认情况下重复选项对单个字符进行重复匹配,即不是贪婪匹配
let hd = "hdddd";
console.log(hd.match(/hd+/i)); //hddd
使用原子组后则对整个组重复匹配
let hd = "hdddd";
console.log(hd.match(/(hd)+/i)); //hd