W moim szczególnym przypadku:
callback instanceof Function
lub
typeof callback == "function"
czy to w ogóle ma znaczenie, jaka jest różnica?
Dodatkowe zasoby:
JavaScript-Garden typeof vs. instanceof
javascript
instanceof
typeof
farinspace
źródło
źródło
Object.prototype.toString
ecma-international.org/ecma-262/6.0/….constructor
właściwości zamiast tego.Odpowiedzi:
Użyj
instanceof
dla niestandardowych typów:Użyj
typeof
dla prostych wbudowanych typów:Użyj
instanceof
dla złożonych typów wbudowanych:A ostatni jest nieco trudny:
źródło
Use instanceof for complex built in types
- to wciąż jest podatne na błędy. Lepiej używać ES5Array.isArray()
i in. lub zalecane podkładki.Oba mają podobną funkcjonalność, ponieważ oba zwracają informacje o typie, ale ja osobiście wolę,
instanceof
ponieważ porównuje rzeczywiste typy zamiast ciągów. Porównanie typów jest mniej podatne na błędy ludzkie i jest technicznie szybsze, ponieważ porównuje wskaźniki w pamięci, a nie porównuje ciągi znaków.źródło
Dobrym powodem do użycia typeof jest to, że zmienna może być niezdefiniowana.
Dobrym powodem do użycia instanceof jest to, że zmienna może mieć wartość NULL.
Tak naprawdę moim zdaniem zależy to od rodzaju możliwych danych, które sprawdzasz.
źródło
instanceof
nie można porównać do typów pierwotnych, typeof może.undefined instanceof Object
zwraca false i nie zgłasza wyjątku. Nie wiem, jak ostatnia jest ta zmiana, ale czyni jąinstanceof
bardziej atrakcyjną.undefined instanceof Object
nie zgłasza wyjątku, ponieważ ehundefined
jest zdefiniowane. Stała istnieje w przestrzeni nazw. Gdy zmienna nie istnieje (na przykład literówka), instanceof zgłosi wyjątek. Z drugiej strony użycie typeof w nieistniejącej zmiennej daje „niezdefiniowany”.Aby to wyjaśnić, musisz znać dwa fakty:
Object.setPrototypeOf()
metodą (ECMAScript 2015) lub__proto__
właściwością (stare przeglądarki, przestarzałe). Zmiana prototypu obiektu nie jest jednak zalecana z powodu problemów z wydajnością.Dlatego instanceof ma zastosowanie tylko do obiektów. W większości przypadków nie używasz konstruktorów do tworzenia ciągów lub liczb. Możesz. Ale prawie nigdy tego nie robisz.
Również instanceof nie może sprawdzić, który konstruktor został użyty do utworzenia obiektu, ale zwróci wartość true, nawet jeśli obiekt pochodzi od sprawdzanej klasy. W większości przypadków jest to pożądane zachowanie, ale czasami tak nie jest. Musisz więc zachować ten umysł.
Innym problemem jest to, że różne zakresy mają różne środowiska wykonawcze. Oznacza to, że mają różne wbudowane elementy (inny obiekt globalny, różne konstruktory itp.). Może to spowodować nieoczekiwane wyniki.
Na przykład
[] instanceof window.frames[0].Array
wrócifalse
, ponieważArray.prototype !== window.frames[0].Array
i tablice dziedziczą po pierwszym.Ponadto nie można go używać z nieokreśloną wartością, ponieważ nie ma prototypu.
Porozmawiajmy teraz o jednej trudnej rzeczy. Co się stanie, jeśli użyjesz konstruktora do utworzenia typu pierwotnego?
Wygląda jak magia. Ale to nie jest. Jest to tak zwane boksowanie (zawijanie pierwotnej wartości przez obiekt) i rozpakowywanie (wydobywanie zawiniętej pierwotnej wartości z obiektu). Taki rodzaj kodu wydaje się „nieco” kruchy. Oczywiście możesz po prostu uniknąć tworzenia prymitywnego typu za pomocą konstruktorów. Ale jest jeszcze jedna możliwa sytuacja, w której boks może cię uderzyć. Gdy używasz Function.call () lub Function.apply () na typie pierwotnym.
Aby tego uniknąć, możesz użyć trybu ścisłego:
upd: Od ECMAScript 2015 istnieje jeszcze jeden typ o nazwie Symbol, który ma swój własny typ == „symbol” .
Możesz o tym przeczytać w MDN: ( Symbol , typeof ).
źródło
if an object is created by a given constructor
To jest niepoprawne.o instanceof C
zwróci true, jeśli odziedziczy po C.prototype. Wspominałeś o tym w dalszej części swojej odpowiedzi, ale nie jest to bardzo jasne.W Safari 5 i Internet Explorer 9. odkryłem pewne naprawdę interesujące (odczytywane jako „okropne”) zachowanie. Korzystałem z tego z dużym powodzeniem w Chrome i Firefox.
Następnie testuję w IE9 i to wcale nie działa. Wielka niespodzianka. Ale w Safari jest przerywany! Więc zaczynam debugować i stwierdzam, że Internet Explorer zawsze powraca
false
. Ale najdziwniejsze jest to, że Safari robi jakąś optymalizację w swojej maszynie Wirtualnej JavaScript, gdzie jesttrue
to pierwszy raz, ale zafalse
każdym razem, gdy naciskasz przeładuj!Mój mózg prawie eksplodował.
Więc teraz zdecydowałem się na to:
A teraz wszystko działa świetnie. Zauważ, że możesz zadzwonić,
"a string".toString()
a ona po prostu zwraca kopię ciągu, tjWięc od teraz będę używać obu.
źródło
Inne znaczące różnice praktyczne:
źródło
instanceof
myślę, że działa również, gdycallback
jest podtypemFunction
źródło
instanceof
w Javascript może być niestabilny - wierzę, że główne frameworki starają się unikać jego użycia. Różne okna to jeden ze sposobów, w jaki może się zepsuć - wierzę, że hierarchie klas również mogą to pomylić.Istnieją lepsze sposoby testowania, czy obiekt jest określonym typem wbudowanym (co zwykle jest tym, czego chcesz). Twórz funkcje narzędziowe i używaj ich:
I tak dalej.
źródło
instanceof
nie będzie pracować dla prymitywów np"foo" instanceof String
powrócifalse
natomiasttypeof "foo" == "string"
powrócitrue
.Z drugiej strony
typeof
prawdopodobnie nie zrobi tego, co chcesz, jeśli chodzi o niestandardowe obiekty (lub klasy, jakkolwiek chcesz je nazwać). Na przykład:Zdarza się, że funkcje są zarówno prymitywami „funkcyjnymi”, jak i instancjami „Funkcji”, co jest nieco dziwne, biorąc pod uwagę, że nie działa tak w przypadku innych typów pierwotnych, np.
ale
źródło
Poleciłbym użycie prototypu
callback.isFunction()
.Wyliczyli różnicę i możesz liczyć na ich powód.
Sądzę, że inne frameworki JS też mają takie rzeczy.
instanceOf
nie działałoby na funkcjach zdefiniowanych w innych oknach, jak sądzę. Ich funkcja jest inna niż twojawindow.Function
.źródło
Podczas sprawdzania funkcji należy zawsze używać
typeof
.Oto różnica:
Dlatego nigdy nie należy używać
instanceof
do sprawdzania funkcji.źródło
typeof
jest złe -f
wszystkie z poniższych: anObject
(obiekt) iFunction
(funkcja). Z wyjątkiem mnie bardziej sensowne jest używanie,instanceof
ponieważ wiedząc, że jest to funkcja, wiem również, że jest to obiekt, ponieważ wszystkie funkcje są obiektami w ECMAScript. Odwrotna sytuacja nie jest prawdą - wiedząc ztypeof
tego, żef
tak naprawdęobject
nie mam pojęcia, że jest to również funkcja.length
,name
icall
od funkcji, ale wszystkie z nich są zlikwidowany. Co gorsza, nie można nazwać iTypeError
mówi:f is not a function
.Znacząca praktyczna różnica:
Nie pytaj mnie dlaczego.
źródło
str
jest prymityw łańcucha, a nie obiekt łańcucha. To samo dotyczy prymitywów liczbowych i prymitywów boolowskich, nie są one instancjami „zbudowanych” odpowiedników, obiektów String, Number i Boolean. JavaScript automatycznie konwertuje te trzy prymitywy na obiekty, gdy jest to wymagane (takie jak użycie metody w łańcuchu prototypów obiektu). Z drugiej strony praktycznej różnicy, instanceof jest lepszy do sprawdzania tablic od tego czasutypeof [] == "object" // true
.Wydajność
typeof
jest szybszy niżinstanceof
w sytuacjach, w których oba mają zastosowanie.W zależności od silnika różnica wydajności na korzyść
typeof
może wynosić około 20% . ( Twój przebieg może się różnić )Oto testy porównawcze dla
Array
:Wynik
źródło
instanceof
zawsze podąża za łańcuchem prototypów obiektu, więc obniżenie wydajności będzie zależeć od tego, jak daleko w łańcuchu prototypów znajduje się klasa,instanceof
jest testowane. Tak na krótkim łańcuchu dziedziczenia kara będzie niższa (jak,[] instanceof Array
,{} instanceof Object
), i na długo - większe. Tak więc, jeśli obaobj instanceof SomeClass
itypeof obj !== 'string'
oznacza to samo z punktu widzenia jakiejś swojej hipotetycznej kodu (fe jeśli tylko co test wif
, a nieswitch
-ing przez wielu klas itp), to lepiej wybrać drugi, wydajność mądry,Jest to tylko wiedza uzupełniająca do wszystkich innych wyjaśnień tutaj - nie sugeruję, aby używać
.constructor
wszędzie.TL; DR: W sytuacjach
typeof
, gdy nie ma takiej opcji i kiedy wiesz, że nie zależy ci na łańcuchu prototypów ,Object.prototype.constructor
może być realną lub nawet lepszą alternatywą niżinstanceof
:Jest w standardzie od 1.1, więc nie martw się o kompatybilność wsteczną.
Muhammad Umer krótko wspomniał o tym w komentarzu gdzieś tutaj. Działa na wszystkim z prototypem - więc wszystko nie
null
lubundefined
:Co więcej, w zależności od przypadku użycia może być o wiele szybszy niż
instanceof
(prawdopodobnie dlatego, że nie musi sprawdzać całego łańcucha prototypów). W moim przypadku potrzebowałem szybkiego sposobu sprawdzenia, czy wartość jest tablicą typową:https://run.perf.zone/view/isTypedArray-constructor-vs-instanceof-1519140393812
A wyniki:
Chrome 64.0.3282.167 (64-bitowy, Windows)
Firefox 59.0b10 (64-bitowy, Windows)
Z ciekawości zrobiłem szybki test porównawczy zabawek
typeof
; co zaskakujące, nie działa znacznie gorzej i wydaje się nawet nieco szybszy w Chrome:https://run.perf.zone/view/typeof-vs-constructor-string-or-number-1519142623570
UWAGA: Kolejność wyświetlania wymienionych funkcji przełącza między obrazami!
Chrome 64.0.3282.167 (64-bitowy, Windows)
Firefox 59.0b10 (64-bitowy, Windows)
UWAGA: Kolejność wyświetlania wymienionych funkcji przełącza między obrazami!
źródło
Użyj instanceof, ponieważ jeśli zmienisz nazwę klasy, pojawi się błąd kompilatora.
źródło
źródło
Po ścisłym wychowaniu OO wybrałbym
Ciągi są podatne na moją okropną pisownię lub inne literówki. Plus czuję, że to czyta lepiej.
źródło
Mimo że instanceof może być nieco szybszy niż typeof , wolę drugi ze względu na taką możliwą magię:
źródło
Jeszcze jeden przypadek, że można tylko zestawiać
instanceof
- zwraca wartość true lub false. Dziękitypeof
niemu możesz uzyskać coś pod warunkiemźródło
mając na uwadze wydajność, lepiej użyć typeof na typowym sprzęcie, jeśli utworzysz skrypt z pętlą 10 milionów iteracji, instrukcja: typeof str == 'string' zajmie 9ms, a 'string' instanceof String zajmie 19ms
źródło
Oczywiście, że to ważne ........!
Przejdźmy przez przykłady. W naszym przykładzie zadeklarujemy funkcję na dwa różne sposoby.
Będziemy używać zarówno Konstruktora, jak
function declaration
i Funkcji . Zobaczymy, jaktypeof
i jakinstanceof
zachowamy się w tych dwóch różnych scenariuszach.Utwórz funkcję za pomocą deklaracji funkcji:
Możliwym wyjaśnieniem tak odmiennego wyniku jest to, że kiedy zadeklarowaliśmy funkcję,
typeof
możemy zrozumieć, że jest to funkcja, ponieważtypeof
sprawdza, czy wyrażenie, na którym działa typeof, w naszym przypadku implementuje metodę wywołania, czy nie . Jeśli implementuje metodę, jest to funkcja, w przeciwnym razie nie. Dla wyjaśnienia sprawdź specyfikację ekmascript dla typeof .MyFunc
Call
Utwórz funkcję za pomocą konstruktora funkcji:
Tutaj
typeof
twierdzi, żeMyFunc2
jest to funkcja, jak równieżinstanceof
operator.We już wiedzątypeof
sprawdzić, czyMyFunc2
zaimplementowaneCall
metody lub not.AsMyFunc2
jest funkcją i implementujecall
metodę, to w jaki sposóbtypeof
wie, że jest to function.On drugiej strony, użyliśmyfunction constructor
do tworzeniaMyFunc2
, to staje się przykłademFunction constructor
. Dlategoinstanceof
też postanawiatrue
.Co jest bezpieczniejsze w użyciu?
Jak widzimy w obu przypadkach
typeof
operator może skutecznie twierdzić, że mamy tutaj do czynienia z funkcją, jest to bezpieczniejsze niżinstanceof
.instanceof
zawiedzie w przypadku,function declaration
ponieważfunction declarations
nie są instancjąFunction constructor
.Najlepsze praktyki :
Jak sugerował Gary Rafferty , najlepszym sposobem powinno być jednoczesne użycie zarówno typeof, jak i instanceof.
źródło
Aby być bardzo precyzyjnym, należy użyć instanceof, gdy wartość jest tworzona za pomocą konstruktora (zazwyczaj typy niestandardowe), np
podczas gdy typeof sprawdza wartości utworzone tylko przez przypisania dla np
źródło
nie musisz przytłaczać mnóstwem powyższych przykładów, pamiętaj tylko o dwóch punktach widzenia:
typeof var;
to jednoargumentowy operator zwróci typ pierwotny lub typ root var. tak, że powróci pierwotne typu (string
,number
,bigint
,boolean
,undefined
, asymbol
) lubobject
typu.w przypadku obiektów wyższego poziomu, takich jak obiekty wbudowane (String, Number, Boolean, Array ..) lub obiekty złożone lub niestandardowe, wszystkie są
object
typu root, ale typ instancji zbudowany na nich jest różny (jak klasa OOP koncepcja dziedziczenia), tutaja instanceof A
- operator binarny - pomoże ci, przejdzie przez łańcuch prototypów, aby sprawdzić, czy pojawia się konstruktor właściwego operandu (A).więc gdy chcesz sprawdzić „typ root” lub pracować ze zmienną pierwotną - użyj „typeof”, w przeciwnym razie użyj „instanceof”.
null
jest szczególnym przypadkiem, który wydaje się prymitywny, ale w rzeczywistości jest szczególnym przypadkiem dla obiektu. Korzystaniea === null
zamiast sprawdzić null.z drugiej strony
function
jest także przypadkiem specjalnym, który jest wbudowanym obiektem, aletypeof
zwracafunction
jak widać,
instanceof
musisz przejść przez łańcuch prototypów, tymczasemtypeof
po prostu sprawdź typ roota, aby łatwo zrozumieć, dlaczegotypeof
jest szybszy niżinstanceof
źródło
Zgodnie z dokumentacją MDN na temat typeof obiekty tworzone za pomocą słowa kluczowego „new” są typu „object”:
O ile dokumentacja o instanceof punktów:
Więc jeśli chcesz sprawdzić np. Czy coś jest ciągiem, bez względu na to, jak to zostało stworzone, najbezpieczniejszym rozwiązaniem byłoby użycie
instanceof
.źródło