关于javascript:对象是空的吗?

Is object empty?

本问题已经有最佳答案,请猛点这里访问。

检查对象是否为空的最快方法是什么?

有没有比这更快更好的方法:

1
2
3
4
5
6
7
8
function count_obj(obj){
    var i = 0;
    for(var key in obj){
        ++i;
    }

    return i;
}


对于ecmascript5(虽然在所有浏览器中都不支持),您可以使用:

1
Object.keys(obj).length === 0


我假设,空的意思是"没有它自己的属性"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Speed up calls to hasOwnProperty
var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

    // null and undefined are"empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // If it isn't an object at this point
    // it is empty, but it can't be anything *but* empty
    // Is it empty?  Depends on your application.
    if (typeof obj !=="object") return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return false;
    }

    return true;
}

实例:

1
2
3
4
5
6
7
8
9
10
isEmpty(""), // true
isEmpty(33), // true (arguably could be a TypeError)
isEmpty([]), // true
isEmpty({}), // true
isEmpty({length: 0, custom_property: []}), // true

isEmpty("Hello"), // false
isEmpty([1,2,3]), // false
isEmpty({test: 1}), // false
isEmpty({length: 3, custom_property: [1,2,3]}) // false

如果只需要处理ecmascript5浏览器,可以使用Object.getOwnPropertyNames而不是hasOwnProperty循环:

1
if (Object.getOwnPropertyNames(obj).length > 0) return false;

这将确保即使对象只有不可枚举的属性,isEmpty仍将为您提供正确的结果。


编辑:请注意,您可能应该使用ES5解决方案,而不是这个,因为ES5支持现在很普遍。但它仍然适用于jquery。

简单而跨浏览器的方式是使用jQuery.isEmptyObject

1
2
3
4
if ($.isEmptyObject(obj))
{
    // do something
}

更多:http://api.jquery.com/jquery.isEmptyObject/

不过,您需要jquery。


如果您不介意添加额外的库,那么下划线和lodash都有一个方便的isEmpty()函数。

1
_.isEmpty({});


让我们把这个婴儿放到床上;在node、chrome、firefox和ie 9下测试,很明显对于大多数用例:

  • (对于…在…)是最快的选择使用!
  • object.keys(obj).length对于空对象来说慢10倍
  • stringify(obj).length总是最慢的(不足为奇)
  • object.getownprotynames(obj).length比object.keys(obj)长。在某些系统上,length可以长很多。

底线性能,使用:

1
2
3
4
function isEmpty(obj) {
   for (var x in obj) { return false; }
   return true;
}

1
2
3
4
function isEmpty(obj) {
   for (var x in obj) { if (obj.hasOwnProperty(x))  return false; }
   return true;
}

节点下的结果:

  • 第一个结果:return (Object.keys(obj).length === 0)
  • 第二个结果:for (var x in obj) { return false; }...
  • 第三个结果:for (var x in obj) { if (obj.hasOwnProperty(x)) return false; }...
  • 第四个结果:return ('{}' === JSON.stringify(obj))

使用0键测试对象零点零零零一八零点零零零零一五零点零零零零一五零点零零零三二四

用1个键测试对象零点零零零三四六零点零零零四五八零点零零零五七七零点零零零六五七

用2个键测试对象零点零零零三七五零点零零零四六零点零零零五六五零点零零零七七三

用3个键测试物体零点零零零四零六零点零零零四七六零点零零零五七七零点零零零九零四

用4个键测试物体零点零零零四三五零点零零零四八七零点零零零五八九零点零零一零三一

用5个键测试物体零点零零零四六五零点零零零五零一零点零零零六零四零点零零一一四八

用6个键测试物体零点零零零四九二零点零零零五一一零点零零零六一八零点零零一二六九

用7个键测试物体零点零零零五二八零点零零零五二七零点零零零六三七零点零零一三八

用8个键测试物体零点零零零五六五零点零零零五三八零点零零零六四七零点零零一五九

用100个键测试物体零点零零三七一八零点零零二四三零点零零二五三五零点零一三八一

用1000键测试物体零点零三三七零点零一九三零点零一九四零点一三三七

请注意,如果您的典型用例使用很少的键测试一个非空对象,并且很少测试空对象或具有10个或更多键的对象,那么请考虑object.keys(obj).length选项。-否则使用更通用的(用于…在……)实现中。

