首页 > 编程语言 >去往js函数式编程(8)完

去往js函数式编程(8)完

时间:2023-06-28 10:44:05浏览次数:59  
标签:冻结 obj 对象 编程 js 去往 let newObject oldObject

冻结

  如果我们希望避免程序员意外或故意修改对象的可能性,冻结对象是一个有效的解决方案。在对象被冻结之后,任何修改它的尝试都会静默失败。javascript 不会报告错误或抛出异常,但也不会修改对象。这种解决方案只有一个问题:冻结对象是一个浅层操作,它仅冻结属性本身,类似于 const 声明的作用。如果任何属性本身是对象或数组,并且具有进一步的对象或数组作为属性,依次类推,它们仍然可以被修改。

let myObj3 = {
  d: 22,
  m: 9,
  o: { c: 'MVD', i: 'UY', f: { a: 56 } }
}

Object.freeze(myObj3)
console.log(myObj3) // {d:22, m:9, o:{c:"MVD", i:"UY", f:{ a:56}}}

//这只是部分成功,当我们尝试更改一些属性时可以看到:
myObj3.d = 8888 //不起作用,与之前一样
myObj3.o.f.a = 9999 //糟糕,起作用了!
console.log(myObj3) // {d:22, m:9, o:{c:"MVD", i:"UY", f:{ a:9999}}}

  如果我们想要实现真正的不可变性,我们需要编写一个可以冻结对象所有层级的例程。幸运的是,通过应用递归,很容易实现这一点。主要思想是先冻结对象本身,然后递归冻结每个属性。我们必须确保只冻结对象自身的属性,不要干扰对象的原型。

const deepFreeze = (obj) => {
  if (obj && typeof obj === 'object' && !Object.isFrozen(obj)) {
    Object.freeze(obj)
    Object.getOwnPropertyNames(obj).forEach((prop) => deepFreeze(obj[prop]))
  }
  return obj
}

  如果一个对象包含对自身的引用会发生什么?如果我们跳过冻结已经被冻结的对象,我们可以避免这个问题:由于它们所引用的对象已经被冻结,因此后向循环引用将被忽略。

  如果禁止修改对象,那么你必须创建一个新对象。例如,如果你使用 Redux,reducer 是一个函数,它接收当前状态和一个动作(本质上是一个带有新数据的对象),并生成新的状态。为了结束这一切,我们还应该冻结返回的对象,就像我们对原始状态做的那样。但让我们从头开始:如何克隆一个对象?

let oldObject = {
  d: 22,
  m: 9,
  o: { c: 'MVD', i: 'UY', f: { a: 56 } }
}

let newObject = {
  d: oldObject.d,
  m: oldObject.m,
  o: { c: oldObject.o.c, i: oldObject.o.i, f: { a: oldObject.o.f.a } }
}

  你可以使用 Object.assign()或扩展运算符来创建浅复制对象:要创建再次是浅数组的副本,你可以使用 slice()或扩展运算符,如果一个对象或数组包含对象,我们会遇到冻结时的相同问题:对象是按引用复制的,这意味着在新对象中的更改也会影响到旧对象。

let newObject1 = Object.assign({}, myObj)
let newObject2 = { ...myObj }

let myArray = [1, 2, 3, 4]
let newArray1 = myArray.slice()
let newArray2 = [...myArray]

let oldObject = {
  d: 22,
  m: 9,
  o: { c: 'MVD', i: 'UY', f: { a: 56 } }
}
let newObject = Object.assign({}, oldObject)
newObject.d = 8888;
new newObject.o.f.a = 9999;

console.log(newObject);
// {d:8888, m:9, o: {c:"MVD", i:"UY", f: {a:9999}}} -- ok

console.log(oldObject);
// {d:22, m:9, o: {c:"MVD", i:"UY", f: {a:9999}}} -- oops!!

  在这种情况下,请注意当我们更改 newObject 的某些属性时会发生什么。更改 newObject.d 是可以的,但更改 newObject.o.f.a 也会影响到 oldObject,因为 newObject.o 和 oldObject.o 实际上是对同一个对象的引用。对于有一个简单的基于 JSON 的解决方案。如果我们对原始对象进行 stringify(),然后解析 parse()结果,我们将得到一个与旧对象完全独立的新对象:

const jsonCopy = (obj) => JSON.parse(JSON.stringify(obj))

  使用 JSON.stringify(),我们可以将对象转换为字符串。然后,JSON.parse()会将该字符串创建一个对象;简单!这适用于数组和对象,但存在一个问题。如果对象的任何属性具有构造函数,它们不会被调用:结果始终由普通的 js 对象组成。

let myDate = new Date()
let newDate = jsonCopy(myDate)
console.log(typeof myDate, typeof newDate)

  模式通常以四个基本要素描述:简洁的名称,用于描述问题,解决方案和后果。模式适用的上下文:需要解决方案的特定情况,可能还有一些额外的条件必须满足。解决方案:列出解决给定情况所需的元素。应用模式的后果。你可能从解决方案中获得一些收益,但也可能带来一些损失。

