在JavaScript中是否有标准函数来检查null、undefined或空变量?

3053

是否有一种通用的JavaScript函数,可以检查变量是否具有值,并确保它不是undefinednull?我有这段代码,但我不确定它是否涵盖了所有情况:

function isEmpty(val){
    return (val === undefined || val == null || val.length <= 0) ? true : false;
}

6
可能是如何在JavaScript中检查空字符串?的重复问题。 - Dour High Arch
191
提示,永远不要写成(truthy statement) ? true : false;。直接写成(truthy statement);即可。 - David Baucum
11
@GeorgeJempty并不是重复的,因为另一个答案特别提到了“字符串”,而这个问题是关于“变量”的。请注意,此处仅进行翻译,不涉及任何解释或其他内容。 - Madbreaks
4
对于这个问题的任何正确答案完全依赖于你如何定义“空白”。 - Madbreaks
7
@Jay,这并不会影响您代码的执行,只是过于冗长。就像您不会说,“Is are you hungry is true?” 而是 “Are you hungry?”所以在代码中只需使用 if (hungry) … 而不是 if (hungry === true) …。就像所有编码风格一样,这只是个人审美问题。更具体地说,对于 OP 提供的例子,他更冗长地表达了“如果它为真,则为真,如果不为真,则为假”,但如果它为真,则已经是真的。如果它为假,则已经是假的。这相当于说:“如果你饿了,那么你就饿了,如果不饿,那么你就不饿。” - David Baucum
显示剩余11条评论
47个回答

21

你有点过度了。为了检查一个变量是否没有被赋值,你只需要检查它是否等于undefined和null。

function isEmpty(value){
    return (typeof value === "undefined" || value === null);
}

假设 0"" 和对象(甚至是空对象和数组)都是有效的“值”。


1
松散比较与 null 的比较一直都具有这种确切的行为;这个函数等同于你的函数:let isEmpty = val => val == null; - Gershom Maes

20

空值

我不建议尝试定义或使用一个计算整个世界中任何值是否为空的函数。什么才是真正的“空”呢?如果我有 let human = { name: 'bob', stomach: 'empty' },那么isEmpty(human)应该返回true吗?如果我有let reg = new RegExp('');,那么isEmpty(reg)应该返回true吗?那么isEmpty([ null, null, null, null ])呢?这个列表只包含空值,那么这个列表本身是否为空呢?我想在这里提出一些关于JavaScript中“vacuousness”的注解(故意使用模糊的词语以避免先前存在的关联),并且我想主张:我们永远不应该用通用方式处理JavaScript值中的“vacuousness”。


真值/假值

为了确定值的“vacuousness”,我们需要适应JavaScript内置、固有的感知值是“truthy”还是“falsy”。自然地,nullundefined都是“falsy”的。较为不自然的是数字0(没有其他数字除了NaN)也是“falsy”的。最不自然的是:''是“falsy”的,但[]{}(以及new Set()new Map())都是“truthy”的-尽管它们看起来都一样空!


null与undefined的区别

还有一些关于nullundefined的讨论-我们是否真的需要两者来表达程序中的“vacuousness”?我个人避免在代码中出现undefined。我总是使用null表示“vacuousness”。尽管如此,我们仍然需要适应JavaScript内置的感知方式,即nullundefined的区别:

  • 试图访问不存在的属性会返回undefined
  • 调用函数时省略参数会导致该参数接收到undefined

let f = a => a;
console.log(f('hi'));
console.log(f());

  • 当给定的参数是undefined时,具有默认值的参数才会接收默认值,而不是null

let f = (v='hello') => v;
console.log(f(null));
console.log(f(undefined));

对我而言,null 是一种明确的空值标识符;“本应填写的内容被有意留空”。实际上,undefined 是一种必要的复杂性,允许某些 JavaScript 特性存在,但在我看来,它应该始终留在幕后,不直接与之交互。我们可以将 undefined 看作是 JavaScript 实现默认函数参数的机制。如果您不向函数提供参数,那么它将接收一个值为 undefined 的参数。如果该参数最初设置为 undefined,则会应用默认值到函数参数中。在这种情况下,undefined 是默认函数参数的关键,但它仍然处于后台:我们可以在不引用 undefined 的情况下实现默认参数功能。

