Jaka jest różnica między typof a instanceof i kiedy należy użyć jednego w porównaniu do drugiego?


394

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


2
Tutaj znalazłem swoją odpowiedź jako łatwe w użyciu rozwiązanie
CrandellWS

1
Istnieje inny sposób sprawdzenia typu za pomocą Object.prototype.toString ecma-international.org/ecma-262/6.0/…
rab

1
po prostu użyj .constructorwłaściwości zamiast tego.
Muhammad Umer

Jeśli zastanawiasz się nad wydajnością , zobacz moją odpowiedź poniżej . typeof jest szybszy tam, gdzie oba mają zastosowanie (mianowicie obiekty).
Martin Peter

Odpowiedzi:


540

Użyj instanceofdla niestandardowych typów:

var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false 

Użyj typeofdla prostych wbudowanych typów:

'example string' instanceof String; // false
typeof 'example string' == 'string'; // true

'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false

true instanceof Boolean; // false
typeof true == 'boolean'; // true

99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true

function() {} instanceof Function; // true
typeof function() {} == 'function'; // true

Użyj instanceofdla złożonych typów wbudowanych:

/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object

[] instanceof Array; // true
typeof []; //object

{} instanceof Object; // true
typeof {}; // object

A ostatni jest nieco trudny:

typeof null; // object

11
Ta odpowiedź wyjaśnia, dlaczego instaceof nie powinien być używany dla typów pierwotnych. To oczywiste, że nie masz opcji, jeśli chodzi o typy niestandardowe, a także korzyści dla typów „obiektowych”. Ale co sprawia, że ​​funkcje są wbudowane w „proste typy wbudowane”? Wydaje mi się dziwne, jak funkcja zachowuje się jak obiekt, ale jej typ to „funkcja”, dzięki czemu możliwe jest użycie „typeof”. Dlaczego jednak miałbyś zniechęcać do tego instancja?
Assimilater,

4
@ Assimilater można również użyć instanceof z funkcjami, jednak uważam, że te 3 reguły są bardzo łatwe do zapamiętania i tak, funkcje są wyjątkiem :)
Szymon Wygnański

2
kolejna trudna część -> „przykładowy ciąg” instanceof String; // false, ale nowy ciąg („przykładowy ciąg”) instanceof String; // prawda
Łukasz

2
@Luke ogólnie zły pomysł na użycie „nowego ciągu” w ten sposób. który tworzy „obiekt łańcuchowy”, a nie prymityw łańcucha. patrz sekcja tutaj developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Colin D

4
Use instanceof for complex built in types- to wciąż jest podatne na błędy. Lepiej używać ES5 Array.isArray()i in. lub zalecane podkładki.
OrangeDog

122

Oba mają podobną funkcjonalność, ponieważ oba zwracają informacje o typie, ale ja osobiście wolę, instanceofponieważ 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.


8
istnieją sytuacje, w których instanceof nie będzie działał zgodnie z oczekiwaniami, a typeof działa dobrze ... developer.mozilla.org/En/Core_JavaScript_1.5_Reference/…
farinspace

55
instanceof działa z obiektami w tym samym oknie. Jeśli użyjesz elementu iframe / frame lub wyskakującego okienka, każda (i) rama / okno ma swój własny obiekt „funkcyjny”, a instanceof nie powiedzie się, jeśli spróbujesz porównać obiekt z innej (i) ramki / okna. typeof będzie działać we wszystkich przypadkach, ponieważ zwraca ciąg „function”.
około

14
jsperf.com/typeof-function-vs-instanceof/3 Próbowałem na Chrome i FF3.X, podejście „typeof” jest szybsze.
Morgan Cheng

10
To tylko fałsz. Nie są identyczne. Nie działają one w tych samych sytuacjach, szczególnie w różnych maszynach wirtualnych JavaScript i przeglądarkach.
Justin Force

8
Twoja odpowiedź mówi „oba są zasadniczo identyczne pod względem funkcjonalności”. Z szacunkiem jest to oczywiście nieprawda. Jak wyjaśniono i wyjaśniono w mojej odpowiedzi, żadna opcja nie działa w każdej sytuacji - szczególnie w różnych przeglądarkach. Lepszym rozwiązaniem jest użycie obu z || operator.
Justin Force

103

Dobrym powodem do użycia typeof jest to, że zmienna może być niezdefiniowana.

alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception

Dobrym powodem do użycia instanceof jest to, że zmienna może mieć wartość NULL.

var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar  instanceof Object); // alerts "false"

Tak naprawdę moim zdaniem zależy to od rodzaju możliwych danych, które sprawdzasz.


