ECMAScript 6 (二)

ECMAScript 6 (二)

面向对象的扩展

不可扩展

一级保护,不可扩展

我们之前在创建的时候,因为JS是一个弱语言,所以对象在创建好之后,任然可以二次添加删除修改属性

同时在ES6里面,虽然推出了const,但是const锁栈不锁堆,所以对于对象的保护任然欠缺,这个时候ES6推出了新的技术用于保护对象

const obj = {userName:"张三"
}
obj.age = 20;
obj.userName = "李四"

如果我们希望一个对象构建好之后,不再去添加新的属性和方法,我们就需要把这个对象设置成一个一级保护对象:不可扩展对象

const obj = {userName:"张三"
}
Object.preventExtensions(obj);obj.age = 20   //这个时候age是无法添加上去的
密封

二级保护:不可扩展,不可删除

const obj = {userName:"张三",sex:"男"
}
Object.seal(obj);
obj.age = 20;     //无法新增
delete obj.sex;   //false
冻结

三级保护:不可扩展,可能删除、不能修改,把堆锁死

let obj = {userName:"张三",sex:"男"
}
let obj1 = {aa:1
}Object.freeze(obj);
obj.age = 20;
delete obj.sex;
obj.userName = "李四"obj = obj1
obj.aa = 2;

说明:

冻结可以锁堆,但是不能锁栈,所以如果想堆栈全锁,可以使用const声明

Object.is()

之前我们在运算符当中,我们学习过完全等于运算符,Object.is()则比完全等于运算符还要严格,它主要是用于对象的判断,它判断的是内存

let obj1 = {userName:"张三"
}
let obj2 = obj1;    //浅拷贝,栈里面的地址是相同的
let obj3 = {userName:"张三"
}console.log(Object.is(obj1,obj2));  //true
console.log(Object.is(obj1,obj3));  //false

指数运算符

求一个数的多少次方可以使用指数运算,运算符使用 **

let num  = 3 ** 5

大整数数据类型BigInt

JS中所有的数值都是number类型,而number类型是不分浮点和整数,但是范围有限,所以JS在进行数值很大的运算的时候会容易溢出

let num1 = 2 ** 513
let num2 = 2 ** 513 + 1
console.log(num1 == num2);  //true

结果比较是个true,这是不对的,因为这个数值已经超过JS的最大处理范围,它计算不过来

所以ES6为了解决这个问题,推出了BigInt

let num3 = 2n;let num4 = 0.5n;   //报错

现在再去运算上面的例子

let num1 = 2n ** 513n
let num2 = 2n ** 513n + 1n
console.log(num1 == num2);   //false

注意:

bigInt不能和Number混合运算

Bigint数据类型转换

使用BigInt()方法可以将其他类型的数据进行bigint类型的转换,但是并不是所有情况下的值都可以被转换

Symbol数据类型

它叫标识类型,页叫做全局唯一标识符

let s1 = Symbol();
let s2 = Symbol();console.log(s1 == s2);

Symbol是通过调用Symbol方法得到的,每次结果都不一样,它是全局唯一的

let s1 = Symbol.for("张三");
let s2 = Symbol.for("张三");console.log(s1 == s2);  //true

这里有个情况注意下

let s3 = Symbol("张三");
let s4 = Symbol("张三");console.log(s3 == s4);   //false

分析:

1、for方法我们可以理解成从张三的身上拿去一个标识符,那么就意味张三身上应该事前有标识符在的,而且是唯一的,所以不管是s1还是s2,从张三身上拿到的都是一样的标识符

2、s3和s4就不太一样,它们没有使用for,所以我们认为这个过程是先获取了一个标识符然后再贴给张三,所以s3和s4不一样

Symbol应用点

Symbol是具备唯一性,不会重复,所以当某些东西不能重复的时候,我们会使用它,再对象里面,属性名是不能重复的,如果重复了,则后面的属性会覆盖掉前面的属性值

obj = {userName:"张三",age:18,userName:"李四"
}

现在李四会把张三覆盖掉,但是我们想两个属性值都留下来,怎么办?

obj = {[Symbol("userName")]:"张三",age:18,[Symbol("userName")]:"李四"
}

