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.