Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JS中的非可变性

JS中的非可变性

作者头像
IMWeb前端团队
发布于 2019-12-03 09:10:28
发布于 2019-12-03 09:10:28
89900
代码可运行
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队
运行总次数:0
代码可运行

本文作者:IMWeb coolriver 原文出处:IMWeb社区 未经同意,禁止转载

非可变性是函数式编程的一个核心规则,对于面向对象编程也有很多用处。本文为参考sitepoint(参考链接1)中的文章后所记录的一些主要内容。

参考链接1:http://www.sitepoint.com/immutability-javascript/ 参考链接2:immutable-js 参考链接3:Immutable_object

什么是非可变性?(Immutability)

如果用非可变性来形容一个对象,对么这个对象的特点是:这个对象在创建之后不会被修改。JS中很多值是非可变的,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var statement = "I am an immutable value";
var otherStr = statement.slice(8, 17);

在执行完以上代码后,statement的值并不会改变。实际上JS中所有字符串方法都不会改变原字符串,而是返回新的字符串。因为字符串是非可变的--不能被修改,只能创建新的字符串。在JS中不只有字符串是非可变,普通的数值也是非可变的。2 + 3并不会改变2的值。

JS中存在中着大量的可变性

在JS中,字符串和数值被设计为非可变的,但是很多情况下并非如此。例如下面:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var arr = [];
var v2 = arr.push(2);

以上代码会使得arrv2都变为[2]push操作改变了原数组的内容。要想使数组满足非可变性,需要使用自定义的类似的数据结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var arr = new ImmutableArray([1, 2, 3, 4]);
var v2 = arr.push(5);

arr.toArray(); // [1, 2, 3, 4]
v2.toArray();  // [1, 2, 3, 4, 5]

var person = new ImmutableMap({name: "Chris", age: 32});
var olderPerson = person.set("age", 33);

person.toObject(); // {name: "Chris", age: 32}
olderPerson.toObject(); // {name: "Chris", age: 33}

以上模拟的非可变数组和非可变Map的操作并不会改变原数据结构中的内容,而是返回新的对象。

JS中非可变性的意义

在应用开发过程中,经常需要管理和跟踪一些状态(在很多UI框架中很常见),这个过程较困难且容易出错。使用非可变性数据结构进行开发,可以使应用中的数据流以不一样的形式来实现和管理。

在使用普通对象(可变性对象)进行开发时,当需要跟踪管理某些数据的变更,需要用到Object.observe之类的方法来监控某个对象,并指定相应的回调函数。这种方法有两弊端:

  1. 为了实现监控某些对象的某些改变成进行某些操作,需要维持较大的内存空间来记录这些信息。过度地使用会使得程序的性能下降。
  2. 让程序的不同部分之间由同步变为异步,更容易发生错误,且排查起来更加困难。 如果使用非可变性对象来存储应用数据,为了监控某个对象的属性是否发生改变,不需要使用“订阅者--发布者”模式,而直接使用上一步得到的新对象与原对象作比较:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 2);
assert(map1 === map2); // no change
var map3 = map1.set('b', 50);
assert(map1 !== map3); // change

使用非可变性对象可以将异步的“订阅者--发布者”模式变成同步的顺序逻辑,即在可能产生新数据的操作之后进行判断并处理。非可变性对象的另一个好处是克隆对象比较方便。因为非可变性对象在创建之后不会被修改,所以可以直接使用等号赋值将一个对象的引用赋给另一个对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var map1 = Immutable.Map({a:1, b:2, c:3});
var clone = map1;

这种赋值引用的方式可以极大地节约内存。说到节约内存,非可变性对象很容易让人怀疑:“像这样有一点修改就创建一个完全的新对象,是不是会很浪费空间?”。如果在创建新对象的时候是完全开辟新的内存空间来存储原对象的所有属性,那么确实很浪费空间。但是在实现非可变性数据结构时可以采用“共享数据结构”(structural sharing)的方法,不同对象的相同值的属性可以共享,只额外保存新的属性值,和一些用于共享的引用信息,这样就可以解决内存开销过大的问题。虽然还是会有一额外的内存开销,但是相比于非可变性数据结构在其它方面带来的开发和性能方面的好处来说可以忽略。下面介绍的immutable-js也是用到了共享数据结构的方法。

immutable-js简介

immutable-js是facebook开发的JS非可变性数据结构集合。里面包含的非可变性数据结构包括List,Stack,Map,OrderedMap,Set,OrderedSetRecord。这些数据结构参考了ES6中新增的一些数据结构,并有所增强。上一节提到了“共享数据结构”,在immutable-js中使用的是hash maps triesvecor tries这两种Clojure和Scala使用的方法来实现,使数据复制与缓存的开销大大降低。immutable-js源码使用ES6标准开发,通过编译程序编译为ES3代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var Immutable = require('immutable');
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 50);
map1.get('b'); // 2
map2.get('b'); // 50