上面的代码,对象内有两个相同的属性名,为了把相同的属性名对应的属性值都保留下来,我们可以使用Symbol,但是实际开发中,我们不会像上面 这样写

实际上我们再有多个对象的时候,我们可能会合并对象,那么这个时候某些属性不需要被合并掉,怎么办?

let obj1 = {[Symbol("userName")]:"张三",age:18
}
let obj2 = {[Symbol("userName")]:"李四",sex:"女"
}let obj3 = {...obj1,...obj2
}
Symbol做属性名

Symbol最大的应用点就是做属性名,之前我们学习过遍历对象

1、for…in

2、Object.keys()

3、Object.getOwnPropertyNames()

这几种遍历对象的时候,如果属性名是Symbol 是得不到

let obj1 = {[Symbol("userName")]:"张三",age:18
}
let obj2 = {[Symbol("userName")]:"李四",sex:"女"
}let obj3 = {...obj1,...obj2
}var propertyArr = Object.getOwnPropertyNames(obj3);  //遍历不到symbol属性

如果想要获取Symbol属性名,需要一个单独的方法

var propertyArr = Object.getOwnPropertySymbols(obj3);

最后注意一点,JSON在序列化对象的时候,不会操作Symbol

总结:

1、Symbol是默认不重复的,它是全局唯一的

2、Symbol是基础数据类型,它必须通过Symbol()返回值获取,每次获取的都不一样

3、Symbol.for()可以得到相同的标识名

4、Symbol(“描述信息”) 在创建标识的时候添加描述信息

5、在Symbol中,有一些特殊值,目前用的最多的就是 [Symbol.iterator] 迭代器

生成器函数

它是ES6中新增的一个函数类型,旨在解决迭代的问题

生成器函数定义
function* abc(){}

在普通函数里面,我们可以通过return返回一个值,并且只能返回一次,因为函数一旦碰到return就直接结束了

试想一下,有没有一种函数可以多次返回,这个时候迭代器就来帮你解决问题

要实现迭代器就必须通过生成器函数的执行来获得

function* abc(){//生成器函数内部是可以返回多个值//要返回多个值使用yieldyield "a";yield "b";yield "c";return "张三"
}var x = abc()   //生成器函数执行以后,得到迭代器

分析:

在上面的代码中,我们的abc生成器函数使用yield返回了a,b,c 三个值,最后又返回了 张三,整个生成器函数向外传递了4个值

但是,这4个值并不是一次性传递出去的,而是一个一个返回的

执行迭代器
function* abc(){//生成器函数内部是可以返回多个值//要返回多个值使用yieldyield "a";yield "b";yield "c";return "张三"
}var x = abc()   //生成器函数执行以后,得到迭代器
let a = x.next();
let b = x.next();
let c = x.next();
let d = x.next();

分析:

每一次next方法的执行就会返回一个yield的结果,直到最后一个return结束,返回的结果是一个对象,对象中value属性表示返回的数据,done表示是否迭代完毕

一个生成器函数的执行可以得到一个迭代器,这个迭代器可以得到一个next方法,这个时候注意,这个next是可以接收参数的,将接收的参数传回给生成器函数的内部

function* abc(str){console.log(str);let a1 = yield "a";			console.log(a1);let b1 = yield "b";console.log(b1);let c1 = yield "c";console.log(c1);return "张三"
}var x = abc("张三")   //生成器函数执行以后,得到迭代器
let a = x.next();
let b = x.next("李四");
let c = x.next("王五");
let d = x.next("赵六");

注意:

这里我们看到结果,张三是没有打印出来的,如果生成器函数要接收初次next的参数,应该直接给到str中接收

生成器函数里面调用另外一个生成器函数
function* xyz(){yield "a";yield "b";yield* def();  //yield "张三";  yield "李四"yield "c";yield "d"
}function* def{yield "张三";yield "李四"
}

最终打印结果应该是 a b 张三 李四 c d

迭代器

迭代就是把一群东西(数据集合)一个一个拿出来的过程,并且只能顺着拿,一旦迭代结束不能重新开始,也不能break

迭代器就是一个个返回的过程,可以多次返回,迭代器只能通过生成器函数得到

迭代器接口

接口可以理解成是一种规范,只要实现了这个接口,就一定实现了这个规范,实现了这个规范就可以具备这个能力

