Jak sprawdzić, czy obiekt jest datą?


601

Mam irytujący błąd na stronie:

date.GetMonth () nie jest funkcją

Przypuszczam więc, że robię coś złego. Zmienna datenie jest obiektem typu Date. Jak mogę sprawdzić typ danych w JavaScript? Próbowałem dodać if (date), ale to nie działa.

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

Jeśli więc chcę napisać kod obronny i uniemożliwić sformatowanie daty (która nie jest jedną), jak to zrobić?

Dzięki!

AKTUALIZACJA: Nie chcę sprawdzać formatu daty, ale chcę mieć pewność, że parametr przekazany do metody getFormatedDate()jest typu Date.


W przypadku, gdy należy również sprawdzić, czy data nie jest Invalid Date: stackoverflow.com/a/44198641/5846045
Boghyon Hoffmann

Odpowiedzi:


1109

Jako alternatywa dla pisania kaczką przez

typeof date.getMonth === 'function'

możesz użyć instanceofoperatora, tzn. Ale zwróci on również prawdę dla niepoprawnych dat, np. new Date('random_string')jest także instancją Date

date instanceof Date

Nie powiedzie się, jeśli obiekty zostaną przekroczone przez granice ramek.

Obejściem tego problemu jest sprawdzenie klasy obiektu za pomocą

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

28
Czy z powodu zainteresowania znasz przyczynę tego niepowodzenia podczas przekraczania granic ramki?
Simon Lieschke

85
@Simon: Globały JS są lokalne dla bieżącego obiektu globalnego (aka windowlub self); różne ramki mają swoje własne obiekty globalne, a ich właściwości (tj. globale) odnoszą się do odrębnych obiektów: Datew frame1 jest innym obiektem funkcji niż Datew frame2; to samo dotyczy Date.prototype, co jest przyczyną instanceofniepowodzenia: Date.prototypez klatki 1 nie jest częścią prototypowego łańcucha Dateinstancji z klatki 2
Christoph

9
Christoph, co nazywasz „ramą”? IFRAME, każda ramka w FRAMESET lub coś innego (mam na myśli specyficzne dla JS, a nie HTML)?
Paul

12
new Date('something') instanceof Datepowraca truew Chrome. To nie zadziała.
krillgar

12
Wykrywanie obiektu typu Data (w przeciwieństwie do zwykłego obiektu lub ciągu) i sprawdzanie poprawności obiektu, który ma być Datą, to dwa różne zadania. Istnieje wiele sytuacji, w których dane wejściowe do funkcji mogą być jednym z wielu różnych typów danych. W moim przypadku mogę ufać, że każdy otrzymany obiekt Date jest prawidłowy (nie pochodzi bezpośrednio od klienta) Jeśli sprawdzanie poprawności stanowi problem, oto post z wieloma opcjami. stackoverflow.com/questions/1353684/…
Michael Blackburn

125

Możesz użyć następującego kodu:

(myvar instanceof Date) // returns true or false

6
Dlaczego nie jest to zaakceptowana lub bardziej pozytywna odpowiedź? Samo sprawdzenie, czy data ma właściwość .getMonth, może wywołać fałszywy alarm.
doremi,

24
instanceof może wywoływać fałszywe negatywy, patrz komentarz Christopha do jego własnej odpowiedzi.
Marco Mariani,

2
@doremi Oto demonstracja instanceofwyzwalania fałszywego negatywu: jsbin.com/vufufoq/edit?html,js,console
Boghyon Hoffmann

67

Aby sprawdzić, czy wartość jest poprawnym typem standardowego obiektu JS-date, możesz użyć tego predykatu:

function isValidDate(date) {
  return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
  1. datesprawdza czy parametr nie był wartość falsy ( undefined, null, 0, "", itp ..)
  2. Object.prototype.toString.call(date)zwraca natywną reprezentację ciągu danego typu obiektu - w naszym przypadku "[object Date]". Ponieważ date.toString()przesłania metodę nadrzędną , musimy .calllub .applymetodę, z Object.prototypektórej bezpośrednio…
  3. !isNaN(date)w końcu sprawdza, czy wartość nie była Invalid Date.

1
Wow isNaNmożna wykorzystać do sprawdzenia Date. To jakiś poziom niepoczytalności PHP.
Nick

@Nata data to jednak liczba.
Josiah

@Josiah Cóż, na pewno, usuwając cały kontekst jest datownik tam: typeof Date.now() === "number", ale: typeof new Date() === "object". Bardziej realistycznie jednak data to czas i miejsce w przestrzeni.
Nick

39

Ta funkcja to getMonth()nie GetMonth().

W każdym razie możesz sprawdzić, czy obiekt ma właściwość getMonth, wykonując tę ​​czynność. Nie musi to oznaczać, że obiekt jest datą, tylko każdy obiekt, który ma właściwość getMonth.

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

3
Sprawdź, czy można to if (date.getMonth && typeof date.getMonth === "function") {...}
wywołać

20

Jak wskazano powyżej, prawdopodobnie najłatwiej jest po prostu sprawdzić, czy funkcja istnieje przed użyciem. Jeśli naprawdę zależy Ci na tym, aby był to obiekt Date, a nie tylko obiekt z getMonth()funkcją, spróbuj tego:

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

Spowoduje to utworzenie klonu wartości, jeśli jest Date, lub utworzenie niepoprawnej daty. Następnie możesz sprawdzić, czy wartość nowej daty jest nieprawidłowa, czy nie.


1
To zadziałało dla mnie, dzięki. Jeśli jednak podasz jedną cyfrę, taką jak 0 lub 1, traktuje to jako prawidłową datę ... jakieś myśli?
Ricardo Sanchez

Zgadza się, @RicardoSanchez. Prawdopodobnie chcesz użyć zaakceptowanej odpowiedzi ( Object.prototype.toString.call(value) === '[object Date]'), jeśli to możliwe, będziesz otrzymywać liczby. Metoda w tej odpowiedzi naprawdę mówi, czy valuemożna ją przekonwertować na Date.
bdukes

18

Dla wszystkich typów przygotowałem funkcję prototypu Object. Może ci się przydać

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;
}

