javascript - Hur kontrollerar man om ett objekt är ett datum?


Jag har en irriterande bugg på en webbsida:

date.GetMonth() är inte en funktion

Så, jag antar att jag gör något fel. Variabeln date är inte ett objekt av typen Date. Hur kan jag kontrollera en datatyp i Javascript? Jag försökte att lägga till en if (date), men det fungerar inte.

function getFormatedDate(date) {
    if (date) {
       var month = date.GetMonth();
    }
}

Så, om jag vill skriva defensiv kod och förhindra att datumet (som inte är ett) formateras, hur gör jag det?

Tack!

UPPDATERING: Jag vill inte kontrollera datumformatet, men jag vill vara säker på att parametern som skickas till metoden getFormatedDate() är av typen Date.

Svar #1

Som ett alternativ till duck typing via

typeof date.getMonth === 'function'

du kan använda instanceof-operatorn, det vill säga. Men den kommer också att returnera sant för ogiltiga datum, t.ex. new Date('random_string') är också en instans av Date

date instanceof Date

Detta kommer att misslyckas om objekt skickas över ramgränser.

En lösning för detta är att kontrollera objektets klass via

Object.prototype.toString.call(date) === '[object Date]'
Var medveten om att instanceof-lösningen inte fungerar när man använder flera domäner:

JavaScript-exekveringsmiljöer (windows, frames, etc.) är var och en i sin egen värld. Detta innebär att de har olika inbyggda objekt (olika globala objekt, olika konstruktörer, etc.). Detta kan resultera i oväntade resultat. Till exempel kommer [] instanceof window.frames[0].Array att returnera false, eftersom Array.prototype !== window.frames[0].Array.prototype och arrayer i den nuvarande världen ärver från den tidigare.

Svar #2

Du kan använda följande kod:

(myvar instanceof Date) // returns true or false
Var medveten om att denna lösning inte fungerar när man använder flera realmer:

JavaScript-exekveringsmiljöer (windows, frames, etc.) är var och en i sin egen värld. Detta innebär att de har olika inbyggda objekt (olika globala objekt, olika konstruktörer, etc.). Detta kan resultera i oväntade resultat. Till exempel kommer [] instanceof window.frames[0].Array att returnera false, eftersom Array.prototype !== window.frames[0].Array.prototype och arrayer i den nuvarande världen ärver från det tidigare.

Svar #3

För att kontrollera om värdet är en giltig typ av standard JS-datumobjektet kan du använda denna predikat:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. date kontrollerar om parametern inte var ett falskt värde (undefined, null, 0, "" osv..)
  2. Object.prototype.toString.call(date) returnerar en inbyggd strängrepresentation av den givna objekttypen - i vårt fall "[object Date]". Eftersom date.toString() överskrider sin föräldrametod, behöver vi .call eller .apply metoden från Object.prototype direkt, vilket ..

    • Bypassar användardefinierad objekttyp med samma konstruktörsnamn (t.ex.: "Date")
    • Fungerar över olika JS-kontexter (t.ex. iframes) i kontrast till instanceof eller Date.prototype.isPrototypeOf.
  3. !isNaN(date) kontrollerar slutligen om värdet inte var ett Invalid Date.

Svar #4

Funktionen är getMonth(), inte GetMonth().

Hur som helst, du kan kolla om objektet har en getMonth-egenskap genom att göra så här. Det betyder inte nödvändigtvis att objektet är ett Date, bara ett objekt som har en getMonth-egenskap.

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

Svar #5

Detta är ett ganska enkelt tillvägagångssätt om du inte bryr dig om iframes/andra sammanhang.

// isNaN(Invalid Date) == true
if (date instanceof Date && !isNaN(date)) { // isNaN wont accept a date in typescript, use date.getTime() instead to produce a number
    console.log("is date!");
}
  • Kontrollerar om objektet faktiskt är ett Date och inte något som ser ut som ett. Alla objekt kan ha en getMonth-funktion.
  • Säkerställer att datumet inte är ett Ogiltigt datum
  • Passerar inte ett värde till new Date() där ett nummer eller till och med en sträng skulle kunna omvandlas till ett Datum.

Om du behöver stödja iframes och olika sammanhang kan du använda det accepterade svaret men lägga till en extra kontroll för att identifiera ogiltiga datum.

// isNaN(Invalid Date) == true
if (Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date)) {
    console.log("is date!");
}

Svar #6

Som angivet ovan är det förmodligen enklast att bara kontrollera om funktionen finns innan du använder den. Om du verkligen bryr dig om att det är ett Date, och inte bara ett objekt med en getMonth()-funktion, prova detta:

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

Detta kommer antingen att skapa en kopia av värdet om det är ett Date, eller skapa ett ogiltigt datum. Du kan sedan kontrollera om det nya datumets värde är ogiltigt eller inte.

Svar #7

För alla typer lagade jag en Object-prototypfunktion. Den kan vara användbar för dig

Object.prototype.typof = function(chkType){
      var inp        = String(this.constructor),
          customObj  = (inp.split(/\({1}/))[0].replace(/^\n/,'').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;
}

Nu kan du kontrollera vilken typ som helst på detta sätt:

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

[Redigera mars 2013] baserat på framåtskridande insikt är detta en bättre metod:

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

Svar #8

Det bästa sättet jag har hittat är:

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

Svar #9

UnderscoreJS och Lodash har en funktion som kallas .isDate() vilket verkar vara precis vad du behöver. Det är värt att titta på deras respektive implementationer: Lodash isDate, UnderscoreJs

Relaterade artiklar