迭代器状态

当我们生成迭代器的时候生成一个迭代器轴,这个轴内部有一个默认状态,这个状态决定了done这个属性的值是true还是false

1、suspended 暂停状态

2、closed 关闭状态,当前迭代结束进行关闭状态

迭代器遍历

迭代器本身是可以遍历,在上面的代码中我们可以看到,我们需要使用next方法一个一个去拿,这样很麻烦

只要实现了迭代器接口的就可以使用for…of ,而迭代器本身就是一个规范,所以肯定是可以使用for…of

function* xyz(){yield "a";yield "b";yield* def();  //yield "张三";  yield "李四"yield "c";yield "d"
}function* def(){yield "张三";yield "李四"
}let z = xyz();for(let item of z){console.log(item);
}

如果可以使用for…of 就一定可以使用展开运算符

console.log(...z);

注意:

迭代器一旦结束不能重新开始,所以上面的for…of与展开运算符不能同时使用

主动实现迭代器接口

主动实现迭代器接口,只需要在对象内部添加一个Symbol(Symbol.iterator)

let obj1 = {0:"张三",1:"李四",2:"王五",3:"赵六",length:4,*[Symbol.iterator](){let index = 0;while(index < this.length){yield this[index];index++}}
}
//以上是我们自定义的类数组
for(let item of obj1){console.log(item);
}

反射

我们可以把反射看做成镜子里面的object对象,这个镜子比较厉害,可以把看的到和看不到的全照出来

var obj1 = {sex:"男",[Symbol("userName")]:"张三"
}
Object.defineProperty(obj1,"age",{value:18,enumerable:false
})
var arr1 = Object.keys(obj1);
var arr2 = Object.getOwnPropertyNames(obj1);
var arr3 = Object.getOwnPropertySymbols(obj1);var arr4 = Reflect.ownKeys(obj1);

1、apply相当于之前方法.apply一样(存疑???????????)


2、consturct 相当于new调用一个构造函数

class Student{constructor(userName){this.userName = userName}
}
let s1 = Reflect.construct(Student,["李四"]);
let s2 = new Student("张三")

3、defineProperty 在一个对象上面添加一个新属性,相当于Object.defineProperty

4、deleteProperty 删除对象的一个属性,相当于delete

5、get获取对象某一个属性值

6、getOwnPropertyDescriptor 获取当前对象属性的描述信息,相当于Object.getOwnPropertyDescriptor

7、getPrototypeof 获取当前对象的原型

8、has 判断某一个对象内是否有某个属性,相当于Object.hasOwnProperty()

9、isExtensible 判断一个对象是否为一级保护对象

10、ownKeys 获取对象的所有属性名

11、set 设置对象的某一个属性

代理Proxy

代理可以理解成是一个代理人,在JS里面代理实现的其实就是一个全局拦截

代理里面两个核心

1、代理对象proxy

2、目标对象target

创建代理对象
var obj = {userName:"张三",work:"厨子",money:10000,address:"上海"
}let obj_proxy = new Proxy(obj,{})

控制台打印两个对象会发现代理比目标多了两个东西

handler 具体的代理了目标对象的哪些操作

Target 代理的目标对象

obj_proxy.money = 200

我们执行了代理对象money属性的赋值操作,对应的目标对象money属性也一同变化

代理的作用

全局拦截

var obj = {userName:"张三",work:"厨子",money:10000,address:"上海"
}let obj_proxy = new Proxy(obj,{//取值操作get(target,p){if(p == "money"){return "不关你的事"}else{target[p]}},//赋值操作set(target,p,v){if(p == "money"){console.log("给我涨工资么?")}else{target[p] = v;}}
})

代码分析:

上面的get是取值操作,所有的取值操作都会触发get方法,而set方法则是代理所有的赋值操作,所以所有的赋值操作都会触发set方法

在上面的代码中我们其实还有问题,我们的obj_proxy作为代理对象是要去保护目标对象的,但是结果却没有

我们依然可以通过目标对象直接去调用,怎么样让代理对象真正的保护好目标对象?

let p1 = new Proxy((()=>{return {userName:"张三",password:"123",sex:"男",age:20,height:170}
})(),{get(target,p){if(p == "userName" || p == "sex"){return target[p]}else{return undefined}},set(target,p,v){if(p == "userName" || p == "sex"){target[p] = v;}}
})