注意,firefox似乎对object.keys(obj).length和object.getownprotynames(obj).length有更快的支持,这使得它成为任何非空对象的更好选择,但对于空对象来说,(for…in…)的速度仅仅是10倍。

我的2美分是那个object.keys(obj),长度是个糟糕的主意,因为它创建一个keys对象只是为了计算里面有多少个keys,而不是销毁它!为了创建那个对象,他需要循环遍历键…所以为什么要用它而不是…在…)选项:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var a = {};

function timeit(func,count) {
   if (!count) count = 100000;
   var start = Date.now();
   for (i=0;i<count;i++) func();
   var end = Date.now();
   var duration = end - start;
   console.log(duration/count)
}

function isEmpty1() {
    return (Object.keys(a).length === 0)
}
function isEmpty2() {
    for (x in a) { return false; }
    return true;
}
function isEmpty3() {
    for (x in a) { if (a.hasOwnProperty(x))  return false; }
    return true;
}
function isEmpty4() {
    return ('{}' === JSON.stringify(a))
}


for (var j=0;j<10;j++) {
   a = {}
   for (var i=0;i<j;i++) a[i] = i;
   console.log('Testing for Object with '+Object.keys(a).length+' keys')
   timeit(isEmpty1);
   timeit(isEmpty2);
   timeit(isEmpty3);
   timeit(isEmpty4);
}

a = {}
for (var i=0;i<100;i++) a[i] = i;
console.log('Testing for Object with '+Object.keys(a).length+' keys')
timeit(isEmpty1);
timeit(isEmpty2);
timeit(isEmpty3);
timeit(isEmpty4, 10000);

a = {}
for (var i=0;i<1000;i++) a[i] = i;
console.log('Testing for Object with '+Object.keys(a).length+' keys')
timeit(isEmpty1,10000);
timeit(isEmpty2,10000);
timeit(isEmpty3,10000);
timeit(isEmpty4,10000);


优雅的方式-使用钥匙

1
2
3
4
var myEmptyObj = {};
var myFullObj = {"key":"value"};
console.log(Object.keys(myEmptyObj).length); //0
console.log(Object.keys(myFullObj).length); //1

https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/object/keys


1
2
3
4
5
6
function isEmpty( o ) {
    for ( var p in o ) {
        if ( o.hasOwnProperty( p ) ) { return false; }
    }
    return true;
}