检测多次点击

  假设出于某种原因,你决定用户应该能够多次点击某个元素,并且点击次数在某种程度上具有意义并产生某种特殊结果。浏览器非常擅长检测单机或双击,但三次火更多次点击并不那么容易获得。

<html>
  <head>
    <title>多次点击示例</title>
    <script type="text/javascript" src="rxjs.umd.js"></script>
  </head>
  <body>
    <span id="mySpan">多次点击此文本(快速点击)</span>
    <script>
      const { fromEvent, pipe } = rxjs;
      const { buffer, filter } = rxjs.operators;

      const spanClick$ = fromEvent(
      document.getElementById("mySpan"),
      "click"
      );

      spanClick$
      .pipe(
      buffer(spanClick$.pipe(debounceTime(250))),
      map(list =>list.length),
      filter(x =>x >= 3)
      )
      .subscribe(e =>{
      console.log(${e} 次点击于 ${new Date()});
      });
    </script>
  </body>
</html>

不写咯,换本书看看

标签:冻结,obj,对象,编程,js,去往,let,newObject,oldObject
From: https://www.cnblogs.com/wlxll/p/17510778.html

相关文章

  • Kubernetes编程——修改客户端默认支持 Protobuf
    修改客户端默认支持Protobuf一、在kubernetes客户端中修改默认支持Protobuf确保你已经安装了kubectl命令行工具,并且版本在1.14.0或更高。打开~/.kube/config文件,该文件存储了你的Kubernetes集群配置信息。找到clusters部分,并在你的集群配置下添加extensions字段,示例如下:......
  • 编程初学者入门5_键盘输入5个人的身高(米),求他们的平均身高(米)。(C的没问题,试着用Java写
    写在前面此系列博客为牛客网编程初学者入门题目小结,题目很基础不常用的知识容易遗忘,为了边复习c语言和学习Java,后面系列博客将采用c、c++、Java双语言版记录现在位置(72/140),虽然我走的很慢,但我仍在前进~题目描述从键盘输入5个人的身高(米),求他们的平均身高(米)。输入描述:一行,连续输......
  • 编程初学者入门6_简单分支问题+Java在OJ中实现多组输入sc.hasNextInt()函数
    题目KiKi想知道这学期他的学习情况,BoBo老师告诉他这学期挂的科目累计的学分,根据所挂学分,判断KiKi学习情况,10分以上:很危险(Danger++),4~9分:危险(Danger),0~3:Good。输入描述:一行,一个整数(0~30),表示KiKi挂的科目累计的学分。输出描述:一行,根据输入的挂科学分,输出相应学习情况(Danger+......
  • 编程初学者入门7_公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分
    题目描述公务员面试现场打分。有7位考官,从键盘输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。输入描述:一行,输入7个整数(0~100),代表7个成绩,用空格分隔。输出描述:一行,输出去掉最高分和最低分的平均成绩,小数点后保留2位,每行输出后换行。示例1我的......
  • 编程初学者入门11_井字棋游戏、进制转换、订闹钟(时间换算)
    一、井字棋游戏题目描述KiKi和BoBo玩“井”字棋。也就是在九宫格中,只要任意行、列,或者任意对角线上面出现三个连续相同的棋子,就能获胜。请根据棋盘状态,判断当前输赢。输入描述:三行三列的字符元素,代表棋盘状态,字符元素用空格分开,代表当前棋盘,其中元素为K代表KiKi玩家的棋子,为O表......
  • 【雕爷学编程】Arduino动手做(132)---KY-027魔术光环模块
    7款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞......
  • ExcelJS 导入导出excel带下拉框筛选数据
    importExcelJSfrom"exceljs"; asyncfunctionexportExcelTemplate(deptList:any){ constworkbook=newExcelJS.Workbook(); constworksheet=workbook.addWorksheet("模板"); worksheet.columns=[  {   header:"编号"......
  • 合并行的单元格 EXTJS
    在ExtJS4中,如何合并行的单元格,已经选取的时候只能选择某一列,期望的效果如下:在ExtJS中,合并表头的列有现成方案,但是合并行单元格不是extjs的现有功能,这个需要底层扩展,也就是使用table的跨行实现。而ExtJS7以及新版本和ExtJS4在最底层的Grid组成上又有差别,所以不同......
  • js中“??“和“?.“怎么用?
    ??:空值合并操作符逻辑操作符,左侧为null和undefined时,才返回右侧的数?.:可选链操作符可以读取位于连接对象链深处属性的值,不必明确验证链中的每个引用是否有效功能类似于“.”链式操作符,不同之处在于,在引用为空null或者undefined的情况下不会引起错误,该表达式短路返回值是u......
  • 鸿蒙星空的太白星 | WebView给元服务调用JS API指明方向
    ​漆黑深夜夜凉如水,繁星盛开于无垠苍穹。清风徐来,一片薄云,夜空顿然失色,有些阴霾。天空中最亮的星,太白星,在薄云中依然闪耀,如同海上迷雾中的灯塔,为迷失方向的船只指明方向。 元服务是华为提供的一种面向未来的服务形态,具有独立入口和免安装等特性,支持运行在1+8+N设备上。在万物互......