代码分析:

上面的代码里面,我们的目标对象并没有暴露在外面,我们目标对象是直接通过立即执行函数返回的一个对象,这样外部就访问不到这个对象,只能访问到p1代理对象

通过代理实现私有属性
let student = new Proxy((() => {return {userName:"张三",_sex:"男",age:20,hobby:"sleep",_IDCard:"1234567",_tel:"1311111111",address:"北京"}
})(),{get(target,p){return target[p]},set(target,p,v){if(p.startsWith("_")){return}else{target[p] = v;}},//代理对象的删除操作deleteProperty(target,p){if(p.startsWith("_")){return}else{return delete target[p]}}
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pom.xml中resouces标签

pom.xml中resouces标签 resources是maven在编译项目时将资源文件或者额外的文件赋值到输出目录(target/classes)中。通常包括配置文件&#xff0c;属性文件&#xff0c;模板文件&#xff0c;jar包等。 resouces中可以包含resouce。也就是可以自定义的配置多个资源配置。 direct…

数据结构学习之单向循环链表应用的案例(旋转链表)

实例要求&#xff1a; 1、给定一个链表的头节点 head &#xff0c;请你旋转链表&#xff0c;将链表每个节点向右移动 k 个位置&#xff1b; 2、链表中节点的数目的范围为[0, 500] &#xff1b; 实例分析&#xff1a; 1、入参合理性检查&#xff0c;即head ! NULL || head-&…

JVM运行时数据区(下篇)

紧接上篇&#xff1a;JVM运行时数据区&#xff08;上篇&#xff09;-CSDN博客 堆 一般Java程序中堆内存是空间最大的一块内存区域。创建出来的对象都存在于堆上。 栈上的局部变量表中&#xff0c;可以存放堆上对象的引用。静态变量也可以存放堆对象的引用&#xff0c;通过静态…

Word插件-大珩助手-手写电子签名

手写签名 支持鼠标写&#xff0c;支持触摸屏写&#xff0c;点击画笔按钮切换橡皮擦&#xff0c;支持清空画板重写&#xff0c;点击在word中插入签名&#xff0c;可插入背景透明的签字图 素材库-保存签名 将写好的签字图复制粘贴到素材库中&#xff0c;以便永久使用&#xff…

AMEYA360:广和通RedCap模组FG131FG132系列

2024年1月&#xff0c;广和通RedCap模组FG131&FG132系列已进入工程送样阶段&#xff0c;可为终端客户提供样片。广和通RedCap模组系列满足不同终端对5G速率、功耗、尺寸、成本的需求&#xff0c;全面助力RedCap技术的行业应用。 FG131&FG132系列基于骁龙X35 5G调制解调…

第六站:C++面向对象

面向对象的第一概念:类 类的构成: “类”&#xff0c;是一种特殊的“数据类型”&#xff0c;不是一个具体的数据。 类的设计: 创建一个类: class Human { public://公有的,对外的void eat();//方法,成员函数void sleep();void play();void work();string getName();//获取对内…

Git相关3 —— 命令及添加Gitee的公钥

1.Git相关命令1 -- 工作目录、暂存区、本地仓库、 使用平台有&#xff1a;cmd、Git bash、VSCode window系统修改VSCode默认终端为git bash git init 初始化 --- 新增.git 文件夹 git status 查看 文件/文件夹 状态 git add 需要追踪的文件名/文件夹名 提交到暂存区 git add…

Electron中 主进程(Main Process)与 渲染进程 (Renderer Process) 通信的方式

1. 渲染进程向主进程通信 修改 html 文件内容 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><!-- 解决控制…

docker部署私人云盘nextcloud

1.拉取镜像 docker pull nextcloud 2.创建目录 mkdir -p /data/nextcloud/{config,data,apps} 3.创建实例 docker run -itd --name yznextcloud -v /data/nextcloud/config:/var/www/html/config -v /data/nextcloud/data:/var/www/html/data -v /data/nextcloud/apps:/va…

Sublime Text4 crack时替换的汇编指令

Sublime Text4 crack时替换的汇编指令 首先请支持正版&#xff0c;这里研究破解的步骤&#xff0c;仅做汇编代码学习。 破解步骤很简单&#xff1a; 打开二进制文件&#xff0c; 搜索 80 78 05 00 0F 94 C1&#xff0c; 替换为 C6 40 05 01 48 85 C9. (源: https://gist.git…

项目成本管理

4过程&#xff1a; 规划成本管理&#xff0c;估算成本&#xff0c;制定预算&#xff0c;控制成本 估算和预算的区别&#xff1a; 估算时准备向上级拿钱&#xff0c;通常是数值&#xff0c;项目团队做&#xff0c; 预算是拿到钱之后怎么花&#xff0c;通常是S曲线&#xff0c…

AI-数学-高中-4.函数表达式特性-要变一起变

原作者视频&#xff1a;函数】1引导课&#xff1a;高中为什么用f(x)_哔哩哔哩_bilibili 1.什么是函数&#xff1a;给定任意一个x&#xff0c;都有唯一确定的y与之对应&#xff0c;这种x与y的关系就叫函数&#xff0c;类似一个加工厂。 判断图像是否是函数&#xff0c;用竖直线…

如何用MetaGPT帮你写一个贪吃蛇的小游戏项目

如何用MetaGPT帮你写一个贪吃蛇的小游戏项目 MetaGPT是基于大型语言模型(LLMs)的多智能体写作框架&#xff0c;目前在Github开源&#xff0c;其Start数量也是比较高的&#xff0c;是一款非常不错的开源框架。 下面将带你进入MetaGPT的大门&#xff0c;开启MetaGPT的体验之旅。…

Uncaught TypeError: Cannot set properties of null (setting ‘textContent‘)是什么原因

这个错误提示表示试图设置一个 null 值的 textContent 属性&#xff0c;这通常是因为在试图操作一个不存在的或者不存在于文档中的元素而导致的。 在使用 document.getElementById() 或者类似的方法获取元素时&#xff0c;如果参数所对应的元素不存在时&#xff0c;会返回 nul…

代码随想录算法训练营第二十天|236. 二叉树的最近公共祖先

236. 二叉树的最近公共祖先 private TreeNode ans null;private int postOrder(TreeNode root, TreeNode p, TreeNode q) {if (root null) {return 0;}//查看子结点的梳计个数int lcnt postOrder(root.left, p, q);int rcnt postOrder(root.right, p, q);//利用子结点返回…

《C++大学教程》4.13汽油哩数

题目: 每位司机都关心自己车辆的行车里程数。有位司机通过记录每次出行所行驶的英里数和用油的加仑数来跟踪他多次出车的情况。请开发一个C程序&#xff0c;它使用一条while语句输入每次出车的行驶英里数和加油量。该程序应计算和显示每次出车所得到的每加仑行驶英里数&#x…

Flutter开发进阶之并发操作数据库

Flutter开发进阶之并发操作数据库 尽管 Flutter 本身不包含任何数据库功能&#xff0c;但可以使用各种第三方库和插件来在 Flutter 应用程序中实现数据库功能&#xff1b; 以下将使用sqflite作为例子&#xff0c;sqflite允许在 Flutter 应用程序中执行 SQL 查询&#xff0c;创…

基于深度学习的多类别电表读数识别方案详解

基于深度学习的多类别电表读数识别方案详解 多类别电表读数识别方案详解项目背景项目难点最终项目方案系列项目全集&#xff1a; 安装说明环境要求 数据集简介数据标注模型选型明确目标&#xff0c;开始下一步的操作 检测模型训练模型评估与推理番外篇&#xff1a;基于目标检测…

pi gpio 内存映射

树霉pi gpio内存映射 #include <stdio.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <stdlib.h>#define BCM2835_PERI_BASE 0x20000000 #define GPIO_BASE (BCM2835_PERI_BASE 0x200000) #define PAGE_SIZE…

vue3移动端适配

将vue3项目中的 px 单位&#xff0c;自动转换为rem 单位 可以看到这里会根据页面缩小放大变化 需要安装两个插件&#xff0c;看步骤 amfe-flexible --- 默认指向2.2.1版本 npm i -S amfe-flexiblepostcss-pxtorem --- 默认指向6.0.0版本 --save-dev 参数会把依赖包的版本信…