nodeJS提供一组assert断言函数,用于验证不变量。

断言类似于布尔值的判断,不同点是断言其实是防止程序意外出错的一种宏,如果其参数计算为假,则程序发出警告,且退出也就是终止程序。这和if语句是不同的。日常开发中基本很少用到断言模块,除非你在写单元测试,其中会涉及到一些断言的语法。

assert是node官方模块包,不需要安装,直接引入即可。

const assert = require('assert');

assert提供的方法都是静态的,可以直接调用。比如assert.ok直接接收一个布尔值,当值为假的时候断言不通过,并且抛出异常。

assert.ok(false);
// assert(false);
AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:

  assert.ok(false)

    at Object.<anonymous> (/Users/choice/Documents/person/blog/test.js:3:8)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

用于比较两个值是否相等,是一种不严格的比较,除 NaN 之外,其他值均使用==来比较原始值,所以比较中会出现一些奇怪的问题。

如果对比的双方均为 NaN,则视为相同。如果是对象,则要求对象的类型标签应该相同。只考虑可枚举的自身属性。如果是Error则会始终比较 Error 的名称和消息,即使这些不是可枚举的属性。对象封装器作为对象和解封装后的值都进行比较。Object 属性的比较是无序的。Map 键名与 Set 子项的比较是无序的。当两边的值不相同或遇到循环引用时,递归停止。不测试对象的 [[Prototype]]。可枚举的自身 Symbol 属性也会比较。WeakMap 和 WeakSet 的比较不依赖于它们的值。

assert.deepEqual('+00000000', false);
// '+00000000' 会变为false 导致相等

在新版本的nodeJS中推荐使用assert.deepStrictEqual代替assert.deepEqual,意为严格模式的断言。

assert.deepStrictEqual使用使用 Object.is()来比较原始值,对象的类型标签应该相同。使用严格相等比较来比较对象的原型。同样也只考虑可枚举的自身属性。始终比较 Error 的名称和消息,即使这些不是可枚举的属性。可枚举的自身 Symbol 属性也会比较。对象封装器作为对象和解封装后的值都进行比较。Object 属性的比较是无序的。Map 键名与 Set 子项的比较是无序的。当两边的值不相同或遇到循环引用时,递归停止。WeakMap 和 WeakSet 的比较不依赖于它们的值。

const assert = require('assert').strict;

// 失败,因为 1 !== '1'。
assert.deepStrictEqual({ a: 1 }, { a: '1' });

// 以下对象没有自身属性。
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);

// 原型不同:
assert.deepStrictEqual(object, fakeDate);
// 类型标签不同:
assert.deepStrictEqual(date, fakeDate);
// + 2018-04-26T00:49:08.604Z
// - Date {}

assert.deepStrictEqual(NaN, NaN);
// 通过,因为使用 SameValue 比较。

// 解封装后的数字不同:
assert.deepStrictEqual(new Number(1), new Number(2));


assert.deepStrictEqual(new String('foo'), Object('foo'));
// 通过,因为对象与解封装后的字符串都是相同的。

assert.deepStrictEqual(-0, -0);
// 通过。

// 使用 SameValue 比较的零不同:
assert.deepStrictEqual(0, -0);

const symbol1 = Symbol();
const symbol2 = Symbol();

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// 通过,因为在两个对象上的 symbol 相同。

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });

const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap([[{}, {}]]);
const weakMap3 = new WeakMap();
weakMap3.unequal = true;

assert.deepStrictEqual(weakMap1, weakMap2);
// 通过,因为无法比较条目。

// 失败,因为 weakMap3 有一个 weakMap1 不包含的属性:
assert.deepStrictEqual(weakMap1, weakMap3);

测试深度严格的不平等。 与 assert.deepStrictEqual()获得的结果相反相反。

const assert = require('assert').strict;

assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// 通过。

接收两个参数,第一个参数是字符串,第二个参数是正则,当不匹配时通过。

const assert = require('assert').strict;

assert.doesNotMatch('I will fail', /fail/);
// 不通过
assert.doesNotMatch(123, /pass/);
// 第一个参数必须是字符串
assert.doesNotMatch('I will pass', /different/);
// 通过

接收两个参数,第一个参数是字符串,第二个参数是正则,当匹配时通过。

const assert = require('assert').strict;
assert.match('I will fail', /pass/);
// 不通过
assert.match(123, /pass/);
// 第一个参数必须是字符串
assert.match('I will pass', /pass/);
// 通过

使用提供的错误消息或默认错误消息抛出 AssertionError。 如果 message 参数是 Error 的实例,则它将被抛出而不是 AssertionError

const assert = require('assert').strict;

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('失败');
// AssertionError [ERR_ASSERTION]: 失败

assert.fail(new TypeError('需要数组'));
// TypeError: 需要数组

如果接收的值 不为 undefined 或 null,则抛出 该值。 在回调中测试 error 参数时,这很有用。 堆栈跟踪包含传递给 ifError() 的错误的所有帧,包括 ifError() 本身的潜在新帧。

const assert = require('assert').strict;

assert.ifError(null);
// 通过。
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('错误');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: '错误'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error

// 创建一些随机错误帧。
let err;
(function errorFrame() {
  err = new Error('测试错误');
})();

(function ifErrorFrame() {
  assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 测试错误
//     at ifErrorFrame
//     at errorFrame

接收两个参数,测试两个参数之间的严格不相等

const assert = require('assert').strict;

assert.notStrictEqual(1, 2);
// 通过。
assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1
assert.notStrictEqual(1, '1');
// 通过。

比较两个值的严格相等

const assert = require('assert').strict;
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
//          ^

const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical

其实断言这种东西日常开发中真的很少用到,不了解也不要紧,不会影响我们日常的工作开发,了解他可以让我们写出一些更加优雅的代码,当然这些代码也仅限于NodeJS,常规的Web开发中如果引入断言也可能成为一种负担。