11
+1 również zauważyć, że instanceofnie można porównać do typów pierwotnych, typeof może.
Tino

3
W Chrome 29.0.1541.0 dev undefined instanceof Objectzwraca false i nie zgłasza wyjątku. Nie wiem, jak ostatnia jest ta zmiana, ale czyni ją instanceofbardziej atrakcyjną.
Cypress Frankenfeld

7
undefined instanceof Objectnie zgłasza wyjątku, ponieważ eh undefinedjest 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”.
cleong

31

Aby to wyjaśnić, musisz znać dwa fakty:

  1. W instanceof testy operatorskie czy nieruchomość prototyp z konstruktora pojawia się nigdzie w prototypach łańcucha obiektu. W większości przypadków oznacza to, że obiekt został utworzony przy użyciu tego konstruktora lub jego potomka. Ale również prototyp można ustawić jawnie 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].Arraywróci false, ponieważ Array.prototype !== window.frames[0].Arrayi tablice dziedziczą po pierwszym.
Ponadto nie można go używać z nieokreśloną wartością, ponieważ nie ma prototypu.

  1. W typeof testy operatorskie czy wartość należą do jednej z sześciu podstawowych typów : „ numer ”, „ ciąg ”, „ logiczną ”, „ obiekt ”, „ funkcja ” lub „ niezdefiniowana ”. Gdzie ciąg „obiekt” należy do wszystkich obiektów (z wyjątkiem funkcji, które są obiektami, ale mają własną wartość w operatorze typeof), a także wartości i tablic „null” (dla „null” jest to błąd, ale ten błąd jest tak stary , więc stało się standardem). Nie opiera się na konstruktorach i może być używany, nawet jeśli wartość jest niezdefiniowana. Ale nie podaje żadnych szczegółów na temat obiektów. Więc jeśli potrzebujesz, przejdź do instanceof.

Porozmawiajmy teraz o jednej trudnej rzeczy. Co się stanie, jeśli użyjesz konstruktora do utworzenia typu pierwotnego?

let num = new Number(5);
console.log(num instanceof Number); // print true
console.log(typeof num); // print object
num++; //num is object right now but still can be handled as number
//and after that:
console.log(num instanceof Number); // print false
console.log(typeof num); // print number

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.

function test(){
  console.log(typeof this);
} 
test.apply(5);

Aby tego uniknąć, możesz użyć trybu ścisłego:

function test(){
  'use strict';
  console.log(typeof this);
} 
test.apply(5);

upd: Od ECMAScript 2015 istnieje jeszcze jeden typ o nazwie Symbol, który ma swój własny typ == „symbol” .

console.log(typeof Symbol());
// expected output: "symbol"

Możesz o tym przeczytać w MDN: ( Symbol , typeof ).


2
if an object is created by a given constructor To jest niepoprawne. o instanceof Czwróci true, jeśli odziedziczy po C.prototype. Wspominałeś o tym w dalszej części swojej odpowiedzi, ale nie jest to bardzo jasne.
oyenamit

1
niepoprawny ... z książki: „ github.com/getify/You-Dont-Know-JS ” instancja Foo; // true Operator instanceof przyjmuje prosty obiekt jako operand po lewej stronie i funkcję jako operand po prawej stronie. Pytanie instancji odpowiedzi brzmi: w całym łańcuchu [[Prototyp]], czy obiekt arbitralnie wskazywany przez Foo.prototype kiedykolwiek się pojawił?
Deen John,

1
Zmodyfikowałem odpowiedź, aby być bardziej poprawnym. Dziękuję za komentarze.
Vladimir Liubimov,

Dodano również wyjaśnienie problemu dotyczącego boksu / rozpakowania.
Vladimir Liubimov,

15

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.

if (typeof this === 'string') {
    doStuffWith(this);
}

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 jest trueto pierwszy raz, ale za false każdym razem, gdy naciskasz przeładuj!

Mój mózg prawie eksplodował.

Więc teraz zdecydowałem się na to:

if (this instanceof String || typeof this === 'string')
    doStuffWith(this.toString());
}

A teraz wszystko działa świetnie. Zauważ, że możesz zadzwonić, "a string".toString()a ona po prostu zwraca kopię ciągu, tj

"a string".toString() === new String("a string").toString(); // true

Więc od teraz będę używać obu.


8

Inne znaczące różnice praktyczne:

// Boolean

var str3 = true ;

alert(str3);

alert(str3 instanceof Boolean);  // false: expect true  

alert(typeof str3 == "boolean" ); // true

