2009-01-23 6 views
55

prostu ciekawi:Dlaczego 4 nie jest instancją numeru?

  • 4 Ilość instanceof => false
  • nowy numer (4) instanceof Number => true?

Dlaczego tak jest? To samo z ciągów:

  • 'some string' instanceof String zwraca false
  • new String('some string') instanceof String => true
  • String('some string') instanceof String zwraca również fałszywe
  • ('some string').toString instanceof String zwraca również fałszywe

dla obiektu, typy macierzy lub funkcja operatora instanceof działa zgodnie z oczekiwaniami. Po prostu nie wiem, jak to zrozumieć.

[nowe spostrzeżenia]

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 Newclass = function(){}; // anonymous Constructor function 
var Some = function Some(){}; // named Constructor function 
(5).is();      //=> Number 
'hello world'.is();   //=> String 
(new Newclass()).is();  //=> ANONYMOUS_CONSTRUCTOR 
(new Some()).is();   //=> Some 
/[a-z]/.is();     //=> RegExp 
'5'.is(Number);    //=> false 
'5'.is(String);    //=> true 
+0

musisz użyć 'Number.prototype.isPrototypeOf (inp)' - Twój sposób również działałby, gdyby został poprawnie wykonany: 'inp.constructor === Number'; może zawieść, ponieważ 'konstruktor' jest tylko właściwością prototypu i może zostać nadpisany! – Christoph

+0

Nie jestem pewien, czy rozumiem, co masz na myśli, gdy "można nadpisać". Nie oznacza to, że mogę nadpisać konstruktor innym konstruktorem (wypróbowałem go). Number.prototype.isPrototypeOf (4) zwraca wartość false, ale nie mogę tego użyć do sprawdzenia typu wartości pierwotnych, czy mam rację? – KooiInc

+0

To był cały punkt (prymitywny! == zawijany prymityw)! Sprawdzanie konstruktorów jest niebezpieczne z powodu 'obj [' constructor '] = ??? 'działa! Proponuję użyć mojej funkcji 'typeOf()'; do traktowania prymitywów i owiniętych prymitywów to samo, użyj 'if (typeOf (x) .toLowerCase() === 'string')' – Christoph

Odpowiedz

57

value instanceof Constructor jest taka sama jak Constructor.prototype.isPrototypeOf(value) i oba sprawdzić [[prototyp]] - łańcuch value do wystąpień określonego obiektu.

Łańcuchy i liczby są wartościami domyślnymi , a nie obiektami i dlatego nie mają [[Prototyp]], więc zadziałają tylko wtedy, gdy zawiniesz je w zwykłe obiekty (zwane "boksem" w Javie).

Ponadto, jak zauważył, String(value) i new String(value) robić różne rzeczy: Jeśli wywołanie funkcji konstruktora wbudowanych typów bez użycia operatora new, starają się przekształcić („cast”) argument do określonego rodzaju . Jeśli użyjesz operatora new, utworzą obiekt opakowania.

new String(value) jest mniej więcej równoznaczne z Object(String(value)), który zachowuje się tak samo jak new Object(String(value)).


Niektórzy bardziej na typy w JavaScript: ECMA-262 definiuje następujące typy pierwotne: Undefined, Null, Boolean, Ilość i String. Dodatkowo istnieje typ Obiekt dla rzeczy, które mają właściwości.

Na przykład, funkcje typu Object (oni po prostu mają szczególną właściwość o nazwie [[CALL]]), a null jest wartością pierwotną typu Null. Oznacza to, że wynik operatora typeof tak naprawdę nie zwraca typu wartości ...

Adnotacja, obiekty JavaScript mają inną właściwość o nazwie [[Klasa]]. Możesz go uzyskać przez Object.prototype.toString.call(value) (to powróci '[objectClassname]').Tablice i funkcje są typu Obiekt, ale ich klasy to Array i Funkcja.

Test dla klasy obiektu podany powyżej działa w przypadku niepowodzenia instanceof (np. Kiedy obiekty są przesyłane między granicami okna/ramki i nie współdzielą tych samych prototypów).


Również może chcesz sprawdzić to ulepszona wersja typeof:

function typeOf(value) { 
    var type = typeof value; 

    switch(type) { 
     case 'object': 
     return value === null ? 'null' : Object.prototype.toString.call(value). 
      match(/^\[object (.*)\]$/)[1] 

     case 'function': 
     return 'Function'; 

     default: 
     return type; 
    } 
} 

Dla prymitywów, zwróci ich typ w niższy przypadku, obiektów, zwróci ich klasa w w w.

Przykłady:

  • Do pierwotnych z typuIlość (np 5) powróci 'number' dla obiektów owinięciu klasyIlość (np new Number(5)), to zwróci 'Number';

  • Dla funkcji zwróci ona 'Function'.

Jeśli nie chcesz, aby rozróżniać pierwotnych wartości i obiektów otoki (z jakiegokolwiek powodu, prawdopodobnie zły), użyj typeOf(...).toLowerCase().

Znane błędy to niektóre wbudowane funkcje w IE, które są uznawane za 'Object' i zwracaną wartość 'unknown', gdy są używane z niektórymi obiektami COM +.

+0

@annakata: sprawdź ECMA-262. typy są nazywane Niezdefiniowane, Null, Boolean, Number, String i Object; nie ma znaczenia, co zwraca 'typeof' ... – Christoph

+0

@ Christophoph - to bardzo ważne, ponieważ obiekty opakowania są pisane wielkimi literami, a typy są małe i nic innego nie jest dostępne. Konwencja i praktyka odnoszą się zatem do typów danych pisanych małymi literami, co wyjaśniono tutaj: https://developer.mozilla.org/En/JS/Glossary – annakata

+0

@annakata: 'typeof' jest zepsuty - jego wartość zwracana nie ma znaczenia z rzeczywistymi typami! – Christoph

12

Możesz spróbować ocenić:

>>> typeof("a") 
"string" 
>>> typeof(new String("a")) 
"object" 
>>> typeof(4) 
"number" 
>>> typeof(new Number(4)) 
"object" 
1

Jest to niuans JavaScript, który znalazłem łapie trochę out. instanceof operatora zawsze będzie skutkować fałszem, jeśli LHS nie jest typem object.

Należy pamiętać, że new String('Hello World') nie daje wyniku w postaci string, ale jest to object. Operator new zawsze generuje obiekt. Widzę tego typu rzeczy: -

function fnX(value) 
{ 
    if (typeof value == 'string') 
    { 
      \\Do stuff 
    } 
} 
fnX(new String('Hello World')); 

Oczekuje się, że „Do Stuff” będzie się działo, ale to nie dlatego, że typeof wartością jest obiekt.

2

Jak stwierdzono w odpowiedzi Christopha, literały łańcuchowe i liczbowe nie są takie same jak obiekty String i Number.Jeśli użyć dowolnego napisu lub numer metod na dosłowne, powiedzmy

'a string literal'.length 

Dosłowne jest czasowo przekształcić w obiekt, metoda jest wywoływana i obiekt zostanie odrzucony.
Literały mają pewne wyraźne zalety w stosunku do obiektów.

//false, two different objects with the same value 
alert(new String('string') == new String('string')); 

//true, identical literals 
alert('string' == 'string'); 

Zawsze używaj literałów, aby uniknąć nieoczekiwanego zachowania!
Można użyć numeru() i String(), aby typecast jeśli trzeba:

//true 
alert(Number('5') === 5) 

//false 
alert('5' === 5) 
0

W przypadku numerów prymitywnych, metoda isNaN może również pomóc.

Powiązane problemy