非可变性数据简单使用示例

Immutability in JavaScript一文中,作者简单地讲解了使用immutable-js中的非可变性数据结构来实现扫雷游戏(Minesweeper)的单元格管理。详细代码在code pen这里。下面是两个主要的函数

  • 初始化数据结构:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function createGame(options) {
  return Immutable.fromJS({
    cols: options.cols,  //列数
    rows: options.rows,  //行数
    tiles: initTiles(options.rows, options.cols, options.mines) //单元格列表
  });
}

/*初始化后的数据结构形如:
{
    cols: 2,
    rows: 2,
    tiles: [{id: 0,isRevealed: false},{id: 1,isRevealed: false},
            {id: 2,isRevealed: false},{id: 3,isRevealed: false}]
}
*/
  • 揭开单元格操作:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function revealTile(game, tile) {
  return game.getIn(['tiles', tile]) ?  //判断揭开的单元格id是否存在
    game.setIn(['tiles', tile, 'isRevealed'], true) :
    game;
}

作者在后续还分析了ES7中的Object.observe()方法并不能很好地解决UI框架中的状态跟踪问题。例子也是使用上面的扫雷:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var tiles = [{id: 0, isRevealed: false}, {id: 1, isRevealed: true}];
Object.observe(tiles, function () { /* ... */ });

tiles[0].id = 2;

在使用原生数组存储单元格信息时,使用Object.observe()不能捕捉到tiles中某个元素的属性被修改。

总结

本文简述了Immutability in JavaScript以及immutable-js文档中关于非可变性之于JS的意义与应用场景。非可变性在JS中实际存在(字符串和数值),在一些函数式编程语言中是一个重要概念(Scala等)。在涉及到状态变更的应用中,使用非可变性数据结构开发的程序在数据流特性上与“订阅者--发布者”有着很大的不同。

