let name = "zhangcheng"
//我想让sum作为obj的key值
let objKey = "sum"
let obj = {
//属性名的简写
name//等同于name:name
//方法的简写
running(){}//等同于running:function(){}
//计算属性名
[objKey]:456//打印出来就是sum:456
}
ES6中引入了解构的用法
//不要在意变量名字是否重复
let arr = ["abc","asd","ewf"]
//基本用法
let [name1,name2,name3] = arr//就会按照顺序打印出来
//顺序问题:数组解构有严格的顺序问题
let [name1,,name3] = arr //"abc","ewf",只想获取间隔的位置时候,中间需要空出来
//解构出数组
let [name,...newName] = arr //"abc",[asd,"ewf"],用...接收剩余的值,就会装入数组中
//解构默认值
let [name1 = "defaults",name2] = arr//若arr[0]的值为undefined时候,name1就是defaults,否则就是arr[0]的值
let obj = {
name: "zhangcheng",
age: 18,
height: 188,
};
//基本用法
let { name, age, height } = obj;
console.log(name, age, height);
//顺序问题:对象的解构是没有顺序问题的,是根据对象的key进行解构的
let { age, name, height } = obj;
console.log(name, age, height);
//对变量进行重命名 原本的key:重命名的变量名
let { age: newAge, name: newName } = obj;
console.log(newAge, newName);
//默认值:若该属性为undefined,则使用默认值
let { age, name, address = "默认值" } = obj;
console.log(age, name, address);
//利用...接收剩余参数:会将剩余参数放到对象中去
let { name, ...arg } = obj;
console.log(name, arg);
//在sum这里,我们就可以用解构接收参数
function sum({a,b}){}
sum({a:100,b:200})
//或者接收返回值的时候,用解构
let {data} = await request()
在先前的文章 重学JavaScript高级(三):深入JavaScript运行原理中提到过,只不过是ES5的执行描述
在ES6中,有些执行描述进行了改变,但是思路是一样的(执行上下文和执行上下文栈没有变化)
词法环境(Lexical Environments)—由执行上下文关联,相当于替代了VO对象
环境记录(Environment Record)
const obj = {
a:100
}
obj = {}//这样是不被允许的
obj.a = 200//这样是可以的
//可以在定义之前访问,就是作用域提升
console.log(message)
var message = "zhangcheng"
function foo(){
console.log(123)
console.log(4456)
//以上就是暂时性死区
let a = 100
//虽然在这里提前访问b,但是代码执行却是在给b赋值之后
console.log(b)
}
let b = 200
foo()
块指的就是代码块
在ES5之前只有 全局作用域以及函数作用域
但是在ES6之后,let /const/class/function都会形成块级作用域
foo()//这样是没办法访问的
{
var message = "hello";
let a = "123"//const/class同理
//但是函数不同
function foo(){
consloe.log(456)
}
}
foo()//可以在块级作用域外访问(需要在定义之后)
console.log(a)//不能访问,因为形成了块级作用域
console.log(message)//可以访问var定义的,因为var没有形成块级作用域
var message = "hello"
let address = "河北"
{
var height = 1.88
let title = "学生"
}
//在执行代码块的时候,会形成新的词法环境,相对应的环境记录中会存放let声明的变量
//现在有多个按钮
//先前使用var定义的i,没有形成块级作用域,所以在打印i的时候,都是全局作用域中的
//我们可以换成let,会形成块级作用域,在每次执行的时候,都会生成新的词法环境,同时会有对应的环境记录,保存每次i的值
//for循环多少次,就相当于创建了多少个词法环境,每个环境记录都记录着不同的i和不同的function
const btnEls = document.querySelectorAll("button")
for(var i = 0;i < btnEls.length; i++){
let btnEl = btnEls[i]
btnEl.onclick = function(){
console.log(`点击了第${i}个按钮`)
}
}
let a = `aaa`//模板字符串
let b = `my functon ${foo()}`//${}中包含的是js表达式、变量等
let name = "zhangcheng";
let age = 18;
function foo(...arg) {
console.log(arg);
}
foo`my name is ${name},i am ${age}`;//[ [ 'my name is ', ',i am ', '' ], 'zhangcheng', 18 ]
function foo(name = "zhangcheng ") {}
function foo({ name = "zhangcheng" } = {}) {
console.log(name);
}
let obj = {
name: "zhangsan",
};
foo(obj);
function foo(name,age = 18,...args){
}
let bar = ()=>{
}
new bar()//是错误的
let arr = [1,2,3,4]
let str = "hello"
let obj = {
a:100
}
function foo(...arg){
console.log(arg)
}
//对数组进行展开
let arr1 = [...arr,5,6]
//对字符串进行展开
foo(...str)
//创建字面量时候,将对象展开
let obj2 = {
...obj,
c:200
}
console.log(100)
console.log(0b100)//2进制
console.log(0o100)//8进制
console.log(0x100)//16进制
let money = 1_0000//一万
let s1 = Symbol();
let obj = {
[s1]: 100,
};
console.log(obj[s1]);
let s1 = Symbol();
let s2 = Symbol();
let obj = {
[s1]: 100,
[s2]: 200,
a: 100,
};
console.log(Object.keys(obj)); //只能获取普通的key
console.log(Object.getOwnPropertySymbols(obj)); //只能获取Symbol的key
let s1 = Symbol("aaa")//添加一个description
s1.description//aaa获取
let s1 = Symbol.for("sss")
let s2 = Symbol.for("sss")
s1 == s2
let arr = [1, 2, 1, 2, 3];
let newArrSet = new Set(arr);
console.log(newArrSet);//[1,2,3]
let arr = [1, 2, 1, 2, 3];
let newArrSet = new Set(arr);
let newArr = Array.from(newArrSet)
//属性size:返回Set中元素的个数
console.log(newArrSet.size);
//常用方法
//add(value)添加某个元素,返回Set本身
newArrSet = newArrSet.add(4);
//delete(value):删除和这个值相等的元素,返回boolean
let isDelete = newArrSet.delete(4);
//has(value):判断是否存在与value值相等的元素,返回boolean
let isHas = newArrSet.has(3);
//clear:清空set,没有返回值
newArrSet.clear();
//forEach():遍历set
newArrSet.forEach((item) => console.log(item));
//支持用for..of进行遍历
for (const item of newArrSet) {
console.log(item)
}
因此WeakSet就是弱引用类型,其指向的对象,有可能会被GC回收
拥有add(value)/delete(value)/has(value)
等方法
与 Set的区别
forEach
进行遍历const wset = new WeakSet()
wset.add({a:100})
用于存储映射关系
对象也可以存储映射关系,那么他们之间有什么区别
常用属性和方法
let obj1 = { a: 100 };
let obj2 = { b: 200 };
let newMap = new Map();
newMap.set(obj1, "abc");
newMap.set(obj2, "abc");
//size:返回map中元素个数
console.log(newMap.size);
//set(key,value)添加key value,返回整个map
newMap.set({ c: 100 }, "cba");
//get(key)获取key对应的value
console.log(newMap.get(obj1));
//has(key)查找是否包含key值对应的value
newMap.has(obj1);
//delete(key)删除key对应的元素
newMap.delete(obj1);
//clear()清空元素
newMap.clear();
//forEach遍历:item打印的是对应的value
newMap.forEach((item) => console.log(item));
//可以使用for of 遍历
for (const item of newMap) {
console.log(item); //[key,value],会将key和value装入一个数组
}
//至少两位,不足两位在头部补充0
let str = "5".padStart(2, "0");
console.log(str);//05
let str = "1306261558515255";
let newStr = str.slice(-4).padStart(str.length, "*");
console.log(newStr);
function foo(num1,num2,){
//
}
Object.getOwnPropertyDescriptors
获取属性描述符Async Function
后续文章let arr = [100, [100, 200], [[300, 400]]];
let newArr1 = arr.flat(1);
let newArr2 = arr.flat(2);
console.log(newArr1);//[ 100, 100, 200, [ 300, 400 ] ]
console.log(newArr2);//[ 100, 100, 200, 300, 400 ]
//现在有多个字符串,需要先将字符串按照空格分隔,而后装入一个数组中
let arr = ["hello world", "nihao hahah"];
let newArr = arr.flatMap((item) => item.split(" "));
console.log(newArr);//[ 'hello', 'world', 'nihao', 'hahah' ]
基本用法
Object.entries
(静态方法返回一个数组)
Object.fromEntries
(静态方法将键值对列表转换为一个对象)
let obj = {
a: 100,
b: 200,
};
console.log(Object.entries(obj)); //[ [ 'a', 100 ], [ 'b', 200 ] ]
let arr = [
["a", 100],
["b", 200],
];
console.log(Object.fromEntries(arr));
let str = " aaa "
str.trim()//去除首尾空格
str.trimStart()//去除头部空格
str.trimEnd()//去除尾部空格
let num = 189156198165165616n
info = info ?? "默认值"
//当info为null的时候,使用null
//当info为“” 0 undefined false的时候用默认值
//
let obj = {
a: 100,
b: {
c: function () {
console.log("zhangcheng");
},
},
};
obj?.b?.c?.();
let obj = {
a: 100,
};
//FinalizationRegistry是一个类,回调函数可以接收参数
const registry = new FinalizationRegistry((value) => {
console.log(`对象${value}被销毁了`);
});
//register这是实例方法,第一个参数是监听对象,第二个参数是描述
registry.register(obj, "zhangcheng");
obj = null;
let obj = {
a:100
}
let weakRefObj = new WeakRef(obj)
//实例方法
//返回当前实例的 WeakRef 对象所绑定的 target 对象,如果该 target 对象已被 GC 回收则返回undefined
let a = weakRefObj.deref()
let b = b + 100
//我们可以写成以下形式
b+= 100
function foo(value) {
//通常我们会对value是否有值进行判断
value = value || "默认值";
//我们现在可以简写成这样
value ||= "默认值";
//我们知道||运算符,有缺陷,若传进来的是“” 0 false会当作有值的
//此运算符,只有value为null的时候
value ??= "默认值";
}
foo(0);
let str = "aaaa";
let newStr = str.replace("a", "b");
let newStr1 = str.replaceAll("a", "b");
console.log(newStr);//baaa
console.log(newStr1);//bbbb
let obj = { a: 100 };
obj.__proto__ = { b: 200 };
console.log(obj.hasOwnProperty("a")); //true
//因为b是在隐式原型上面的,所以返回false
console.log(obj.hasOwnProperty("b")); //false
//第一个参数传递对象,第二个参数传递要查找的属性
console.log(Object.hasOwn(obj, "a")); //true
console.log(Object.hasOwn(obj, "b")); //false
通过以上代码我们可以看出以下区别
1.hasOwn
是一个静态方法:通过 Object.hasOwn
进行调用
hasOwnProperty
是一个实例方法,需要创建出来的对象进行调用
2.防止创建出来的对象中,有 hasOwnProperty
属性,对内置的进行修改
3.接下来看一个例子,就能明白 hasOwnProperty
的局限性
const obj = Object.create(null);
obj.a = 100;
//因为现在obj指向了null,obj本身没有hasOwnProperty方法,而null中也没有,所以会报错
//而之前的代码可以用,是因为obj指向的是Object_prototype,Object原型对象中有hasOwnProperty该方法可以调用
console.log(obj.hasOwnProperty("a"));
//而这个是直接调用静态方法,因此无论对象的隐式原型指向什么地方,都能使用该方法
console.log(Object.hasOwn(obj, "a"));
class Person {
//对象属性:public
height = 1.88;
//对象属性:private,程序员之间的约定
_intro = "";
//真正的私有属性.只能在clas类中访问,不能被实例访问
#intro1 = "123";
//类属性:public
static intro2 = "70";
//私有类属性:外界不能访问
static #intro3 = "70";
constructor(name) {
this.name = name;
}
//静态代码块:只会执行一次,用于对class进行初始化
static {
console.log("hello");
}
}