以下是一种与 undefined 直接交互的糟糕默认参数实现:

let fnWithDefaults = arg => {
  if (arg === undefined) arg = 'default';
  ...
};

这是一个很好的实现:

let fnWithDefaults = (arg='default') => { ... };

这是一种不好的接受默认参数的方式:

fnWithDefaults(undefined);

只需这样做:
fnWithDefaults();

你是否有一个带有多个参数的函数,同时想要为某些参数提供值,而对于其他参数则接受默认值?

例如:

let fnWithDefaults = (a=1, b=2, c=3, d=4) => console.log(a, b, c, d);

如果你想为 ad 提供值,并接受其他参数的默认值,应该怎么做?这似乎是错误的:
fnWithDefaults(10, undefined, undefined, 40);

答案是:重构fnWithDefaults以接受一个单一的对象:
let fnWithDefaults = ({ a=1, b=2, c=3, d=4 }={}) => console.log(a, b, c, d);
fnWithDefaults({ a: 10, d: 40 }); // Now this looks really nice! (And never talks about "undefined")

非泛化的空值

我认为我们不应该以泛化的方式处理空值。相反,我们应该始终具有严谨性,在确定数据是否为空值之前获取更多信息 - 我主要通过检查我正在处理的数据类型来实现这一点:

let isType = (value, Cls) => {
  // Intentional use of loose comparison operator detects `null`
  // and `undefined`, and nothing else!
  return value != null && Object.getPrototypeOf(value).constructor === Cls;
};

请注意,此函数会忽略继承 - 它期望valueCls的直接实例,而不是Cls的子类的实例。我避免使用instanceof有两个主要原因:
  • ([] instanceof Object) === true (“数组是对象”)
  • ('' instanceof String) === false (“字符串不是字符串”)
请注意,Object.getPrototypeOf用于避免(晦涩的)边缘情况,例如let v = { constructor: String }; 对于isType(v, String)(false)和isType(v, Object)(true),isType函数仍然返回正确值。
总体而言,我建议使用这个isType函数以及以下提示:
  • 尽量减少处理未知类型值的代码量。例如,对于let v = JSON.parse(someRawValue);,我们的v变量现在是未知类型。尽早限制可能性是最好的方式。最好的方法是通过要求特定类型来实现:例如if (!isType(v, Array)) throw new Error('Expected Array'); - 这是一种非常快速和表达力强的方式,可以消除v的通用性,并确保它始终是一个Array。但有时候,我们需要允许v具有多种类型。在这些情况下,我们应该尽早创建代码块,在其中v不再是通用的:

if (isType(v, String)) {
  /* v isn't generic in this block - It's a String! */
} else if (isType(v, Number)) {
  /* v isn't generic in this block - It's a Number! */
} else if (isType(v, Array)) {
  /* v isn't generic in this block - it's an Array! */
} else {
  throw new Error('Expected String, Number, or Array');
}

  • 始终使用“白名单”进行验证。 如果您需要一个值是字符串、数字或数组,请检查这三个“白色”可能性,并在没有满足这三个条件时抛出错误。我们应该能够看到检查“黑色”可能性并不是非常有用的:假设我们编写了if (v === null) throw new Error('Null value rejected'); - 这很好,可以确保null值不会被通过,但如果一个值确实被通过了,我们仍然几乎不知道它的任何信息。通过这个null-check的值v仍然非常通用 - 它是除了null之外的任何东西!黑名单几乎无法消除通用性。
  • 除非一个值是null,否则永远不要考虑“空值”。相反,考虑“一个为空的X”。 实际上,永远不要考虑做任何类似于if (isEmpty(val)) { /* ... */ }的事情 - 无论这个isEmpty函数如何实现(我不想知道...),它都是没有意义的!而且它太过通用了!只有了解val的类型,才能计算它是否为空。检查空值应该像这样:
    • “一个没有字符的字符串”:if (isType(val, String) && val.length === 0) ...

    • “一个没有属性的对象”:if (isType(val, Object) && Object.entries(val).length === 0) ...

    • “一个小于等于零的数字”:if (isType(val, Number) && val <= 0) ...

    • “一个没有项目的数组”:if (isType(val, Array) && val.length === 0) ...

    • 唯一的例外是当null用于表示某些功能时。在这种情况下,说“一个空值”是有意义的:if (val === null) ...