// Number

var str4 = 100 ;

alert(str4);

alert(str4 instanceof Number);  // false: expect true   

alert(typeof str4 == "number" ); // true

7

instanceofmyślę, że działa również, gdy callbackjest podtypemFunction


4

instanceofw 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:

function isFunction(obj) {
  return typeof(obj) == "function";
}
function isArray(obj) {
  return typeof(obj) == "object" 
      && typeof(obj.length) == "number" 
      && isFunction(obj.push);
}

I tak dalej.


2
Jeśli nie wiesz: typeof nie potrzebuje nawiasów, ponieważ jest to słowo kluczowe, a nie funkcja. I IMHO powinieneś użyć === zamiast ==.
około

5
@some Masz rację co do typeof, ale w tym przypadku nie ma potrzeby ===, jest on potrzebny tylko wtedy, gdy porównywana wartość może być równa bez posiadania tego samego typu. Tutaj nie może.
Nicole

@some czy typeof kiedykolwiek zwraca coś innego niż ciąg znaków?
Kenneth J

Zatem isArray byłby niewłaściwy dla, powiedzmy, obiektu stosu z metodą wypychania i atrybutem długości liczbowej. W jakich okolicznościach (instanceof Array) byłoby błędem?
Chris Noe,

@ChrisNoe Problem powstaje w przypadku obiektów współużytkowanych przez wiele ramek: groups.google.com/forum/#!msg/comp.lang.javascript/XTWYCOwC96I/…

3

instanceofnie będzie pracować dla prymitywów np "foo" instanceof Stringpowróci falsenatomiast typeof "foo" == "string"powróci true.

Z drugiej strony typeofprawdopodobnie nie zrobi tego, co chcesz, jeśli chodzi o niestandardowe obiekty (lub klasy, jakkolwiek chcesz je nazwać). Na przykład:

function Dog() {}
var obj = new Dog;
typeof obj == 'Dog' // false, typeof obj is actually "object"
obj instanceof Dog  // true, what we want in this case

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.

(typeof function(){} == 'function') == (function(){} instanceof Function)

ale

(typeof 'foo' == 'string') != ('foo' instanceof String)

3

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.

instanceOfnie działałoby na funkcjach zdefiniowanych w innych oknach, jak sądzę. Ich funkcja jest inna niż twoja window.Function.


3

Podczas sprawdzania funkcji należy zawsze używać typeof.

Oto różnica:

var f = Object.create(Function);

console.log(f instanceof Function); //=> true
console.log(typeof f === 'function'); //=> false

f(); // throws TypeError: f is not a function

Dlatego nigdy nie należy używać instanceofdo sprawdzania funkcji.


Mogę argumentować, że to typeofjest złe - fwszystkie z poniższych: an Object(obiekt) i Function(funkcja). Z wyjątkiem mnie bardziej sensowne jest używanie, instanceofponieważ 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 z typeoftego, że ftak naprawdę objectnie mam pojęcia, że ​​jest to również funkcja.
AMN

@amn Dla mnie jest to zepsuta instancja funkcji. Dostaje to atrybuty, takie jak length, namei callod funkcji, ale wszystkie z nich są zlikwidowany. Co gorsza, nie można nazwać i TypeErrormówi: f is not a function.
maaartinus

2

Znacząca praktyczna różnica:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

Nie pytaj mnie dlaczego.


11
Ponieważ tutaj strjest 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 czasu typeof [] == "object" // true.
Andy E,

2

Wydajność

typeofjest szybszy niż instanceofw sytuacjach, w których oba mają zastosowanie.

W zależności od silnika różnica wydajności na korzyść typeofmoże wynosić około 20% . ( Twój przebieg może się różnić )

Oto testy porównawcze dla Array:

var subject = new Array();
var iterations = 10000000;

var goBenchmark = function(callback, iterations) {
    var start = Date.now();
    for (i=0; i < iterations; i++) { var foo = callback(); }
    var end = Date.now();
    var seconds = parseFloat((end-start)/1000).toFixed(2);
    console.log(callback.name+" took: "+ seconds +" seconds.");
    return seconds;
}

// Testing instanceof
var iot = goBenchmark(function instanceofTest(){
     (subject instanceof Array);
}, iterations);

// Testing typeof
var tot = goBenchmark(function typeofTest(){
     (typeof subject == "object");
}, iterations);

var r = new Array(iot,tot).sort();
console.log("Performance ratio is: "+ parseFloat(r[1]/r[0]).toFixed(3));

Wynik

instanceofTest took: 9.98 seconds.
typeofTest took: 8.33 seconds.
Performance ratio is: 1.198