Teraz możesz sprawdzić dowolny typ tego typu:

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

[ Edytuj marzec 2013 ] w oparciu o postęp wglądu jest to lepsza metoda:

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


8

Najlepszy sposób, jaki znalazłem, to:

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

To nie działa Twoja prawdziwa linia jest w rzeczywistości fałszywa, a pytanie dotyczy sprawdzenia, czy obiekt jest obiektem daty ...
Clint

1
Odpowiedź @jspassov jest dokładniejsza, jeśli ciąg znaków jest datą, czy nie. Tego szukałem. Dzięki!!
Anant

To najlepsza odpowiedź na proste sprawdzenie, czy napis jest datą, czy nie
James Gentes,

3

Możesz sprawdzić, czy istnieje funkcja specyficzna dla obiektu Date:

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

3

Zamiast wszystkich obejść można użyć następujących opcji:

dateVariable = new Date(date);
if (dateVariable == 'Invalid Date') console.log('Invalid Date!');

Znalazłem ten hack lepiej!


2

Możesz także użyć krótkiego formularza

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

lub coś w tym stylu:

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

2

Korzystałem z dużo prostszego sposobu, ale nie jestem pewien, czy jest to dostępne tylko w ES6, czy nie.

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"

Nie będzie to jednak działać w przypadku wartości NULL lub niezdefiniowanej, ponieważ nie mają one konstruktora.


Zwraca "Date"również dowolny obiekt niestandardowy o nazwie konstruktora „Data”, co jest tak ryzykowne, jak samo sprawdzenie, czy parametr ma getMonthwłaściwość.
Boghyon Hoffmann

2
@boghyon brzmi jak ktoś, kto tworzy obiekt o nazwie konstruktora już zdefiniowanej standardowej biblioteki JavaScript, nie przestrzega przede wszystkim najlepszych praktyk. To byłoby jak pobranie lodash, a następnie utworzenie własnego modułu lodash i oczekiwanie, że wszystko zadziała.
mjwrazor

1

Ta funkcja zwróci, truejeśli jest to data lub w falseinny sposób:

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

1
isDate(new (function AnythingButNotDate(){ })())zwrotytrue
Boghyon Hoffmann

1

Jeszcze inny wariant:

Date.prototype.isPrototypeOf(myDateObject)

Miło i krótko! Ale niestety ma ten sam problem coinstanceof .
Boghyon Hoffmann

@BoghyonHoffmann w przypadku iFrame może wyglądać następująco: iWindow.Date.prototype.isPrototypeOf(iWindow.date); // true iWindow.date instanceof iWindow.Date; // true
Vadim

1

Podejście wykorzystujące try / catch

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)));


0

W rzeczywistości data będzie typu Object. Ale możesz sprawdzić, czy obiekt ma getMonthmetodę i czy można ją wywoływać.

function getFormatedDate(date) {
    if (date && date.getMonth && date.getMonth.call) {
       var month = date.getMonth();
    }
}

2
Odpowiedź Christopha jest dokładniejsza. Posiadanie właściwości „call” niekoniecznie oznacza, że ​​jest to funkcja!
Chetan Sastry

-1

Możemy to również sprawdzić za pomocą poniższego kodu

var a = new Date();
a.constructor === Date
/*
true
*/

wprowadź opis zdjęcia tutaj


Konstruktor function Date() {/*...*/}jest również Date. Tj. Zwykłe porównanie funkcji konstruktora jest zbyt podatne na błędy, co często skutkuje fałszywymi trafieniami.
Pomiń

-1

Zainspirowane tą odpowiedzią , to rozwiązanie działa w moim przypadku (musiałem sprawdzić, czy wartość otrzymana z API jest datą, czy nie):

!isNaN(Date.parse(new Date(YourVariable)))

W ten sposób, jeśli jest to dowolny ciąg losowy pochodzący od klienta lub dowolnego innego obiektu, możesz dowiedzieć się, czy jest to obiekt podobny do daty.


-2

Nie możesz po prostu użyć

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

1
Nie, isValidmetoda ma tylko obiekt daty
nikk wong 14.04.17

2
@grumpy @nikkwong Nie i nie. Standardowy obiekt daty nie ma isValid. Tylko moment.js ma taki interfejs API.
Boghyon Hoffmann
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.