在这样一个基本的JS问题上看到如此多的薄弱答案,真让人惊讶…最重要的答案也不好,原因如下:

  • 它生成一个全局变量
  • 返回undefined上的true
  • 使用for...in,本身速度非常慢
  • for...in中的函数是无用的-没有hasOwnProperty的返回false魔法会起作用的
  • 事实上,有一个更简单的解决方案:

    1
    2
    3
    function isEmpty(value){
        return Boolean(value && typeof value == 'object') && !Object.keys(value).length;
    });


    1
    2
    3
    4
    5
    6
    7
    var x= {}
    var y= {x:'hi'}
    console.log(Object.keys(x).length===0)
    console.log(Object.keys(y).length===0)

    true
    false

    http://jsfiddle.net/j7ona6hz/1/


    https://lodash.com/docs isEmpty非常方便:

    1
    2
    3
    4
    _.isEmpty({})   // true
    _.isEmpty()     // true
    _.isEmpty(null) // true
    _.isEmpty("")   // true

    这有多糟?

    1
    2
    3
    4
    5
    6
    7
    function(obj){
        for(var key in obj){
            return false; // not empty
        }

        return true; // empty
    }


    不需要图书馆。

    1
    2
    3
    4
    5
    6
    7
    8
    function(){ //must be within a function
     var obj = {}; //the object to test

     for(var isNotEmpty in obj) //will loop through once if there is a property of some sort, then
        return alert('not empty')//what ever you are trying to do once

     return alert('empty'); //nope obj was empty do this instead;
    }

    可能有点粗糙。你可以试试这个。

    1
    2
    3
    if (JSON.stringify(data).length === 2) {
       // Do something
    }

    不确定这种方法是否有任何缺点。


    1
    2
    3
    4
    5
    6
    7
    8
    funtion isEmpty(o,i)
    {
        for(i in o)
        {
            return!1
        }
        return!0
    }


    假设您有以下对象:

    1
    2
    var obj1= {};
    var obj2= {test:"test"};

    别忘了,我们不能使用==符号来测试继承后的对象相等性,所以如果您使用ECMA 5和Javascript的上一个版本,答案很简单,您可以使用下面的函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function isEmpty(obj) {
       //check if it's an Obj first
       var isObj = obj !== null
       && typeof obj === 'object'
       && Object.prototype.toString.call(obj) === '[object Object]';

       if (isObj) {
           for (var o in obj) {
               if (obj.hasOwnProperty(o)) {
                   return false;
                   break;
               }
           }
           return true;
       } else {
           console.error("isEmpty function only accept an Object");
       }
    }

    结果如下:

    1
    2
    3
    isEmpty(obj1); //this returns true
    isEmpty(obj2); //this returns false
    isEmpty([]); // log in console: isEmpty function only accept an Object

    "字典"对象的快速联机程序:

    1
    function isEmptyDict(d){for (var k in d) return false; return true}


    如果array.is array和object.getownPropertyNames不可用,则可以编写回退。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    XX.isEmpty = function(a){
        if(Array.isArray(a)){
            return (a.length==0);
        }
        if(!a){
            return true;
        }
        if(a instanceof Object){

            if(a instanceof Date){
                return false;
            }

            if(Object.getOwnPropertyNames(a).length == 0){
                return true;
            }
        }
        return false;
    }

    我修改了肖恩·维埃拉的代码以满足我的需要。空值和未定义值根本不算作对象,数字、布尔值和空字符串返回false。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    'use strict';

    // Speed up calls to hasOwnProperty
    var hasOwnProperty = Object.prototype.hasOwnProperty;

    var isObjectEmpty = function(obj) {
        // null and undefined are not empty
        if (obj == null) return false;
        if(obj === false) return false;
        if(obj === true) return false;
        if(obj ==="") return false;

        if(typeof obj ==="number") {
            return false;
        }  
       
        // Assume if it has a length property with a non-zero value
        // that that property is correct.
        if (obj.length > 0)    return false;
        if (obj.length === 0)  return true;

        // Otherwise, does it have any properties of its own?
        // Note that this doesn't handle
        // toString and valueOf enumeration bugs in IE < 9
        for (var key in obj) {
            if (hasOwnProperty.call(obj, key)) return false;
        }
       
       
       
        return true;
    };

    exports.isObjectEmpty = isObjectEmpty;


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    function isArray(a) {
        return Object.prototype.toString.call(a) === '[object Array]'
    }
    function isObject(a) {
        return Object.prototype.toString.call(a) === '[object Object]'
    }
    function isEmpty(a) {
        if (null == a ||"" == a)return!0;
        if ("number" == typeof a ||"string" == typeof a)return!1;
        var b = !0;
        if (isArray(a)) {
            if (!a.length)return!0;
            for (var c = 0; c < a.length; c++)isEmpty(a[c]) || (b = !1);
            return b
        }
        if (isObject(a)) {
            for (var d in a)hasOwnProperty.call(a, d) && (isEmpty(a[d]) || (b = !1));
            return b
        }
        return!0
    }


    这是一个很好的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function isEmpty(obj) {
      if (Array.isArray(obj)) {
        return obj.length === 0;
      } else if (typeof obj === 'object') {
        for (var i in obj) {
          return false;
        }
        return true;
      } else {
        return !obj;
      }
    }

    也许你可以用这个决定:

    1
    2
    3
    4
    5
    6
    var isEmpty = function(obj) {
      for (var key in obj)
        if(obj.hasOwnProperty(key))
          return false;
      return true;
    }

    这是我的解决方案

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function isEmpty(value) {
        if(Object.prototype.toString.call(value) === '[object Array]') {
            return value.length == 0;
        } else if(value != null && typeof value === 'object') {
            return Object.getOwnPropertyNames(value).length  == 0;
        } else {
            return !(value || (value === 0));
        }
    }

    切尔


    an object is an associative array, augmented with a prototype.

    The Object.is() method determines whether two values are the same value.

    对象比较:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Object.is('LOL', 'LOL');// true
    Object.is(console, console);// true
    Object.is(null, null);// true
    Object.is('ROFL', 'LOL');// false
    Object.is([], []);// false
    Object.is(0, -0);// false
    Object.is(NaN, 0/0);// true

    if (!Object.is)
    {
       // do something
    }

    1
    2
    3
    4
    if (Object.getOwnPropertyNames(obj1).length > 0)
    {
     alert('obj1 is empty!');
    }