如何检查对象是不是不可变?

Posted

技术标签:

【中文标题】如何检查对象是不是不可变?【英文标题】:How to check if object is Immutable?如何检查对象是否不可变? 【发布时间】:2015-11-01 15:41:45 【问题描述】:

不可变对象可以是以下实例:

Immutable.List Immutable.Map Immutable.OrderedMap Immutable.Set Immutable.OrderedSet Immutable.Stack

【问题讨论】:

我假设有一种比instanceof 对每种类型都更友好的方法。 【参考方案1】:

Immutable.js 自 v4.0.0-rc.1 起具有isImmutable() 功能:

 import  isImmutable, Map, List, Stack  from 'immutable';

 isImmutable([]); // false
 isImmutable(); // false
 isImmutable(Map()); // true
 isImmutable(List()); // true
 isImmutable(Stack()); // true
 isImmutable(Map().asMutable()); // false

如果您使用以前的版本之一,您可以通过这种方式检查对象是否不可变:

 Immutable.Iterable.isIterable(YOUR_ENTITY)

因为所有不可变对象都继承自 Iterable 对象

【讨论】:

这在 3.8.1 中不可用 谁知道如何在他们的官方网站上查看以前版本的API文档? @Romasato - 也许不理想,但我可以在 github 上查看旧版本的文档源,例如3.8.2:github.com/facebook/immutable-js/blob/v3.8.2/type-definitions/…【参考方案2】:

这在某些情况下可能有效:

typeof object.toJS === 'function'

例如,如果您检查不可变对象与普通对象 (json),则可以使用这种鸭式键入方法。

【讨论】:

为什么不呢?请发表评论。 因为这通过了你的测试:const notImmutable = toJS: () => 'nope!' ; @KenGregory,没错,但实际上它仍然可以工作几年) 您提供了这个答案并问“为什么不呢?请发表评论”所以我做到了。您的答案不如其他答案的原因是因为它不够好。 @KenGregory,同意,这并不完美,这就是我写“这在某些情况下可能有效”的原因。无论如何,谢谢你的评论!现在,至少,“减号”是合理的。【参考方案3】:

有一张到improve the API 的公开票在 4.0 的路线图上。在此之前,我建议您使用Immutable.Iterable.isIterable() (docs)。

使用instanceof 是not reliable(例如,当不同的模块使用不同的 Immutable.js 副本时返回 false)

【讨论】:

假设我无权访问Immutable 本身(只是我想检查的对象的一个​​实例,比如在第三方库中)正在使用item.asImmutable && item.asImmutable() === item 一个合理的代理?这似乎适用于Immutable.Map/List,并且感觉比item.__proto__['@@__IMMUTABLE_MAP__@@'] 更强大【参考方案4】:

检查特定类型通常会在以后引起更多工作。通常我会等待通过检查 Map 或 List 来锁定类型,但是......

我在这里的动机主要是我对未定义便便的调用 .get 本身非常困难,并且在整个地方正确初始化会有所帮助,但并不能捕捉所有边缘情况。我只想要数据或未定义而没有任何破损。如果我希望它进行更改,特定的类型检查会导致我稍后做更多的工作。

这个更宽松的版本解决了比特定类型检查更多的边缘情况(如果不是全部的话,大多数扩展类型 Iterable 都有 .get,并且所有数据最终都会得到)(这通常只会在您尝试更新类型错误等)。

/* getValid: Checks for valid ImmutableJS type Iterable

    returns valid Iterable, valid Iterable child data, or undefined

    Iterable.isIterable(maybeIterable) && maybeIterable.get(['data', key], Map()), becomes
    getValid(maybeIterable, ['data', key], Map())

    But wait! There's more! As a result:
    getValid(maybeIterable) returns the maybeIterable or undefined 
    and we can still say getValid(maybeIterable, null, Map()) returns the maybeIterable or Map()            */

export const getValid = (maybeIterable, path, getInstead) =>
  Iterable.isIterable(maybeIterable) && path
    ? ((typeof path === 'object' && maybeIterable.getIn(path, getInstead)) || maybeIterable.get(path, getInstead))
    : Iterable.isIterable(maybeIterable) && maybeIterable || getInstead;


//Here is an untested version that a friend requested. It is slightly easier to grok.

export const getValid = (maybeIterable, path, getInstead) => 
  if(valid(maybeIterable))                  // Check if it is valid
    if(path)                                         // Check if it has a key
      if(typeof path === 'object')      // Check if it is an 'array'
        return maybeIterable.getIn(path, getInstead) // Get your stuff
       else 
        maybeIterable.get(path, getInstead)          // Get your stuff
      
     else 
      return maybeIterable || getInstead;                 // No key? just return the valid Iterable
    
   else 
    return undefined;                       // Not valid, return undefined, perhaps should return false here
  

只要给我我想要的,或者告诉我不。不要爆炸。我相信 underscore 也有类似的作用。

【讨论】:

【参考方案5】:

这样你就可以知道Immutable Iterable变量是什么类型的:

const obj0 = 'xxx';
const obj1 = Immutable.fromJS(x: 'XXX', z: 'ZZZ');
const obj2 = Immutable.fromJS([ x: 'XXX', z: 'ZZZ']);

const types = ['List', 'Stack', 'Map', 'OrderedMap', 'Set', 'OrderedSet'];
const type0 = types.find(currType => Immutable[currType][`is$currType`](obj0));
const type1 = types.find(currType => Immutable[currType][`is$currType`](obj1));
const type2 = types.find(currType => Immutable[currType][`is$currType`](obj2));

console.log(`Obj0 is: $type0`); // Obj0 is: undefined
console.log(`Obj1 is: $type1`); // Obj1 is: Map
console.log(`Obj2 is: $type2`); // Obj2 is: List
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

【讨论】:

【参考方案6】:

我了解到using instanceof to determine wether object is Immutable 不安全:

模块 A:

var Immutable = require('immutable');
module.exports = Immutable.Map(foo: "bar);

模块 B:

var Immutable = require('immutable');
var moduleA = require('moduleA');
moduleA instanceof Immutable.Map // will return false

Immutable.js API 定义了以下方法来检查 object 是否是 Immutable 的实例:

Map.isMap() List.isList() Stack.isStack() OrderedMap.isOrderedMap() Set.isSet() OrderedSet.isOrderedSet()

Iterable.isIterable()

后者检查是否:

如果是 Iterable 或其任何子类,则为真。

ListStackMapOrderedMapSetOrderedSet 都是 Iterable 的子类。

【讨论】:

以上是关于如何检查对象是不是不可变?的主要内容,如果未能解决你的问题,请参考以下文章

java中是啥是不可变对象和可变对象

DDD 中的值对象 - 为啥是不可变的?

如何更改不可变对象的值

“不可变的对象”与“不可变的对象引用”

java不可变类和不可变对象

ReadonlyCollection,对象是不可变的吗?