专业编程基础技术教程

网站首页 > 基础教程 正文

通过JavaScript学习不变性(immutability)

ccvgpt 2024-07-19 12:49:51 基础教程 15 ℃

不可变值(immutability)是一旦创建,就无法更改的值。

Primitives(原始值)

原始值是不可变的,对象不是。

通过JavaScript学习不变性(immutability)

不可变原语的最佳示例是string。 对字符串的任何修改都将产生一个新字符串。 考虑下面的例子:

"ABCD".substring(1,3) //"BC"
"AB" + "CD" //"ABCD"
"AB".concat("CD") //"ABCD"

在所有这些情况下,都会创建新字符串。

Reading code

看看下一个代码:

const arr = [1,2,3];
doSomething(arr);
console.log(arr);
//[1,2,3] ?

我们可以轻易地说log()会将[1,2,3]打印到控制台吗? 不是的。 该数组是JavaScript中的可变数据结构。 它可以在doSomething()函数中更改。 我们需要阅读并理解doSomething()函数,以便说出将在控制台中记录的内容。

以下是改变数组的doSomething()函数示例:

function doSomething(arr){
 arr.push(4)
}

如果数组是一个不可变的数据结构,我们可以说在没有读取doSomething()函数的情况下将在控制台中记录什么。

Const

const声明一个无法重新分配的变量。 只有当赋值是不可变的时,它才会变为常量。

简而言之,使用带有原始值的const定义一个常量。 将const与对象值一起使用不一定定义常量。

const book = ({
 title : "JavaScript, The good parts",
 author : "Douglas Crockford"
});
book.title = "Other title";
console.log(book);

Freezing objects

要使对象不可变,我们需要冻结它们。 使数组不可变需要更多的纪律。

Object.freeze()可用于冻结对象。 无法添加,删除或更改属性。 对象变得不可变。

const book = Object.freeze({
 title : "How JavaScript Works",
 author : "Douglas Crockford"
});
book.title = "Other title";
//Cannot assign to read only property 'title'

Object.freeze()执行浅冻结。 嵌套对象可以更改。 对于深度冻结,我们需要递归地冻结类型对象的每个属性。 以下是我们如何创建deepFreeze()实现。

function deepFreeze(object) {
 Object.keys(object).forEach(function freezeNestedObjects(name){
 const value = object[name];
 if(typeof value === "object") {
 deepFreeze(value);
 }
 });
 return Object.freeze(object);
}

deepFreeze()不会使数组成为不可变的。 它使普通对象不可变。

使用不可变对象

将book视为不可变对象。 任何更改都需要创建一个新对象

Edit property

const title = "JavaScript The good parts"
const newBook = { ...book, title };

Add propery

const description = "Looking at JavaScript";
const newBook = { ...book, description };

Remove property

请参阅下文,如何使用解构语法创建没有title属性的新对象:

const { title, ...newBook } = book;

使用数组作为不可变的

数组数据结构在JavaScript中不是不可变的。 为了使用数组作为不可变数据结构,我们只需要使用纯数组方法和扩展运算符。 纯数组方法是在某些内容发生变化时创建新数组的方法。

  • pop(),push()和splice()都不是纯粹的
  • concat(),slice()是纯粹的
  • sort()应该是纯粹的

Add

以下是向不可变数组添加新值的示例:

const books = [ { title : "book1" }, { title : "book2"}];
//add with spread
const newBooks = [ ...books, newBook ];
//add with concat()
const newBooks = books.concat([newBook]);

Remove

以下是从位置索引中删除值的示例:

const newBooks = [...books.slice(0, index), 
 ...books.slice(index + 1)];

不可变的可用的库

Immutable.js (https://facebook.github.io/immutable-js/) 提供了不可变的数据结构,如List和Map。 这些数据结构经过高度优化。

让我们使用List数据结构。

Add

push(value)返回添加了新值的新List。

import { List, Map } from "immutable";
const aNewBook = { title: "book3" };
const books = List([{ title: "book1" }, { title: "book2" }]);
const newBooks = books.push(aNewBook);
newBooks.toArray();

Remove

remove(index)返回一个新的List,它排除索引位置的值。

const books = List([{ title: "book1" }, { title: "book2" }]);
const remainingBooks = books.remove(0);
remainingBooks.toArray();

接下来,让我们看一下Map:

const book = Map({
 title: "JavaScript, The good parts",
 author: "Douglas Crockford"
});
const title = "JavaScript The good parts"
const newBook = book.set("title", title);
console.log(newBook.toJS())

Tags:

最近发表
标签列表