当 class 包含函数时,如何比较两个 class 实例

How can I compare two class instances when the class contains functions

如果我有一个包含函数的 ES6 class,两个相同的实例不会被 chai deepEqual 考虑。在这种情况下比较实例的正确方法是什么。

例如给出这个 class 定义

class Foo {
  x;

  constructor(x) {
    this.x = x;
  }

  y = () => x*2;
}

前两个测试通过但第三个失败

describe('class equality', function() {
  it('compare single instance', function() {
    var foo = new Foo(1);
    assert.deepEqual(foo, foo);
  });

  it('compare string', function() {
    assert.deepEqual(JSON.stringify(new Foo(1)), JSON.stringify(new Foo(1)));
  });

  it('compare instance', function() {
    assert.deepEqual(new Foo(1), new Foo(1));
  });
});

在此处演示(也 on jsFiddle - 注释掉第 12 行并且所有三个测试都通过:

mocha.setup('bdd');

var assert = chai.assert;

class Foo {
  x;

  constructor(x) {
    this.x = x;
  }
  
  y = () => x*2;
}
  
describe('class equality', function() {
 it('compare single instance', function() {
    var foo = new Foo(1);
    assert.deepEqual(foo, foo);
  });

 it('compare string', function() {
    assert.deepEqual(JSON.stringify(new Foo(1)), JSON.stringify(new Foo(1)));
  });

 it('compare instance', function() {
    assert.deepEqual(new Foo(1), new Foo(1));
  });
});

mocha.run();
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.css" rel="stylesheet"/>

<div id="mocha"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.js"></script>

首先,让我们明确一点:这不是 ES6 class。那是一个 ES6(正式的,ES2015+)class加上一个class字段。 Class 字段还不是语言的一部分;当我在 2017 年 10 月写这篇文章时,他们是 Stage 3 proposal。你的

y = () => x*2;

...通过即将添加(可能)的语法向实例添加 enumerable 属性。 (和顶部附近的 x; 一样。)它应该使用 this:

y = () => this.x*2;
// -------^^^^^

Chai 显然是在比较所有 enumerable 属性,即使它们是函数。您可以通过 Object.definePropertyy 添加为 不可枚举 属性(或者,有一天,在 class 字段;现在,它们只是构造函数中的阶段 2):

Object.defineProperty(this, "y", {
  value: () => this.x * 2
});

更新的代码段:

mocha.setup('bdd');

var assert = chai.assert;

class Foo {
  x;

  constructor(x) {
    this.x = x;
    Object.defineProperty(this, "y", {
      value: () => this.x * 2
    });
  }
}
  
describe('class equality', function() {
 it('compare single instance', function() {
    var foo = new Foo(1);
    assert.deepEqual(foo, foo);
  });

 it('compare string', function() {
    assert.deepEqual(JSON.stringify(new Foo(1)), JSON.stringify(new Foo(1)));
  });

 it('compare instance', function() {
    assert.deepEqual(new Foo(1), new Foo(1));
  });
});

mocha.run();

console.log(new Foo(4).y());
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.css" rel="stylesheet"/>

<div id="mocha"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.js"></script>

就是说,y 是代替原型的完美候选者,这也解决了问题:

mocha.setup('bdd');

var assert = chai.assert;

class Foo {
  x;

  constructor(x) {
    this.x = x;
  }
  
  y() {
    return this.x * 2;
  }
}
  
describe('class equality', function() {
 it('compare single instance', function() {
    var foo = new Foo(1);
    assert.deepEqual(foo, foo);
  });

 it('compare string', function() {
    assert.deepEqual(JSON.stringify(new Foo(1)), JSON.stringify(new Foo(1)));
  });

 it('compare instance', function() {
    assert.deepEqual(new Foo(1), new Foo(1));
  });
});

mocha.run();
<link href="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.css" rel="stylesheet"/>

<div id="mocha"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/2.3.4/mocha.js"></script>