1
typeof subject == „tablica” powinna zwrócić wartość false. typeof subject to „obiekt”.
Shardul

jak to możliwe, że typeof jest szybszy? czy JavaScript internalizuje dosłowne ciągi znaków?
Gregory Magarshak

Powód jest taki: 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, instanceofjest 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 oba obj instanceof SomeClassi typeof obj !== 'string'oznacza to samo z punktu widzenia jakiejś swojej hipotetycznej kodu (fe jeśli tylko co test w if, a nie switch-ing przez wielu klas itp), to lepiej wybrać drugi, wydajność mądry,
ankhzet

2

Jest to tylko wiedza uzupełniająca do wszystkich innych wyjaśnień tutaj - nie sugeruję, aby używać .constructorwszę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.constructormoże być realną lub nawet lepszą alternatywą niż instanceof:

x instanceof Y
x.constructor === Y

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 nulllub undefined:

// (null).constructor;      // TypeError: null has no properties
// (undefined).constructor; // TypeError: undefined has no properties

(1).constructor;                 // function Number
''.constructor;                  // function String
([]).constructor;                // function Array
(new Uint8Array(0)).constructor; // function Uint8Array
false.constructor;               // function Boolean()
true.constructor;                // function Boolean()

(Symbol('foo')).constructor;     // function Symbol()
// Symbols work, just remember that this is not an actual constructor:
// new Symbol('foo'); //TypeError: Symbol is not a constructor

Array.prototype === window.frames.Array;               // false
Array.constructor === window.frames.Array.constructor; // true

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ą:

function isTypedArrayConstructor(obj) {
  switch (obj && obj.constructor){
    case Uint8Array:
    case Float32Array:
    case Uint16Array:
    case Uint32Array:
    case Int32Array:
    case Float64Array:
    case Int8Array:
    case Uint8ClampedArray:
    case Int16Array:
      return true;
    default:
      return false;
  }
}

function isTypedArrayInstanceOf(obj) {
  return obj instanceof Uint8Array ||
    obj instanceof Float32Array ||
    obj instanceof Uint16Array ||
    obj instanceof Uint32Array ||
    obj instanceof Int32Array ||
    obj instanceof Float64Array ||
    obj instanceof Int8Array ||
    obj instanceof Uint8ClampedArray ||
    obj instanceof Int16Array;
}

https://run.perf.zone/view/isTypedArray-constructor-vs-instanceof-1519140393812

A wyniki:

Chrome 64.0.3282.167 (64-bitowy, Windows)

Insted Array instanceof vs constructor - 1,5x szybciej w Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64-bitowy, Windows)

Insted Array instanceof vs constructor - 30x szybciej w Firefox 59.0b10 (64-bit, 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:

let s = 0,
    n = 0;

function typeofSwitch(t) {
    switch (typeof t) {
        case "string":
            return ++s;
        case "number":
            return ++n;
        default:
            return 0;
    }
}

// note: no test for null or undefined here
function constructorSwitch(t) {
    switch (t.constructor) {
        case String:
            return ++s;
        case Number:
            return ++n;
        default:
            return 0;
    }
}

let vals = [];
for (let i = 0; i < 1000000; i++) {
    vals.push(Math.random() <= 0.5 ? 0 : 'A');
}

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)

Typ ciągu / liczby w stosunku do konstruktora - 1,26 razy szybszy w Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64-bitowy, Windows)

UWAGA: Kolejność wyświetlania wymienionych funkcji przełącza między obrazami!

Typ ciągu / liczby w porównaniu z konstruktorem - 0,78x wolniejszy w Firefox 59.0b10 (64-bit, Windows)


1

Użyj instanceof, ponieważ jeśli zmienisz nazwę klasy, pojawi się błąd kompilatora.


1

var newObj =  new Object;//instance of Object
var newProp = "I'm xgqfrms!" //define property
var newFunc = function(name){//define function 
	var hello ="hello, "+ name +"!";
	return hello;
}
newObj.info = newProp;// add property
newObj.func = newFunc;// add function

console.log(newObj.info);// call function
// I'm xgqfrms!
console.log(newObj.func("ET"));// call function
// hello, ET!

console.log(newObj instanceof Object);
//true
console.log(typeof(newObj));
//"object"


Co powinienem zrobić, czy mogę uzyskać UA (navigator.userAgent)?
xgqfrms

0

Po ścisłym wychowaniu OO wybrałbym

callback instanceof Function

Ciągi są podatne na moją okropną pisownię lub inne literówki. Plus czuję, że to czyta lepiej.