JS也是一种函数式编程语言,在ES6中新增的尾调用优化特性使JS更具有“函数式”特性。如果能参考其它函数式语言使用非可变性数据结构来构建数据流,可能会有很好的效果。但是究竟能否对现有observe模式的程序有性能和开发便利方面的改进,还需要进一步调查。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-05-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
React性能优化三篇之一
简单的说就是Redux能够管理js app的状态,状态是由数据维护的,也就是说Redux是管理数据的。那么Redux是怎么管理数据的呢?
javascript.shop
2019/09/04
5530
React性能优化三篇之一
JavaScript 中的 不变性(Immutability)
不变性(Immutability)是函数式编程的核心原理,也有很多面向对象的程序提供了这一特性。在这篇文章中,我将展示什么是完全不变的,如何在JavaScript中使用这个概念,以及为什么它是有用的。
用户7293182
2022/01/20
1.1K0
JavaScript 中的 不变性(Immutability)
Python 对象引用与可变性
Python 中的变量都是引用式的,这个概念很容易在写代码的时候引入 bug,还不易察觉。这篇文章就是讲述 Python 中对象的引用和可变性,然而首先要抛弃变量是存储数据的盒子的传统观念。
CS实验室
2021/03/22
4080
翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 第 6 章:值的不可变性
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 第 6 章:值的不可变性 在第 5 章中,我们探讨了减少副作用的重要性:
iKcamp
2018/01/04
1.2K0
翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 第 6 章:值的不可变性
immutable.js 简介
Immutable数据就是一旦创建,就不能更改的数据。每当对Immutable对象进行修改的时候,就会返回一个新的Immutable对象,以此来保证数据的不可变
江米小枣
2020/06/16
1.6K0
immutable.js 简介
React应用优化:避免不必要的render
React在组件的生命周期方法中提供了一个钩子shouldComponentUpdate,这个方法默认返回true,表示需要重新执行render方法并使用其返回的结果作为新的Virtual DOM节点。通过实现这个方法,并在合适的时候返回false,告诉React可以不用重新执行render,而是使用原有的Virtual DOM 节点,这是最常用的避免render的手段,这一方式也常被很形象地称为“短路”(short circuit)。
博文视点Broadview
2020/06/12
1.4K0
String 的“不可变性”是因为 final?请别再错下去了!
“Java 中 String 为什么设计成 final 类?为什么它有’不可变性’?”
业余草
2019/03/11
7080
String 的“不可变性”是因为 final?请别再错下去了!
深入探究Immutable.js的实现机制(一)
Immutable.js 由 Facebook 花费 3 年时间打造,为前端开发提供了很多便利。我们知道 Immutable.js 采用了持久化数据结构,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过结构共享等方式大幅提高性能。
秋风的笔记
2020/10/27
1.5K0
深入探究Immutable.js的实现机制(一)
多线程----Immutable VS Mutable (可变与不可变)
Immutable是什么意思?不变的、不发生改变的意思。在JDK中有很多的类被设计成不可变的,举个大家经常用到的类java.lang.String,String类被设计成不可变。String所表示的字符串的内容绝对不会发生变化。因此,在多线程的情况下,String类无需进行互斥处理,不用给方法进行synchronized或者lock等操作,进行上锁、争抢锁、解锁等流程也是有一定性能损耗的。因此,若能合理的利用Immutable,一定对性能的提升有很大帮助。
令仔很忙
2019/02/25
6230
聊一聊C#中的不可变类型
在C#中,不可变类型(Immutable Types)是指一旦创建后,其状态或内容不能被修改的数据类型。不可变类型是基于函数式编程的概念,它们通常用于创建不可更改的对象,从而提高代码的可靠性、可维护性和线程安全性。
JusterZhu
2023/09/06
5110
聊一聊C#中的不可变类型
【Java】Java中String不可变性的底层实现
在Java编程中,String类的不可变性是一个被广泛讨论和利用的特性。这种不可变性使得String对象在创建后无法被修改,从而保证了程序的安全性和线程安全性。本文将深入探讨Java中String不可变性的底层实现原理,并讨论其对程序设计的影响。
人不走空
2024/03/07
1400
【Java】Java中String不可变性的底层实现
震惊,99.9% 的同学没有真正理解字符串的不可变性
稍有些基础的同学都知道 Java 中 String 字符串是“不可变”的,想要使用“可变字符串”可以使用 StringBuilder 和 StringBuffer 。
明明如月学长
2022/09/17
2620
震惊,99.9% 的同学没有真正理解字符串的不可变性
javascript基础修炼(8)——指向FP世界的箭头函数
箭头函数是ES6语法中加入的新特性,而它也是许多开发者对ES6仅有的了解,每当面试里被问到关于“ES6里添加了哪些新特性?”这种问题的时候,几乎总是会拿箭头函数来应付。箭头函数,=>,没有自己的this , arguments , super , new.target ,“书写简便,没有this”在很长一段时间内涵盖了大多数开发者对于箭头函数的全部认知(当然也包括我自己),如果只是为了简化书写,把=>按照function关键字来解析就好了,何必要弄出一个跟普通函数特性不一样的符号呢?答案就是:函数式编程(Functional Programming)。
大史不说话
2018/10/25
5010
javascript基础修炼(8)——指向FP世界的箭头函数
Python 字符串不可变性的优缺点
随着计算机技术的快速发展,越来越多的编程语言被发明出来,每种编程语言都有自己独特的特点和优势。以我经常使用python写爬虫为例,在 Python 中,字符串是不可变的,这意味着一旦字符串被创建,就不能被修改。这与其他一些编程语言(如 C++ 和 Java)不同,在这些语言中,字符串是可以被修改的。
华科云商小徐
2024/01/22
1980
Immutable日常操作之深入API
写在前面 本文只是个人在熟悉Immutable.js的一些个人笔记,因此我只根据我自己的情况来熟悉API,所以很多API并没有被列举到,比如常规的push/map/filter/reduce等等操作,这些API我认为只要你自己稍微看一下官网的介绍都可以知道怎么用。本文所有的代码请参看本人的github地址https://github.com/Rynxiao/immutable-learn。 一、什么是Immutable collections Immutable data cannot be change
糊糊糊糊糊了
2018/05/09
1.9K0
✨从纯函数讲起,一窥最深刻的函子 Monad
本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!
掘金安东尼
2022/10/27
4640
共享可变状态中出现的问题以及如何避免[每日前端夜话0xDB]
这里有两个独立的部分:函数logElements()和函数main()。后者想要在对数组进行排序的前后都打印其内容。但是它到用了 logElements() ,会导致数组被清空。所以 main() 会在A行输出一个空数组。
疯狂的技术宅
2019/11/03
1.6K0
Rust学习笔记:3.1 变量与可变性
3.1 变量与可变性 声明变量使用 let 关键字 默认情况下,变量是不可变的(Immutable) 案例:variables fn main() { let mut x = 5; println!("x = {}", x); //5 可变 x = 6; println!("x = {}", x); //6 可变 let x = 7; println!("x = {}", x); //7 不可变 } 3.1.1 变量与常量 常量 (constant),常量是
DioxideCN
2022/08/05
2680
java安全编码指南之:Mutability可变性
mutable(可变)和immutable(不可变)对象是我们在java程序编写的过程中经常会使用到的。
程序那些事
2020/09/04
4790
java安全编码指南之:Mutability可变性
字符串 --- 不可变性与驻留池
面试中,常会问道,在大数据量的字符串拼接情况,为什么 StringBuilder 性能比直接字符串拼接更好?
Niuery Diary
2023/10/22
1880
字符串 --- 不可变性与驻留池
相关推荐
React性能优化三篇之一
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验