一、严格模式
1. 概述
在JS/TS文件的头部或者函数的开始位置加上"use strict"
<script>
"use strict"
text = "严格模式"
console.log(text) // 会报错,报错内容:text is not defined 不能使用未声明过的变量
function ceshi(){
"use strict"
msg = "函数内部严格模式"
console.log(msg) //报错 报错内容:msg is not defined
}
ceshi()
</script>
2. 严格模式特点
1)禁止使用未声明过的变量并进行赋值
2)禁止使用arguments.callee
3)禁止使用 delete 删除变量
4) 禁止重名,包括对象属性和函数参数
5)函数预编译时this默认为undefined,不再指向window
6)对超出权限的操作显示报错,不再做静默失败处理
7)禁止使用八进制数字 ,例如076
8)禁止使用with语句,with(target){}
9)强制为eval创建新作用域,即块级作用域
10)禁止使用保留字作为变量名,如implements, interface, let, package, private, protected, public, static, yield等
3. 严格模式作用
- 消除JavaSript语法的一些不合理,不严谨之处,减少一些怪异的行为
- 消除代码运行的一些不安全之处,为代码的安全运行保驾护航
- 提高编译器效率,增加运行速度
二、数组的扩展
1. Array.isArray()
判断对象是否为数组,返回值为boolean类型
Array.isArray(obj)
2. Array.forEach()
遍历索引数组,为数组每个元素调用一次函数。参数为回调函数(原数组当前元素的值、当前的下标、原数组)
array.forEach((item, index,arr)=>{
... ...
})
3. Array.map()
遍历索引数组,读取原数组中的每个值,可进行修改,会生成一个新数组返回。参数为回调函数(原数组当前元素的值、当前的下标、原数组),返回值为一个新数组。
const newArr = array.map((item, index, arr)=>{
... ...
})
4. Array.filter()
遍历数组元素,将符合条件的元素过滤出来,放到新的数组中返回。参数为回调函数(原数组当前元素的值、当前的下标、原数组),返回值为一个新数组。
const newArr = array.filter((item, index, arr)=>{
... ...
})
5. Array.reduce()
遍历数组,将元素跟储存值进行处理,并返回储存值。参数为回调函数和一个初始值,回调函数有四个参数(储存值、元素值、元素下标、数组),返回值为储存值。
<script>
var arr = [1, 2, 3, 4, 5, 6, 7, 8]
let count = arr.reduce(function (accumulator, Value, Index, array) {
return accumulator + Value;
}, 0) // 把0当做初始值传入
console.log(count)
</script>
6. Array.reduceRight()
类似于reduce(),与reduce不同的是计算顺序从右往左。参数为一个回调函数和一个初始值,回调函数有四个参数(储存值、元素值、元素下标、数组),返回值为储存值。
<script>
var arr = [1, 2, 3, 4, 5, 6, 7, 8]
let count = arr.reduceRight(function (accumulator, Value, Index, array) {
return accumulator + Value;
}, 0) // 把0当做初始值传入
console.log(count)
</script>
7. Array.every()
检查数组中每个元素是否都满足要求,自带循环,每次循环都会调用一次回调函数。参数为回调函数(原数组当前元素的值、当前的下标、原数组),返回值为布尔值,符合要求为true,不符合要求为false。
const res = array.every((item, index, arr)=>{
if(item % 2 === 0){
return item;
}
})
8. Array.some()
检查数组中的元素是否有满足条件的(有一个符合就会返回true)。参数为回调函数(原数组当前元素的值、当前的下标、原数组),返回值为布尔值。
const res = array.some((item, index, arr)=>{
if(item % 2 === 0){
return item;
}
})
9. Array.indexOf()
检索数组中的某个元素值并返回其下标,数组中存在某个元素值会返回该元素值的下标,不存在就会返回-1。参数为元素值(必填)检索的开始下标(选填),如indexOf(1,5)从下标5的位置开始向后查找1。
const index = arr.indexOf('1',3);
10. Array.lastIndexOf()
与 Array.indexOf() 类似,从数组结尾处开始检索,返回指定元素在数组中最后一次出现的位置,如果没有则返回 -1。参数为元素值(必填)检索的开始下标(选填),返回值为指定元素在数组中最后一次出现的位置。
const index = arr.lastIndexOf('1',3);
11. Array.includes()
判断数组中是否包含一个元素。参数为搜索的值和搜索的开始索引(可选),返回true或者false
const demo = [1, NaN, 2, 3] demo.includes(NaN) //true
const demo = [1, NaN, 2, 3] demo.indexOf(NaN) //-1
12. Array.flat()
按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。参数为指定要提取嵌套数组的结构深度,默认值为 1,返回值一个新数组。
可用于二维数组降序
const numbers = [1, 2, [3, 4, [5, 6]]]
console.log(numbers.flat())
// [1, 2, 3, 4, [5, 6]]
console.log(numbers.flat(2))
// [1, 2, 3, 4, 5, 6]
13. Array.flatMap()
首先使用映射函数映射每个元素,然后将结果压缩成一个新数组,两个功能一个是 map,一个是 flat(深度为1)
const new_array = arr.flatMap(
function callback(currentValue[, index[, array]]) {}[, thisArg]
)
const numbers = [1, 2, 3]
numbers.map(x => [x * 2]) // [[2], [4], [6]]
numbers.flatMap(x => [x * 2]) // [2, 4, 6]
14. Array.toSorted
sort方法的复制版本,区别就是sort是修改原数组,而toSorted是返回新数组
15. Array.toReversed
reverse方法的复制版本,区别就是reverse是修改原数组,而toReversed是返回新数组
16. Array.toSpliced
splice是截取原数组的数据,并返回截取出来的数据。toSpliced是对原数组的副本进行操作,然后返回被截取完后的新数组,并不会修改原数组
17. Array.with
不修改原数组,返回整个新数组
const arr = [1, 3, 5, 2, 8];
const newArr = arr.with(1, 10);
console.log("原数组:", arr);
console.log("新数组:", newArr);
三、JSON的扩展
1. 序列化和反序列化
序列化指的是将内存中的对象转化为字节序列,用于持久化到磁盘中或者通过网络传输。对象序列化的最主要的用处就是传递和保存对象,保证对象的完整性和可传递性。序列化后的字节流保存了对象的状态以及相关的描述信息,其核心作用就是对象状态的保存与重建。
反序列化指的是从字节序列创建对象的过程称为反序列化。从文件中或网络上获得序列化的字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
2. JSON.stringify(obj)和JSON.parse(JSstr)
JSON.stringify(obj)可以将将数组、对象转化为JSON字符串。
JSON.parse(JSstr)可以将字符串转化为对象,参数为字符串和可选的回调函数,其中函数有两个参数key转换为对象的属性名、value转换为对象的属性值。
<script>
var obj = { "name": "Bill", "age": 62, "city": "Seatle" };
var JSstr = JSON.stringify(obj);
let JSpar = JSON.parse(JSstr)
console.log(JSpar)
JSpar = JSON.parse(JSstr, function (key, value) {
console.log(key, value)
return value + "!"
})
</script>
四、字符串的扩展
1. String.trim()
删除字符串两端的空白字符,不会删除字符串中间的空格,该方法并不影响原字符串本身,会返回一个新的字符串。
const str = ' 123 '.trim();
2. String.trimStart()
从字符串的开头删除空格,trimLeft()是此方法的别名
3. String.trimEnd()
从字符串的结尾删除空格,trimRight()是此方法的别名
4. String.padStart()
把指定字符串填充到字符串头部,返回新字符串
// targetLength:目标字符串保证的长度
// padString:填充字符
str.padStart(targetLength [, padString])
const str = 'randy'
console.log(str.padStart(8, 'x')) // xxxrandy
// 数字替换,比如手机号,身份证号
const tel = '13012345678'
const newTel = tel.slice(-4).padStart(tel.length, '*')
console.log(newTel) // *******5678
5. String.padEnd()
用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定长度的字符串。从当前字符串的末尾(右侧)开始填充
6. String.matchAll()
返回一个包含所有匹配正则表达式及分组捕获结果的迭代器,参数为正则表达式对象,返回值一个迭代器
- 如果所传参数不是一个正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为一个 RegExp
- 返回迭代器不可重复使用,可再次调用方法,获取一个新的迭代器
function selectDiv(regExp, str) {
let matches = [];
for (let match of str.matchAll(regExp)) {
console.log(match);
matches.push(match[1]);
}
return matches;
}
const res = selectDiv(/<div>(.*)</div>/g, str);
console.log(res); // ['第一个div', '第二个div']
7. String.replaceAll()
replace() 方法仅替换一个字符串中某模式 pattern 的首个实例,replaceAll() 会返回一个新字符串,该字符串中用一个替换项替换了原字符串中所有匹配了某模式的部分。replaceAll() 相当于增强了 replace() 的特性,全量替换
const str1 = "hello word";
console.log(str1.replace("o", "哦")); // hell哦 word
console.log(str1.replaceAll("o", "哦")); // hell哦 w哦rd
五、对象的扩展
1. Object.defineProperty()
定义新属性或修改原有的属性,限制属性是否可以被枚举、修改、删除。
参数:obj(必需)目标对象;prop(必需)需定义或修改的属性;descriptor(必需)目标属性所拥有的特性
- value:设置属性的值,默认为underfined
- enumerable:属性是否可以被枚举 默认为false
- writable:值是否可以重写 默认为false
- configurable:属性是否可以被删除或是否可以再次修改配置项 默认为false
- get:读取时内部调用的函数
- set:写入时内部调用的函数
<script>
var obj = { name: 'XiaoMing', sex: '男' }
Object.defineProperty(obj, "name", {
configurable: false, //设置之后,name属性就不能删除了
})
delete obj.name;
console.log(obj); //{name: 'XiaoMing', sex: '男'}
Object.defineProperty(obj, "age", {
writable: false, //设置age只读,无法修改
value: 18, //设置obj.age = 18
})
obj.age = 20;
console.log(obj.age); //18
Object.defineProperty(obj, "age", {
enumerable: false //设置不能被枚举,无法通过obj.age获取打印
})
for (var i in obj) {
console.log(i + "的值是" + obj[i]); //通过循环获取obj能枚举的属性,打印
}
</script>
2. Object.create
Object.create(proto,[ propertiesObject ])
将现有对象作为原型,创建新对象。
参数为proto新对象的原型,可以是null。propertiesObject可选参数,指定要添加到新对象的属性描述符,以及相应的属性名称,这些属性的第二个参数对应于Object.defineProperties()对象属性的作用。返回值是具有指定原型对象和属性的新对象。
// obj 继承了属性name 和 age
var obj = Object.create({name: 'johan', age: 23});
// obj2 不继承任何属性和方法
var obj2 = Object.create(null);
// 与 {} 和 new Object() 一个意思,继承了Object
var obj3 = Object.create(Object.prototype);
// 第二个参数与 Object.defineProperties() 一致
var obj4 = Object.create({}, {property1: {value: true,writable: true}});
3. Object.getOwnPropertyDescriptors()
获取对象所有属性的描述符
value [属性的值]writable [属性的值是否可被改变]enumerable [属性的值是否可被枚举]configurable [描述符本身是否可被修改,属性是否可被删除]
console.log(Object.getOwnPropertyDescriptor(data, 'Lima'))
{
value: "58/40",
writable: true,
enumerable: false,
configurable: true
}
4. Object Rest & Spread
const output = { ...input, c: 3 }
let { a, ...rest } = input
5. Object.fromEntries()
把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的
Object.fromEntries([ ['foo', 1],
['bar', 2]
]) // {foo: 1, bar: 2}
6. Object.hasOwn()
判断对象是否包含某和属性,如果这个对象本身就有这个属性的话,这个函数就会返回true,否则就返回false。hasOwnProperty()方法是Object原型上的方法,可以被覆盖,Object.create(null)对象获取不到hasOwnProperty()方法。
六、原型的扩展
1. 对象的可拓展性
原型.isPrototypeOf(实例)
判断原型对象是否是参数实例对象的原型,会查找整个原型链,即原型的原型也是实例化对象的原型
setPrototypeOf(实例,prototype)
设置某个实例对象的原型,参数是obj实例化对象,prototype 给实例化对象设置的新原型对象(可以是null,也可以是一个对象)
getPrototypeOf(实例)
获取对象的原型对象,参数是实例化对象
2. 取消对象可拓展性
preventExtensions(obj)
取消对象的可拓展性,对象不能再增加新的属性,但是可以修改和删除原有的属性
isExtensible(obj)
判断对象是否具有可拓展性,返回值为布尔值,true代表对象可以拓展属性,false即对象不可拓展属性
3. 封闭对象
seal(obj)
封闭对象的属性,不能拓展和删除属性,但是可以修改属性
isSealed(obj)
判断对象属性是否被封闭,返回值为布尔值,true代表对象被封闭,false代表对象没有被封闭
4. 冻结对象
freeze(obj)
冻结对象的属性,不能拓展、修改和删除属性
isFrozen(obj)
判断对象属性是否被冻结,返回值为布尔值,true代表对象被冻结,false代表对象没有被冻结
七、拷贝
1. 赋值拷贝
- 基本数据类型的赋值拷贝相互之间不会有影响
- 引用数据类型的赋值拷贝是地址引用,即两个变量指向堆内存中的同一个地址,所以相互之间就会有影响
2. 浅拷贝
浅拷贝只拷贝对象的第一层属性 如果对象属性是基本数据类型,拷贝的就是基本数据类型的值; 如果对象属性是引用数据类型,拷贝的就是引用数据类型的内存地址
1)浅拷贝方法
- Object.assign()
- 扩展运算符{...obj}、[...arr]
- lodash库clone()
2)基于浅拷贝实现的方法
- Array.slice()
- Array.from()
3. 深拷贝
深拷贝是从内存中完整的拷贝一份出来,在堆内存中开辟一个新的内存空间存储拷贝值,新对象与原对象完全独立,修改新对象不会影响原对象
JSON.parse(JSON.stringfy(obj))- lodash库
deepClone() - js内置函数
structuredClone
1)JSON.parse(JSON.stringfy(obj))缺点
- 对象中有时间类型,序列化之后会变成字符串类型
- 对象中有undefined和function类型,序列化之后会丢失
- 对象中有NaN,infinity,-infinity数据,序列化之后会显示null
- 对象中有循环引用时,会直接报错
2)structuredClone函数
const calendarEvent = {
title: "Builder.io Conf",
date: new Date(123),
attendees: ["Steve"]
}
const copied = structuredClone(calendarEvent);
console.log(copied.attendees === calendarEvent.attendees); // false
优点:
- 主流浏览器支持程度很好
- 克隆无限嵌套的对象和数组
- 克隆循环引用
- 克隆各种 JavaScript 类型,如
Date、Set、Map、Error、RegExp、ArrayBuffer、Blob、File、ImageData等 - 转移任何可转移对象
缺点:
- 不能克隆函数
- 不能克隆DOM元素
- 不能遍历原型链
八、Math的扩展
1. 幂运算符**
等同于Math.pow(base,exponent) 函数
console.log(2 ** 10) // 1024
2. BigInt
表示一个任意精度的整数,可以表示超长数据,可以超出2的53次方
const bigInt = 9007199254740993n
const bigIntNum = BigInt(9007199254740993)
3. 空值合并运算符
空值合并运算符 ?? 是一个逻辑运算符。当左侧操作数为 null 或 undefined 时,其返回右侧的操作数。否则返回左侧的操作数
4. &&=
let num1 = 1;
let num2 = 2;
num1 &&= num2;
console.log(num1); // 2
let num1 = 0;
let num2 = 2;
num1 &&= num2;
console.log(num1); // 0
5. ||=
let num3 = 3;
let num4 = 4;
num3 ||= num4;
console.log(num1); // 3
let num3 = 0;
let num4 = 4;
num3 ||= num4;
console.log(num3); // 4
6. ??=
只有在左边的值严格等于 null 或 undefined 时起作用进行赋值
let num5 = 0;
let num6 = null;
let num7 = undefined;
num5 ??= 10;
console.log(num5); // 0
num6 ??= 10;
console.log(num6); // 10
num7 ??= 10;
console.log(num7); // 10
九、Function的扩展
1. 尾逗号优化
允许函数的最后一个参数后面有逗号
function clownsEverywhere(
param1,
param2,
) {
/* ... */
}
clownsEverywhere(
'foo',
'bar',
)
十、RegExp的扩展
支持返回开始和结束索引:给正则表达式添加一个d的标记来让它在匹配的时候给我们既返回匹配到的子字符串的起始位置还返回其结束位置
const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
/**
[
'and',
index: 4,
input: 'sun and moon',
groups: undefined,
indices: [ [ 4, 7 ], groups: undefined ]
]
*/
console.log(matchObj);