0

Mimo że instanceof może być nieco szybszy niż typeof , wolę drugi ze względu na taką możliwą magię:

function Class() {};
Class.prototype = Function;

var funcWannaBe = new Class;

console.log(funcWannaBe instanceof Function); //true
console.log(typeof funcWannaBe === "function"); //false
funcWannaBe(); //Uncaught TypeError: funcWannaBe is not a function

0

Jeszcze jeden przypadek, że można tylko zestawiać instanceof- zwraca wartość true lub false. Dzięki typeofniemu możesz uzyskać coś pod warunkiem


0

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


0

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 declarationi Funkcji . Zobaczymy, jak typeofi jak instanceofzachowamy się w tych dwóch różnych scenariuszach.

Utwórz funkcję za pomocą deklaracji funkcji:

function MyFunc(){  }

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

Możliwym wyjaśnieniem tak odmiennego wyniku jest to, że kiedy zadeklarowaliśmy funkcję, typeofmożemy zrozumieć, że jest to funkcja, ponieważ typeofsprawdza, 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:

var MyFunc2 = new Function('a','b','return a+b') // A function constructor is used 

typeof MyFunc2 == 'function' // true

MyFunc2 instanceof Function // true

Tutaj typeoftwierdzi, że MyFunc2jest to funkcja, jak również instanceofoperator.We już wiedzą typeofsprawdzić, czy MyFunc2zaimplementowane Callmetody lub not.As MyFunc2jest funkcją i implementuje callmetodę, to w jaki sposób typeofwie, że jest to function.On drugiej strony, użyliśmy function constructordo tworzenia MyFunc2, to staje się przykładem Function constructor. Dlatego instanceofteż postanawia true.

Co jest bezpieczniejsze w użyciu?

Jak widzimy w obu przypadkach typeofoperator może skutecznie twierdzić, że mamy tutaj do czynienia z funkcją, jest to bezpieczniejsze niż instanceof. instanceofzawiedzie w przypadku, function declarationponieważ function declarationsnie są instancją Function constructor.

Najlepsze praktyki :

Jak sugerował Gary Rafferty , najlepszym sposobem powinno być jednoczesne użycie zarówno typeof, jak i instanceof.

  function isFunction(functionItem) {

        return typeof(functionItem) == 'function' || functionItem instanceof Function;

  }

  isFunction(MyFunc) // invoke it by passing our test function as parameter

zostanie doceniona jakakolwiek konstruktywna krytyka tej odpowiedzi.
AL-zami

0

Aby być bardzo precyzyjnym, należy użyć instanceof, gdy wartość jest tworzona za pomocą konstruktora (zazwyczaj typy niestandardowe), np

var d = new String("abc")

podczas gdy typeof sprawdza wartości utworzone tylko przez przypisania dla np

var d = "abc"

0

nie musisz przytłaczać mnóstwem powyższych przykładów, pamiętaj tylko o dwóch punktach widzenia:

  1. typeof var;to jednoargumentowy operator zwróci typ pierwotny lub typ root var. tak, że powróci pierwotne typu ( string, number, bigint, boolean, undefined, a symbol) lub objecttypu.

  2. w przypadku obiektów wyższego poziomu, takich jak obiekty wbudowane (String, Number, Boolean, Array ..) lub obiekty złożone lub niestandardowe, wszystkie są objecttypu root, ale typ instancji zbudowany na nich jest różny (jak klasa OOP koncepcja dziedziczenia), tutaj a 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”.

nulljest szczególnym przypadkiem, który wydaje się prymitywny, ale w rzeczywistości jest szczególnym przypadkiem dla obiektu. Korzystanie a === nullzamiast sprawdzić null.

z drugiej strony functionjest także przypadkiem specjalnym, który jest wbudowanym obiektem, ale typeofzwracafunction

jak widać, instanceofmusisz przejść przez łańcuch prototypów, tymczasem typeofpo prostu sprawdź typ roota, aby łatwo zrozumieć, dlaczego typeofjest szybszy niżinstanceof


0

Zgodnie z dokumentacją MDN na temat typeof obiekty tworzone za pomocą słowa kluczowego „new” są typu „object”:

typeof 'bla' === 'string';

// The following are confusing, dangerous, and wasteful. Avoid them.
typeof new Boolean(true) === 'object'; 
typeof new Number(1) === 'object'; 
typeof new String('abc') === 'object';

O ile dokumentacja o instanceof punktów:

const objectString = new String('String created with constructor');
objectString instanceOf String; // returns true
objectString instanceOf Object; // returns true

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.

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.