let、const基本使用
- var允许重复声明变量;let、const不允许重复声明变量
- var声明的变量是会有作用域提升;使用let、const声明的变量,在声明之前访问会报错
- let、const定义的标识符真正执行到声明的代码之前,是不能被访问的,存在暂时性死区
- let、const没有作用域提升,但是会在解析阶段被创建出来
- 全局通过var来声明一个变量,会在window上添加一个属性;let、const不会给 window 添加属性
- var没有块级作用域;通过let、const、function、class声明的标识符是具备块级作用域的限制的
- 函数有块级作用域,外面依然可以访问:因为引擎会对函数声明进行特殊处理,允许像var进行提升
let message2 = '你好啊'
message2 = '你好啊 大哥'
console.log(message2); // 你好啊 大哥
// 示保存的数据一旦被赋值,就不能被修改
const message3 = '香菜'
message3 = '喜欢吃'
console.log(message3); // Uncaught TypeError: Assignment to constant variable
// 如果赋值的是引用类型,可以通过引用找到对应的对象,修改对象的内容
const info = {
name:'www',
age:10
}
info.name = 'wqq'
console.log(info); // {name: 'wqq', age: 10}
模板字符串
// 基本用法
const name = 'www'
console.log(`我叫${name}`) // 我叫www
function bar() {
return '香菜'
}
console.log(`我爱吃${bar()}`) // 我爱吃香菜
// 标签模板字符串的用法(React的styled-components库里用)
const age = 19
function foo(...args) {
console.log('参数:',args);
}
foo`hello${name}, age is${age}` // [Array(3), 'www', 19]
函数默认值
有默认参数的形参,尽量放在最后面,且不会计算在length之内(后面所有的形参都不会计算在内)
剩余参数放在最后
/* 默认值写法:
1. n1 = n1 ? n1 : '默认值'
2. n1 = n1 || '默认值'
3. n1 = (n1 === undefined || n1 === null) ? '默认值' : n1
4. n1 = n1 ?? '默认值'
*/
function foo(n1 = 10, n2 = 20) {
console.log(n1 + n2);
}
foo(10, 20)
// 默认参数解构
function foo1(obj={name:'ww',age:20}) {
console.log(obj.name, obj.age);
}
function foo2({name,age} = {name:'ww',age:20}) {
console.log(name, age);
}
function foo3({name = 'qq', age = '20'} = {}) {
console.log(name, age);
}
foo()
展开语法
const obj ={
name:'ww',
age:10
}
// 在构建字面量的时候,可以使用展开运算符
const info = {
...obj,
height:1.99
}
function foo(name, age, ...arg) {
console.log(name, age, ...arg);
}
const obj = {
name: 'ww',
height: 1.22
}
// 可迭代对象:数组,字符串,argument
foo(...obj) // 对象默认不是可迭代的,不可以这样使用
浅拷贝深拷贝
浅拷贝-原始类型:赋值引用,修改info1的值,obj的值也会改掉
浅拷贝-复杂类型,只会拷贝第一层数据
深拷贝-完全生成一个新的对象
深拷贝实现方案:第三方库、自己实现、间接利用js机制(拷贝不了函数)
const obj3 = JSON.parse(JSON.stringify(obj)) // 会完全创建一个新的对象
数字过长时可以用 _ 连接
const num = 1000_000_000
Symbol的基本使用
Symbo()用来生成一个独一无二的值
对象的属性名都是字符串形式,那么很容易造成属性名的冲突
在ES6中,对象的 key 可以使用字符串或者 Symbol值
用法
function baz(obj) {
const key = Symbol()
obj[key] = function () {} // 不会覆盖obj本身的key
delete obj[key]
}
写法
// 写法一:字面量直接赋值
const s1 = Symbol()
const obj = {
[s1]:'aaa'
}
// 写法二:属性名赋值
const s2 = Symbol()
obj[s2] = 'bbb'
// 写法三: Object.defineProperty
Object.defineProperty(obj,s1,{
value:'ddd'
})
获取Symbol对应的key,使用getOwnPropertySymbols方法
const keys = Object.getOwnPropertySymbols(obj)
for (const key of keys){
console.log(obj[key]);
}
拿到Symbol描述,description
const s3 = Symbol('ccc')
console.log(s3.description) // 可以拿到描述'ccc'
const s4 = Symbol(s3.description)
console.log(s3 === s4); // false
const s5 = Symbol.for(s3.description)
console.log(s4 === s5); // false
// 如果相同的key(s3.description), Symbol.for可以生成相同的Symbol值(了解)
const s6 = Symbol.for(s3.description)
console.log(s5 === s6); // ture
// 获取传入的key
console.log(Symbol.keyFor(s5)) // ccc
Set的基本使用
可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复
// 创建Set
const set = new Set()
// 添加元素
set.add(10)
set.add(13)
set.add(14)
set.add(14)
const info = {}
set.add(info)
set.add(info)
console.log(set); // { 10, 13, 14, {...} }
// set常见的属性和方法
console.log(set.size); // 获取元素个数: 3
console.log(set.delete(14)); // 10 13
console.log(set.has(10)); //是否存在某个元素:true
set.forEach(item => console.log(item)) // 10 13
// set 支持for...of
for( const item of set) {
console.log(item);
}
set.clear() // 清空set中所有的元素,没有返回值
应用场景(数组去重)
const name = ['aa','bb','cc','aa']
// 方式一:
const newArr = []
for (const key of name){
// 判断新数组是否包含key
if(!newArr.includes(key)) {
newArr.push(key) // 没有就push进新数组
}
}
console.log(newArr); // ['aa', 'bb', 'cc']
// 方式二:
const newArr2 = Array.from(new Set(name))
console.log(newArr2); // ['aa', 'bb', 'cc']
WeakSet使用
Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构
WeakSet中只能存放对象类型
WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,GC可以对该对象进行回收
WeakSet 不能遍历
- WeakSet常见的方法:
add(value):添加某个元素,返回WeakSet对象本身
delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型
has(value):判断WeakSet中是否存在某个元素,返回boolean类型
- WeakSet的案例
const pWeakSet = new WeakSet()
class Person {
constructor() {
pWeakSet.add(this)
}
running(){
if(!pWeakSet.has(this)){
console.log('type error');
return
}
console.log('running');
}
}
const p = new Person() // p = null的时候,就会进行销毁
p.running()
Map的基本使用
size:返回Map中元素的个数set(key, value):在Map中添加key、value,并且返回整个Map对象get(key):根据key获取Map中的valuehas(key):判断是否包括某一个key,返回Boolean类型delete(key):根据key删除一个键值对,返回Boolean类型clear():清空所有的元素forEach():拿到的是valuefor of进行遍历,将key,value组成数组返回
WeakMap的使用
对象的局限性:不可以使用复杂类型作为key
WeakMap的key只能使用对象,不接受其他的类型作为key
WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象
- WeakMap常见的方法:
set(key, value):在Map中添加key、value,并且返回整个Map对象;
get(key):根据key获取Map中的value;
has(key):判断是否包括某一个key,返回Boolean类型;
delete(key):根据key删除一个键值对,返回Boolean类型;
应用
对象相关的属性
Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组
const obj = {
name: 'www',
age: 19,
address: '成都'
}
// 获取所有的key
console.log(Object.keys(obj)); // ['name', 'age', 'address']
// 获取所有的value
console.log(Object.values(obj)); // ['www', 19, '成都']
// 对对象的操作
const entries = Object.entries(obj)
console.log(entries);
for (const entry of entries){
const [key,value] = entry
console.log(key, value);
}
// 对数组、字符串的操作
console.log(Object.entries(['abc', 'cda']));
console.log(Object.entries('hello'));
padStart 和 padEnd(字符串的首尾)
padStart 和 padEnd 方法,分别是对字符串的首尾进行填充的
// 对时间进行格式化
const minute = '15'.padStart(2,'0')
const second = '8'.padStart(2,'0')
console.log(`${minute}:${second}`) // 15:08 字符串的首尾
// 对数据格式化
let carNumber = '277382933281923339'
const sliceNumber = carNumber.slice(-4) // 3339
carNumber = sliceNumber.padStart(carNumber.length,'*')
console.log(carNumber); // **************3339
将当前字符串从末尾开始填充给定的字符串
const str1 = 'hello';
console.log(str1.padEnd(10, '.')); // hello.....
flat 和 flatMap
flat() 将多维数组扁平化
// flat的使用
const num = [12,435,[231],[13,23,[14,546]]]
console.log(num.flat(1)); // [12, 435, 231, 13, 23, Array(2)]
console.log(num.flat(2)); // [12, 435, 231, 13, 23, 14, 546]
const message = [
'hello wqq',
'你好啊 gg'
]
// for循环的方式:
const newInfo = []
for (const item of message) {
const infos = item.split(' ')
for (const info of infos) {
newInfo.push(info)
}
}
console.log(newInfo); // ['hello', 'wqq', '你好啊', 'gg']
// 先进性map,在进行flat
const newMeg = message.map(item => item.split(' ')) // [Array(5), Array(3)]
const finalMeg = newMeg.flat(1) // // ['hello', 'wqq', '你好啊', 'gg']
// flatMap的使用
const newMessage = message.flatMap(item => item.split(''))
console.log(newMessage); // ['hello', 'wqq', '你好啊', 'gg']
trimStart 和 trimEnd(去除首尾空格)
const message = ' hello wqq '
console.log(message.trim()); //hello wqq
console.log(message.trimStart()); //hello wqq
console.log(message.trimEnd()); // hello wqq
BigInt
const maxNum = Number.MAX_SAFE_INTEGER
console.log(maxNum); // 9007199254740991 安全的最大正整数
// BitInt的表示方法是在数值的后面加上n
const bigInt = 9007199254740991n
console.log(bigInt + 1n); // 9007199254740992n
空值合并运算符 ??
逻辑或 || 操作符在左侧操作数为假值时返回默认值,左侧为 0 或空字符串都会返回默认值
?? 操作符在左侧值为undefined和null就返回默认值
let info = ''
info1 = info || '默认值' // 默认值
info2 = info ?? '默认值' // ''
可选链 ?.
const obj = {
name: 'www',
friend: {
name:'qqq',
running(){
console.log('running');
}
}
}
if(obj.friend && obj.friend.running) {
obj.friend.running()
}
// 可选链
obj?.friend?.running?.()
replaceAll(字符串替换)
const message = 'hello www'
const newMeg = message.replaceAll('www','qqq')
console.log(newMeg); // hello qqq
at方法
const nums = ['aaa','bbb','ccc']
const str = 'hello wq'
console.log(nums.at(1)); // bbb
console.log(nums.at(-1)); // ccc
console.log(str.at(1)); // e
console.log(str.at(-1)); // q
hasOwn
用于判断一个对象中是否有某个自己的属性
- 防止对象内部有重写hasOwnProperty
- 对于隐式原型指向null的对象, hasOwnProperty无法进行判断
let info = {
name: 'www',
age:10,
__proto__:{
address:'成都'
}
}
console.log(Object.hasOwn(info, 'name')); // true
console.log(Object.hasOwn(info, 'address')); // false
定义class类中成员字段
class Person {
// 对象属性(公共)
height = 1.66
// 约定的私有属性
_intro = 'hello www'
// es13私有属性
#intro = 'message'
// 类属性(公共)
static totalCount = '70'
// 类属性(私有)
static #maleCount = '20'
constructor(name, age) {
this.name = name
this.age = age
this.address = '成都'
}
// 静态代码块
static {
console.log('吃香菜'); // 进行初始化操作
}
}
const p = new Person('www',19)
console.log(p.height); // 1.66