14

可能最简短的答案是

val==null || val==''

如果你将右边改为val === '',那么空数组将会返回false。证明如下:

function isEmpty(val){
    return val==null || val==''
}

// ------------
// TEST
// ------------

var log = (name,val) => console.log(`${name} -> ${isEmpty(val)}`);

log('null', null);
log('undefined', undefined);
log('NaN', NaN);
log('""', "");
log('{}', {});
log('[]', []);
log('[1]', [1]);
log('[0]', [0]);
log('[[]]', [[]]);
log('true', true);
log('false', false);
log('"true"', "true");
log('"false"', "false");
log('Infinity', Infinity);
log('-Infinity', -Infinity);
log('1', 1);
log('0', 0);
log('-1', -1);
log('"1"', "1");
log('"0"', "0");
log('"-1"', "-1");

// "void 0" case
console.log('---\n"true" is:', true);
console.log('"void 0" is:', void 0);
log(void 0,void 0); // "void 0" is "undefined" - so we should get here TRUE

关于==的更多细节(源自这里

Enter image description here

BONUS: 为什么=====更清晰

Enter image description here

为编写清晰易懂的代码,请使用明确列出可接受值的列表

val===undefined || val===null || val===''|| (Array.isArray(val) && val.length===0)

function isEmpty(val){
    return val===undefined || val===null || val==='' || (Array.isArray(val) && val.length===0)
}

// ------------
// TEST
// ------------

var log = (name,val) => console.log(`${name} -> ${isEmpty(val)}`);

log('null', null);
log('undefined', undefined);
log('NaN', NaN);
log('""', "");
log('{}', {});
log('[]', []);
log('[1]', [1]);
log('[0]', [0]);
log('[[]]', [[]]);
log('true', true);
log('false', false);
log('"true"', "true");
log('"false"', "false");
log('Infinity', Infinity);
log('-Infinity', -Infinity);
log('1', 1);
log('0', 0);
log('-1', -1);
log('"1"', "1");
log('"0"', "0");
log('"-1"', "-1");

// "void 0" case
console.log('---\n"true" is:', true);
console.log('"void 0" is:', void 0);
log(void 0,void 0); // "void 0" is "undefined" - so we should get here TRUE


有用的可视化!它们的来源是什么? - viam0Zah
1
@viam0Zah 源代码链接在下面的片段中 --> (这里是源代码链接) - Kamil Kiełczewski
如果 val 的类型是字符串,那么是否被赋值为 "undefined"? - Victor

12

以下是我的代码 - 如果值为null、undefined等或为空(即只包含空格),则返回true:

function stringIsEmpty(value) {

    return value ? value.trim().length == 0 : true;

}

1
我在这里测试了几种方法。通过检查未定义,您的函数运行良好。因此,我使用if(typeof value !== 'undefined' && !IsEmpty(value)),或者如果您实际上想要检查空值,可以使用if(typeof value === 'undefined' || IsEmpty2(value))。这将适用于null;未定义;0;"";" ";false。 - RationalRabbit

10
如果您更喜欢使用纯JavaScript,请尝试以下代码:
  /**
   * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
   * length of `0` and objects with no own enumerable properties are considered
   * "empty".
   *
   * @static
   * @memberOf _
   * @category Objects
   * @param {Array|Object|string} value The value to inspect.
   * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
   * @example
   *
   * _.isEmpty([1, 2, 3]);
   * // => false
   *
   * _.isEmpty([]);
   * // => true
   *
   * _.isEmpty({});
   * // => true
   *
   * _.isEmpty('');
   * // => true
   */

function isEmpty(value) {
    if (!value) {
      return true;
    }
    if (isArray(value) || isString(value)) {
      return !value.length;
    }
    for (var key in value) {
      if (hasOwnProperty.call(value, key)) {
        return false;
      }
    }
    return true;
  }

否则,如果您已经在使用 underscore 或 lodash,请尝试:
_.isEmpty(value)

3
我尝试了你的代码。在控制台中收到了一个错误消息,上面写着:“未捕获的引用错误:isArray()未定义”。如果能正常工作就太好了。 - crmprogdev
12
至少在lodash这个库中,_.isNil是你要寻找的函数,而不是_.isEmptyisNil文档isEmpty文档 - Snixtor
1
如果值是布尔类型且为true,则此操作将失败。 - kalyanbk
3
зәҜ JavaScript еңЁ window дёҠжІЎжңү isArray жҲ– isString еҮҪж•°гҖӮ - GFoley83
@GFoley83 - 你抓住我了!我有自己不使用Windows的理由。实际上,在探讨软件语言的历史和进展的章节中,我已经涵盖了这个话题。更相关的信息可能会出现在我所著的《Go语言函数式编程》一书中介绍Monad错误处理的讨论/代码中。干杯! - l3x
4
@l3x:那是开玩笑吗? - Ry-

8
return val || 'Handle empty variable'

使用这种方法能够在很多地方更加清晰简洁地处理。同时,也可以用于变量的赋值。

const res = val || 'default value'

很多地方都可以,但默认值为true且您正在尝试提供或返回falseval时不行。 - Molomby
@Molomby,这是一个非常特殊的边缘情况,但即使如此也很容易处理。 const res = falsyValue ? true : falsyValue - cubefox

7

如果变量没有被声明,你将无法使用函数测试未定义的变量,因为会出现错误。

if (foo) {}
function (bar) {}(foo)

如果foo没有被声明,两者都会生成错误。

如果您想测试变量是否已声明,可以使用

typeof foo != "undefined"

如果你想测试 foo 是否已经被声明并且有一个值,可以使用以下方法:

if (typeof foo != "undefined" && foo) {
    //code here
}

7
你可以使用nullish coalescing运算符??来检查nullundefined值。请参阅MDN文档
null ?? 'default string'; // returns "default string"

0 ?? 42;  // returns 0

(null || undefined) ?? "foo"; // returns "foo"

6

这可能会有用。

数组中的所有值都代表您想要的内容(null、undefined或其他内容),您需要在其中搜索您想要的内容。

var variablesWhatILookFor = [null, undefined, ''];
variablesWhatILookFor.indexOf(document.DocumentNumberLabel) > -1

2
请解释一下,请问发生了什么? - JoshKisb
该数组包含一些您认为为空的变量。 - ddagsan
@JoshKisb 数组中的所有值都代表你想要的内容(null、undefined 或其他内容),你可以在其中搜索你想要的内容。 - ddagsan
2
@ddagsan,虽然JoshKisb可能会感谢您的回复,但您应该将您的解释放在答案中而不是评论中。 - Nick stands with Ukraine

6
function isEmpty(obj) {
    if (typeof obj == 'number') return false;
    else if (typeof obj == 'string') return obj.length == 0;
    else if (Array.isArray(obj)) return obj.length == 0;
    else if (typeof obj == 'object') return obj == null || Object.keys(obj).length == 0;
    else if (typeof obj == 'boolean') return false;
    else return !obj;
}

在ES6中,使用trim函数处理空格字符串:

const isEmpty = value => {
    if (typeof value === 'number') return false
    else if (typeof value === 'string') return value.trim().length === 0
    else if (Array.isArray(value)) return value.length === 0
    else if (typeof value === 'object') return value == null || Object.keys(value).length === 0
    else if (typeof value === 'boolean') return false
    else return !value
}

1
伟大的函数,谢谢!可以处理所有类型的值——所有其他解决方案中都排除了数字! - Fabian von Ellerts
2
@FabianvonEllerts 请不要试图将其他代码编辑到别人的答案中。请将其作为您自己的答案发布,作为答案下的评论,或在评论中请求他们自行更新答案。 - TylerH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接