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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Unity3D】Unity 脚本 ② ( Visual Studio 2019 中的 Unity 编译环境配置 | Unity 编辑器关联外部 C# 脚本编辑器 Visual Studio )
在上一篇博客 【Unity3D】Unity 脚本 ① ( 创建 C# 脚本 | Visual Studio 2019 中打开 C# 脚本 | 编译 C# 脚本 | 挂载 C# 脚本到游戏物体 | 运行脚本 ) 中 , 双击 Unity 编辑器中的 Project 窗口中的 C# 脚本 , 进入到 Visual Studio 中出现下图样式 , 这是因为没有配置 Unity 编译环境 ;
韩曙亮
2023/03/30
3.1K0
【Unity3D】Unity 脚本 ② ( Visual Studio 2019 中的 Unity 编译环境配置 | Unity 编辑器关联外部 C# 脚本编辑器 Visual Studio )
【Unity3D】Android 打包 ③ ( Android 工程设置 | 打包 Apk 安装文件 | 配置项细节 | 运行效果 )
配置完编译选项后 , 还需要配置基本的 JDK , NDK , SDK 等工具 ;
韩曙亮
2023/03/30
1.2K0
【Unity3D】Android 打包 ③ ( Android 工程设置 | 打包 Apk 安装文件 | 配置项细节 | 运行效果 )
Unity3D开发入门教程(一)——搭建开发环境[通俗易懂]
五邑隐侠,本名关健昌,12年游戏生涯。 本教程以 Unity 3D + VS Code + C# + xlua 为例。
全栈程序员站长
2022/09/07
7K0
Unity3D开发入门教程(一)——搭建开发环境[通俗易懂]
【Unity3D】Android 打包 ① ( Android 编译选项 | 安装 Android Build Support 模块 )
在 Unity 编辑器中 , 选择 " 菜单栏 | File | Build Settings " 选项 ,
韩曙亮
2023/03/30
9750
【Unity3D】Android 打包 ① ( Android 编译选项 | 安装 Android Build Support 模块 )
Unity3D学习笔记(二) - Unity3D的许可证管理
安装完Unity3D后,需要申请许可证才能正常使用,官网对个人版提供了免费申请的服务,我们可以通过Hub界面的管理许可证来获取全新的许可证
云叶知秋
2021/02/01
1.9K0
Unity3D学习笔记(二) - Unity3D的许可证管理
unity安装使用教程_免费版签名
4、弹出账户登录界面,如果已有账户直接登录即可,没有账户的话最方便的就是直接用微信登录!
全栈程序员站长
2022/08/03
1.6K0
unity安装使用教程_免费版签名
【Unity3D】Unity 编辑器窗口布局 ( 创建 Unity3D 项目 | 添加物体 | 层级窗口 | 场景窗口 | 游戏窗口 | 属性窗口 | 项目窗口 | 控制台窗口 | 窗口位置修改 )
在 Unity Hub 界面 中 , 左侧选择 " 项目 " 面板 , 然后点击右上角的 " 新项目 " 按钮 ,
韩曙亮
2023/03/30
3.5K0
【Unity3D】Unity 编辑器窗口布局 ( 创建 Unity3D 项目 | 添加物体 | 层级窗口 | 场景窗口 | 游戏窗口 | 属性窗口 | 项目窗口 | 控制台窗口 | 窗口位置修改 )
Unity3D 入门:安装 Unity3D 并配置与 Visual Studio 的协作开发环境
实际上本文不看也罢,因为整个过程除了网速之外基本没啥坑。不过装完可能有一些配置,所以如果不知道的话可以参考本文。
walterlv
2023/10/22
2.9K0
Unity3D 入门:安装 Unity3D 并配置与 Visual Studio 的协作开发环境
Unity3D学习笔记(一) - Unity3D的安装
选定版本后,点击对应版本的从Hub下载按钮开始下载,从Hub下载类似一个Unity3D的下载器一样,可以定制自己的Unity3D用到的组件,个人推荐使用这种方式。
云叶知秋
2021/02/01
1.5K0
Unity3D学习笔记(一) - Unity3D的安装
【Unity3D】Unity 脚本 ① ( 创建 C# 脚本 | Visual Studio 2019 中打开 C# 脚本 | 编译 C# 脚本 | 挂载 C# 脚本到游戏物体 | 运行脚本 )
在 Project 窗口中的 Assets 目录下 , 创建 Scripts 目录用于存放 C# 脚本 ;
韩曙亮
2023/03/30
4.4K0
【Unity3D】Unity 脚本 ① ( 创建 C# 脚本 | Visual Studio 2019 中打开 C# 脚本 | 编译 C# 脚本 | 挂载 C# 脚本到游戏物体 | 运行脚本 )
Unity3D游戏开发入门引导:Unity3D收费方案和版本、下载地址、安装教程
Unity5.0(也称为Unity3D5.0或Unity pro5.0)是由Unity公司开发的一款跨平台游戏开发工具,用户可以通过此软件轻松创建出多种类型的互动内容,例如三维视频游戏、建筑可视化和实时三维动画等等。相比以前的版本,Unity pro5.0免费版功能更加强大,主要集中在音频、插件、网络、着色器和光照方面。在音频方面,Unity pro5.0重新编写了整个音频管道,新版本的音频效率更高、更灵活,其中最大的不同是它的混音器,可以帮助用户实现高度复杂的实时路由和效果场景。在插件方面,新版本增加了全新的WebGL插件,用户现在可以使用Unity pro5.0预览版本的WebGL插件,从而在浏览器中为无插件游戏创建交互体验。在网络方面,Unity pro5.0将发布全新的Unity Cloud交互推广网络,可以让用户在移动游戏开发过程中进行全屏插播式广告。在着色器方面,新版本新增了一个全新的内置着色器系统,可以在所有光照情况下涵盖多种真实材料。
学习牛牛
2023/04/15
9720
Unity3D游戏开发入门引导:Unity3D收费方案和版本、下载地址、安装教程
Unity3D安装_3D杀号APP
《Unity3D入门教程》会带领零基础的初学者,一步步学会使用Unity3D来开发简单的应用程序,走近游戏开发的世界。本系列教程虽然不会面面俱到地深入到全部的知识点,但是会涉及到所有入门阶段所需要掌握的必备技能。通过本教程的学习,可以快速“入门”。师傅领进门,修行在个人。当我们掌握了基本的框架和技能后,就可以自由选择自己喜欢的点去深入学习。本教程是博主自己学习Unity3D时候总结的学习笔记,基本能够涵盖住入门阶段所需要学习的点。希望能都对读者有哪怕那么一点点的帮助,也不枉敲了那么久的键盘,码了那么些字。Enjoy Unity3D!
全栈程序员站长
2022/09/22
3650
Unity3D安装_3D杀号APP
Unity 安装开发环境
点击“人像图标”,点击“登录”(无账号则点击“登录”上方“创建Unity ID”注册账号)
90后小陈老师
2024/08/27
1770
Unity 安装开发环境
游戏开发工具Unity3D 2023下载及图文安装教程+Unity3D 2023激活下载+安装包
Unity3D是一款跨平台游戏引擎,可以用于开发多种类型的游戏,包括2D和3D游戏。以下是一些Unity3D的功能和使用技巧:
用户10519170
2023/04/21
3.2K0
Unity3d的安装
第三步:来到UnityStore,拖到该页面的最底部,点击资源下面的Unity旧版本
全栈程序员站长
2022/09/14
8720
Unity3d的安装
Unity安装图文步骤「建议收藏」
最近因工作需要使用Unity实现一些动画效果,刚好也可以增长自己的技术硬实力,开始自学Unity之旅! 学习一门技术必不可少的就是要学会使用工具,所以下面记录一下我安装Unity工具的过程。
全栈程序员站长
2022/09/14
3.3K0
Unity安装图文步骤「建议收藏」
unity安装配置和vs2022联动教程
就是我们的这个unity里面的这个脚本的编写就是通过我们的vs2022实现的,因此这个时候如果我们之前就是用过这个vs2022但是没有勾选这个unity的选项的话,这个时候我们就需要重新的修改一下,把这个unity配置上去;
阑梦清川
2025/02/24
1400
unity安装配置和vs2022联动教程
Unity基础知识+Unity安装许可证【详细版】2022.5.6
文章目录 前言 unity基础知识 1️⃣打开unity hub 2️⃣管理许可证 3️⃣通过许可证请求 ---- 前言 提示:总的有两种方法: 1️⃣:获取免费的个人版许可证 2️⃣:通过许可证请求 💦效果一样,那种试用便用那个💦 个人在学习unity时,安装软件遇到的一些问题! 🥇个人主页:@MIKE笔记 🥈文章专栏:技术教程 unity基础知识 1、绑定脚本编辑器 点击顺序:Edit->preferences->External Tools->External Script Ed
MIKE笔记
2023/03/23
2.7K0
Unity基础知识+Unity安装许可证【详细版】2022.5.6
【Unity】入门级Unity安装教程
这是一篇面向对unity感兴趣,想要学习unity,但是还处于入门阶段的小伙伴的超详细unity安装教程。因为是面向入门的小伙伴,所以文章写的有点长,还配有许多图片,这样才能更详细的介绍安装流程。但是不必担心太长看起来太费劲,各位只要照着教程一步步来就可以了。跟着这章博文走,最终你的电脑一定能张开双臂,成功拥抱unity。那么,现在进入正题吧!
全栈程序员站长
2022/09/14
2K0
【Unity】入门级Unity安装教程
【Unity3D 问题总结】☀️ | 在Unity Hub中 许可证服务器连接失败 解决方案
在使用Unity的过程中偶然会出现 许可证服务器连接失败 这种情况而导致无法正常使用Unity
呆呆敲代码的小Y
2021/10/13
3.8K0
推荐阅读
【Unity3D】Unity 脚本 ② ( Visual Studio 2019 中的 Unity 编译环境配置 | Unity 编辑器关联外部 C# 脚本编辑器 Visual Studio )
3.1K0
【Unity3D】Android 打包 ③ ( Android 工程设置 | 打包 Apk 安装文件 | 配置项细节 | 运行效果 )
1.2K0
Unity3D开发入门教程(一)——搭建开发环境[通俗易懂]
7K0
【Unity3D】Android 打包 ① ( Android 编译选项 | 安装 Android Build Support 模块 )
9750
Unity3D学习笔记(二) - Unity3D的许可证管理
1.9K0
unity安装使用教程_免费版签名
1.6K0
【Unity3D】Unity 编辑器窗口布局 ( 创建 Unity3D 项目 | 添加物体 | 层级窗口 | 场景窗口 | 游戏窗口 | 属性窗口 | 项目窗口 | 控制台窗口 | 窗口位置修改 )
3.5K0
Unity3D 入门:安装 Unity3D 并配置与 Visual Studio 的协作开发环境
2.9K0
Unity3D学习笔记(一) - Unity3D的安装
1.5K0
【Unity3D】Unity 脚本 ① ( 创建 C# 脚本 | Visual Studio 2019 中打开 C# 脚本 | 编译 C# 脚本 | 挂载 C# 脚本到游戏物体 | 运行脚本 )
4.4K0
Unity3D游戏开发入门引导:Unity3D收费方案和版本、下载地址、安装教程
9720
Unity3D安装_3D杀号APP
3650
Unity 安装开发环境
1770
游戏开发工具Unity3D 2023下载及图文安装教程+Unity3D 2023激活下载+安装包
3.2K0
Unity3d的安装
8720
Unity安装图文步骤「建议收藏」
3.3K0
unity安装配置和vs2022联动教程
1400
Unity基础知识+Unity安装许可证【详细版】2022.5.6
2.7K0
【Unity】入门级Unity安装教程
2K0
【Unity3D 问题总结】☀️ | 在Unity Hub中 许可证服务器连接失败 解决方案
3.8K0
相关推荐
【Unity3D】Unity 脚本 ② ( Visual Studio 2019 中的 Unity 编译环境配置 | Unity 编辑器关联外部 C# 脚本编辑器 Visual Studio )
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验