关于javascript:如何检查对象是否是日期?

How to check whether an object is a date?

我在网页上发现了一个令人讨厌的错误:

date.GetMonth() is not a function

所以,我想我做错了什么。变量date不是date类型的对象。如何检查javascript中的数据类型?我试图添加一个if (date),但它不起作用。

1
2
3
4
5
function getFormatedDate(date) {
    if (date) {
       var month = date.GetMonth();
    }
}

所以,如果我想写防御代码并防止日期(不是一个)被格式化,我该怎么做呢?

谢谢!

更新:我不想检查日期的格式,但我想确保传递给方法getFormatedDate()的参数是date类型。


作为鸭子打字的替代方法

1
typeof date.getMonth === 'function'

您可以使用instanceof操作符,也就是说,对于无效日期,它也会返回true,例如,new Date('random_string')也是日期的实例。

1
date instanceof Date

如果对象通过帧边界,这将失败。

解决这个问题的方法是通过

1
Object.prototype.toString.call(date) === '[object Date]'


您可以使用以下代码:

1
(myvar instanceof Date) // returns true or false


函数是getMonth(),而不是getMonth()

无论如何,您可以通过这样做来检查对象是否具有GetMonth属性。它不一定意味着对象是日期,只是具有getMonth属性的任何对象。

1
2
3
if (date.getMonth) {
    var month = date.getMonth();
}


为了检查该值是否为标准JS日期对象的有效类型,可以使用此谓词:

1
2
3
function isValidDate(date) {
  return date && Object.prototype.toString.call(date) ==="[object Date]" && !isNaN(date);
}
  • Date检查参数是否为假值(undefinednull0""等)。
  • Object.prototype.toString.call(date)返回给定对象类型的本机字符串表示形式—在我们的例子中是"[object Date]"。由于date.toString()重写了其父方法,所以我们需要直接从Object.prototype获取.call.apply方法。
    • 绕过具有相同构造函数名称的用户定义对象类型(例如:"日期")。
    • instanceofDate.prototype.isPrototypeOf不同,它在不同的JS上下文(例如iframes)中工作。
  • !isNaN(date)最后检查该值是否为Invalid Date

  • 如上所述,在使用函数之前,检查函数是否存在可能是最简单的。如果您真的关心它是一个Date,而不仅仅是一个具有getMonth()函数的对象,请尝试以下操作:

    1
    2
    3
    4
    function isValidDate(value) {
        var dateWrapper = new Date(value);
        return !isNaN(dateWrapper.getDate());
    }

    如果值是Date,这将创建该值的克隆,或者创建一个无效的日期。然后可以检查新日期的值是否无效。


    对于所有类型,我编写了一个对象原型函数。可能对你有用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Object.prototype.typof = function(chkType){
          var inp        = String(this.constructor),
              customObj  = (inp.split(/\({1}/))[0].replace(/^
    /,'').substr(9),
              regularObj = Object.prototype.toString.apply(this),
              thisType   = regularObj.toLowerCase()
                            .match(new RegExp(customObj.toLowerCase()))
                           ? regularObj : '[object '+customObj+']';
         return chkType
                ? thisType.toLowerCase().match(chkType.toLowerCase())
                   ? true : false
                : thisType;
    }

    现在您可以检查以下任何类型:

    1
    2
    3
    4
    var myDate     = new Date().toString(),
        myRealDate = new Date();
    if (myRealDate.typof('Date')) { /* do things */ }
    alert( myDate.typof() ); //=> String

    [2013年3月编辑]基于不断深入的洞察力,这是一种更好的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Object.prototype.is = function() {
            var test = arguments.length ? [].slice.call(arguments) : null
               ,self = this.constructor;
            return test ? !!(test.filter(function(a){return a === self}).length)
                   : (this.constructor.name ||
                      (String(self).match ( /^function\s*([^\s(]+)/im)
                        || [0,'ANONYMOUS_CONSTRUCTOR']) [1] );
    }
    // usage
    var Some = function(){ /* ... */}
       ,Other = function(){ /* ... */}
       ,some = new Some;
    2..is(String,Function,RegExp);        //=> false
    2..is(String,Function,Number,RegExp); //=> true
    'hello'.is(String);                   //=> true
    'hello'.is();                         //-> String
    /[a-z]/i.is();                        //-> RegExp
    some.is();                            //=> 'ANONYMOUS_CONSTRUCTOR'
    some.is(Other);                       //=> false
    some.is(Some);                        //=> true
    // note: you can't use this for NaN (NaN === Number)
    (+'ab2').is(Number);                 //=> true


    underlinejs和lodash有一个名为.isDate()的函数,这似乎正是您所需要的。值得一看它们各自的实现:lodash isdate,underlinejs


    我发现最好的方法是:

    1
    2
    3
    4
    !isNaN(Date.parse("some date test"))
    //
    !isNaN(Date.parse("22/05/2001"))  // true
    !isNaN(Date.parse("blabla"))  // false


    您可以检查特定于日期对象的函数是否存在:

    1
    2
    3
    4
    5
    function getFormatedDate(date) {
        if (date.getMonth) {
            var month = date.getMonth();
        }
    }

    你也可以用短表格

    1
    2
    3
    4
    function getClass(obj) {
      return {}.toString.call(obj).slice(8, -1);
    }
    alert( getClass(new Date) ); //Date

    或者像这样:

    1
    (toString.call(date)) == 'Date'

    我一直在使用一种更简单的方法,但不确定这是否只在ES6中可用。

    1
    2
    3
    4
    5
    6
    let a = {name:"a", age: 1, date: new Date("1/2/2017"), arr: [], obj: {} };
    console.log(a.name.constructor.name); //"String"
    console.log(a.age.constructor.name);  //"Number"
    console.log(a.date.constructor.name); //"Date"
    console.log(a.arr.constructor.name);  //"Array"
    console.log(a.obj.constructor.name);  //"Object"

    但是,这不会在空值或未定义值上工作,因为它们没有构造函数。


    如果是日期,此函数将返回true,否则返回false

    1
    2
    3
    function isDate(myDate) {
        return myDate.constructor.toString().indexOf("Date") > -1;
    }


    使用try/catch的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function getFormatedDate(date = new Date()) {
      try {
        date.toISOString();
      } catch (e) {
        date = new Date();
      }
      return date;
    }

    console.log(getFormatedDate());
    console.log(getFormatedDate('AAAA'));
    console.log(getFormatedDate(new Date('AAAA')));
    console.log(getFormatedDate(new Date(2018, 2, 10)));


    实际日期为Object类型。但是您可以检查对象是否有getMonth方法,以及它是否可以调用。

    1
    2
    3
    4
    5
    function getFormatedDate(date) {
        if (date && date.getMonth && date.getMonth.call) {
           var month = date.getMonth();
        }
    }


    还有另一个变种:

    1
    Date.prototype.isPrototypeOf(myDateObject)


    你不能用一下吗

    1
    2
    3
    4
    5
    function getFormatedDate(date) {
        if (date.isValid()) {
           var month = date.GetMonth();
        }
    }