Sprawdź, czy zmienna jest ciągiem w JavaScript


1737

Jak mogę ustalić, czy zmienna jest łańcuchem, czy czymś innym w JavaScript?

Odpowiedzi:


1689

Możesz użyć typeofoperatora:

var booleanValue = true; 
var numericalValue = 354;
var stringValue = "This is a String";
var stringObject = new String( "This is a String Object" );
alert(typeof booleanValue) // displays "boolean"
alert(typeof numericalValue) // displays "number"
alert(typeof stringValue) // displays "string"
alert(typeof stringObject) // displays "object"

Przykład z tej strony . (Przykład został jednak nieco zmodyfikowany).

Nie będzie to działało zgodnie z oczekiwaniami w przypadku ciągów utworzonych za pomocą new String(), ale jest to rzadko używane i zalecane przeciwko [1] [2] . Zobacz inne odpowiedzi, jak sobie z nimi poradzić, jeśli chcesz.


  1. Przewodnik po stylu JavaScript w Google mówi, że nigdy nie należy używać pierwotnych opakowań obiektów .
  2. Douglas Crockford zalecił wycofanie pierwotnych opakowań obiektów .

45
@ Wolfy87 Należy pamiętać, że istnieją przypadki, w których typof stringValue może zwracać „obiekt” zamiast „ciąg”. Zobacz komentarze do mojej odpowiedzi.
DRAX

163
Moja preferowana odpowiedź. Argumentem przemawiającym przeciwko niemu jest to, że „zawodzi” w przypadku łańcuchów opakowanych obiektowo new String('foo'), ale to nie ma znaczenia, ponieważ łańcuchy obiektowe są bezwartościową funkcją, której nie powinieneś używać. Przewodnik po stylu Google zabrania ich , Douglas Crockford chce, aby były przestarzałe i żadne biblioteki ich nie używają. Udawaj, że nie istnieją i używaj ich typeofbez strachu.
Mark Amery


2
@DanielLe, ponieważ zaproponował zastąpienie, które naprawia niektóre problemy, a nie dlatego, że zasadniczo jest temu przeciwny.
Vsevolod Golovanov,

4
Jeśli powoduje to bóle głowy, 99,99% czasu wynika z niewłaściwej struktury kodu. To nie jest wina NaN za to, że istnieje i robi to, co robi, należy o tym pamiętać, uczyć się od niego i pamiętać o tym, kiedy następnym razem będziesz pracować z kodem, który może to dać.
Mike 'Pomax' Kamermans

1905

Oto, co działa dla mnie:

if (typeof myVar === 'string' || myVar instanceof String)
// it's a string
else
// it's something else

77
Czy „myVar instanceof String” robi coś więcej niż „typeof myVar == 'string”?
svth

81
@svth Pamiętam. W JavaScript możesz mieć zmienny typ łańcucha lub typ obiektu, który jest klasą String (to samo - oba są łańcuchami - ale inaczej zdefiniowane), dlatego jest podwójnie sprawdzany.
DRAX

38
var somevar = new String ('somestring') console.log (typeof somevar) // obiekt
Danubian Sailor

82
-1, ponieważ instanceofsprawdzanie tutaj jest bezcelowe, chyba że podążasz za jakimś bardzo niezwykłym praktyk kodowania, a ta odpowiedź nic nie wyjaśnia, co robi i dlaczego możesz go użyć. Jedynym powodem, dla którego będziesz go kiedykolwiek potrzebować, jest użycie ciągów zawijanych w obiektach, ale ciągi zawijane w obiekty są bezwartościową funkcją, której nikt nie używa, a Google i Crockford potępiają jako złą praktykę ( google-styleguide.googlecode.com/svn/ trunk /… , crockford.com/javascript/recommend.html ).
Mark Amery

78
Usilnie nie zgadzam się z tym, że należy unikać pisania solidnego kodu, który poprawnie obsługuje mało prawdopodobne przypadki. Sprawdzanie obu typeofi instanceofwydaje się dobrą radą, jeśli Twój kod może zostać wywołany przez inne osoby. @ MarkAmery'spostmessage krawędzi znaczenie, jeśli pytasz „co ja właśnie postmessaged?”. - ale można oczekiwać, że zostanie to obsłużone w interfejsie i nie będzie mogło się rozprzestrzeniać. Gdzie indziej, wydaje się poprawne posługiwanie się nieaktualnymi metodami kodowania, nawet jeśli niektóre estetyki JS ich nie pochwalają. NIGDY nie komentuj swojego kodu jako akceptującego String, chyba że tak naprawdę!
Dewi Morgan

157

Ponieważ ponad 580 osób głosowało na niepoprawną odpowiedź, a ponad 800 głosowało na działającą, ale podobną do strzelby odpowiedź, pomyślałem, że warto powtórzyć moją odpowiedź w prostszej formie, którą każdy może zrozumieć.

function isString(x) {
  return Object.prototype.toString.call(x) === "[object String]"
}

Lub inline (mam do tego konfigurację UltiSnip):

Object.prototype.toString.call(myVar) === "[object String]"

Do Twojej wiadomości, odpowiedź Pablo Santa Cruz jest zła, ponieważ typeof new String("string")jestobject

Odpowiedź DRAX-a jest dokładna i funkcjonalna i powinna być poprawną odpowiedzią (ponieważ Pablo Santa Cruz jest zdecydowanie niepoprawna i nie będę się kłócił przeciwko głosowaniu powszechnemu).

Jednak ta odpowiedź jest również zdecydowanie poprawna i faktycznie najlepsza odpowiedź (z wyjątkiem być może sugestii użycia lodash / podkreślenia ). zrzeczenie się odpowiedzialności: Przyczyniałem się do bazy kodu lodash 4.

Moja pierwotna odpowiedź (która oczywiście przeleciała nad wieloma głowami) brzmi:

Przekodowałem to z underscore.js:

['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'].forEach( 
    function(name) { 
        window['is' + name] = function(obj) {
              return toString.call(obj) == '[object ' + name + ']';
    }; 
});

To zdefiniuje isString, isNumber itp.


W Node.js można to zaimplementować jako moduł:

module.exports = [
  'Arguments',
  'Function', 
  'String', 
  'Number', 
  'Date', 
  'RegExp'
].reduce( (obj, name) => {
  obj[ 'is' + name ] = x => toString.call(x) == '[object ' + name + ']';
  return obj;
}, {});

[edytuj]: Object.prototype.toString.call(x)działa również w celu rozdzielenia funkcji i funkcji asynchronicznych:

const fn1 = () => new Promise((resolve, reject) => setTimeout(() => resolve({}), 1000))
const fn2 = async () => ({})

console.log('fn1', Object.prototype.toString.call(fn1))
console.log('fn2', Object.prototype.toString.call(fn2))


11
Polecasz underscore.js (z jakiego dziwnego powodu?), Ale nie używasz go tutaj. Ponadto zanieczyszczasz globalną przestrzeń nazw funkcjami. W node.js chcesz utworzyć moduł, który by te wszystkie funkcje (ty może używać global || windowzamiast windowjednak, że byłoby to złe podejście do rozwiązania problemu nie powinien mieć w pierwszej kolejności).
Benjamin Gruenbaum

19
@BenjaminGruenbaum Przyszedłem szukać odpowiedzi na pytanie OP i nie podobały mi się żadne odpowiedzi. Sprawdziłem więc, co zrobiło podkreślenie, i pomyślałem, że jest wystarczająco fajny, aby trochę wyodrębnić i zmodyfikować (aby uniknąć konieczności ładowania biblioteki podkreśleń). Wyjaśnię mój post.
Orwellophile,

2
@Orwellophile Fajnie, rozumiem teraz, twoja oryginalna odpowiedź została sformułowana tak, jakbyś sugerował sam podkreślenie. Osobiście po prostu sprawdziłbym, myObject+"" === myObjectczy obiekt jest ciągiem (a nawet lepiej, nie pisałbym sprawdzania w systemie typu opartym na zachowaniu).
Benjamin Gruenbaum,

18
@Orwellophile, w jaki sposób jest to lepsze niż odpowiedź DRAX?
Pacerier

3
JS obsługuje łatanie małp, więc można ponownie zdefiniować toStringw Object.prototype. Twierdzę więc, że poleganie na toStringsprawdzaniu typu obiektu jest w najlepszym razie złą praktyką.
Andre Rodrigues

84

Polecam korzystanie z wbudowanych funkcji jQuery lub lodash / Underscore . Są prostsze w użyciu i łatwiejsze do odczytania.

Każda funkcja obsłuży wspomniany przypadek DRAX ... to znaczy oba sprawdzają, czy (A) zmienna jest literałem ciągu lub (B) jest instancją obiektu String. W obu przypadkach funkcje te poprawnie identyfikują wartość jako ciąg.

lodash / Underscore.js

if(_.isString(myVar))
   //it's a string
else
   //it's something else

jQuery

if($.type(myVar) === "string")
   //it's a string
else
   //it's something else

Zobacz dokumentację lodash dla _.isString (), aby uzyskać więcej informacji.

Zobacz dokumentację jQuery dla $ .type () po więcej szczegółów.


96
Jest to podstawa tego, co jest nie tak ze społecznością JS - sprawdzanie względem typu prymitywnego jest jednowierszowe i obejmuje tylko konstrukcję języka (jedną z podstawowych), ale zalecamy korzystanie z biblioteki zewnętrznej. Jeśli ktoś już korzysta z jednej z tych bibliotek, może to być dobry pomysł, ale pobranie ich tylko w tym celu zamiast zwykłego sprawdzania typu jest przesadą.
Rafał Wrzeszcz

5
Zgodzę się z Rafałem. Wszędzie widzę, że poprawia to „czytelność” korzystania z jednej z tych bibliotek zewnętrznych. Jeśli znasz JavaScript, jest to łatwiejsze do odczytania niż biblioteka zewnętrzna, której nie używałeś. _.every()jest trochę mylące w użyciu i coś tak prostego, jak _.isBoolean()mylące devy w moim towarzystwie. Deweloper błędnie pomyślał, że byłoby fałszem, gdyby wartość była wartością logiczną i była fałszywa. Angielski jest dla mnie łatwiejszy do odczytania niż niemiecki, ponieważ nie znam niemieckiego. Naucz się JavaScript, a wszystko to będzie miało sens.
John Harding,

20
@ RafałWrzeszcz Te biblioteki są dość szeroko stosowane i zapewniają bardzo przydatną (i przetestowaną) funkcjonalność. Zwłaszcza lodash. Nie poleciłbym, aby ktoś pobierał bibliotekę tylko dla tego jednego rozwiązania ... ale zalecałbym każdemu programistowi javascript pobranie tej biblioteki i zobaczenie, czego brakuje. ;)
ClearCloud8

13
Wszystkim wam brakuje sensu biblioteki takiej jak Lodash: nie prędkości. Nie „łatwość rozwoju”. Powód korzystania z biblioteki takiej jak Lodash zapewnia „obronność” przed problemami, które wysadzą twoją aplikację js. Błędy krytyczne zdarzają się, gdy próbujesz wykonać operacje na łańcuchach obiektu (lub odwrotnie), a Lodash zapewnia ogromną wartość w zapobieganiu tym błędom.
random_user_name

1
Pamiętaj, że wiele osób będzie to robić w środowisku węzłowym lub podobnym do węzła, a bardzo niewiele osób będzie tam używać jQuery.
Matt Fletcher

35
function isString (obj) {
  return (Object.prototype.toString.call(obj) === '[object String]');
}

Widziałem to tutaj:

http://perfectionkills.com/instanceof-consanted-harmful-or-how-to-write-a-robust-isarray/


4
Myślę, że to rozwiązanie jest najbardziej niezawodne, ponieważ obsługuje scenariusze odniesienia między ramkami / między oknami, jak wspomniano w adresie URL podanym w odpowiedzi.
ewh

1
Świetna odpowiedź, wygląda na to, że Underscore.js również korzysta z tej metody!
Daan

1
@ling Ciekawe, dlaczego umieszczasz nawiasy Object.prototype.toString.call(obj) === '[object String]'?
StubbornShowaGuy,

@ Earlee Masz na myśli (x === y)lepszą czytelność niż x === y?
StubbornShowaGuy

@StubbornShowaGuy Moim zdaniem tak. Chodzi również o spójność. Osobiście zawsze zwracam wartość w nawiasach.
Aquarelle

28

Najlepszym sposobem:

var s = 'String';
var a = [1,2,3];
var o = {key: 'val'};

(s.constructor === String) && console.log('its a string');
(a.constructor === Array) && console.log('its an array');
(o.constructor === Object) && console.log('its an object');
(o.constructor === Number || s.constructor === Boolean) && console.log('this won\'t run');

Każdy z nich został skonstruowany za pomocą odpowiedniej funkcji klasy, takiej jak „new Object ()” itp.

Ponadto, pisanie kaczką: „Jeśli wygląda jak kaczka, chodzi jak kaczka i pachnie jak kaczka - to musi być szyk”. Oznacza to, sprawdź jej właściwości.

Mam nadzieję że to pomoże.

Edytować; 12.05.2016

Pamiętaj, że zawsze możesz używać kombinacji podejść. Oto przykład użycia wbudowanej mapy działań z typof :

var type = { 'number': Math.sqrt.bind(Math), ... }[ typeof datum ];

Oto bardziej „rzeczywisty” przykład użycia map wbudowanych:

function is(datum) {
    var isnt = !{ null: true, undefined: true, '': true, false: false, 0: false }[ datum ];
    return !isnt;
}
console.log( is(0), is(false), is(undefined), ... );  // >> true true false

Ta funkcja użyłaby [niestandardowego] „rzutowania typu” - raczej „mapowania typu - / - wartości” - aby dowiedzieć się, czy zmienna rzeczywiście „istnieje”. Teraz możesz rozdzielić te paskudne włosy pomiędzy nulli 0!

Wiele razy nawet nie dbasz o jego typ . Innym sposobem na uniknięcie pisania jest łączenie zestawów typu kaczka:

this.id = "998";  // use a number or a string-equivalent
function get(id) {
    if (!id || !id.toString) return;
    if (id.toString() === this.id.toString()) http( id || +this.id );
    // if (+id === +this.id) ...;
}

Oba Number.prototype i String.prototype mają .toString() method. Właśnie upewniłeś się, że ekwiwalent ciągu liczby był taki sam, a następnie upewniłeś się, że przekazałeś go do httpfunkcji jako Number. Innymi słowy, nie obchodziło nas nawet, jaki był tego typu.

Mam nadzieję, że dajesz więcej do pracy :)


Będziesz potrzebować innego sprawdzania zwykłych starych liczb, ponieważ próba przejęcia ich właściwości konstruktora zakończy się niepowodzeniem:

@torazaburo Teraz działało dla mnie dobrze w konsoli Chrome. Co sprawia, że ​​myślisz, że to nie zadziała?
Mark Amery

2
@torazaburo Możesz zagrać w asercje ( (o.constructor === Number || s.constructor === Boolean)). Anegdotycznie parseInti NaNsą delikatnymi, ale potężnymi narzędziami. Pamiętaj tylko, że NIE-Liczba nie jest NIE-Liczba i można zdefiniować niezdefiniowany.
Cody

1
a.constructor === Tablica jest niepoprawna i może czasami zawieść, użyj Array.isArray patrz web.mit.edu/jwalden/www/isArray.html
axkibe

1
Zgadzam się, nie jest to niezawodne. Lepszym sposobem jest użycie sprawdzania właściwości - W tej chwili jest to jedyny naprawdę bezpieczny sposób. Przykład: if(thing.call) { 'its a function'; }lub if(thing.defineProperties) { 'its an object'; }. Dzięki za wkład, axkibe!
Cody

17

Nie rozumiem szczerze, dlaczego typeofw takim przypadku nie można po prostu użyć :

if (typeof str === 'string') {
  return 42;
}

Tak, nie powiedzie się w przypadku łańcuchów opakowanych w obiekty (np. new String('foo')), Ale są one powszechnie uważane za złą praktykę i większość współczesnych narzędzi programistycznych może zniechęcać do ich używania. (Jeśli widzisz, po prostu to napraw!)

Object.prototype.toStringSztuką jest coś, co wszyscy deweloperzy front-end został uznany za winnego robi jeden dzień w ich karierze, ale nie pozwól, by oszukać jego polerowania mądry: pęknie jak tylko coś małpy plastra prototyp obiektu:

const isString = thing => Object.prototype.toString.call(thing) === '[object String]';

console.log(isString('foo'));

Object.prototype.toString = () => 42;

console.log(isString('foo'));


15

Lubię używać tego prostego rozwiązania:

var myString = "test";
if(myString.constructor === String)
{
     //It's a string
}

3
Czym różni się to od odpowiedzi Cody'ego 4 lata później?
Jonathan H

3
@Sheljohn Cody odpowiedź jest świetna. Moja odpowiedź (pełny tekst) jest krótsza i od razu do rzeczy.
Pytałeś

W związku z tym wymagałoby to sposobu radzenia sobie z undefinedi null, i wciąż uzyskania właściwej odpowiedzi dla pustych ciągów (zarówno ''i new String('')).
MikeBeaton

@MikeBeaton Nie ma problemu: (mystring || false) && mystring.constructor === String. Użyłem wartości false, jeśli jest używana w funkcji, która musi zwrócić wartość logiczną.
alans

13

To świetny przykład tego, dlaczego wydajność ma znaczenie:

Wykonanie czegoś tak prostego jak testowanie łańcucha może być kosztowne, jeśli nie zostanie wykonane poprawnie.

Na przykład, jeśli chciałbym napisać funkcję sprawdzającą, czy coś jest ciągiem, mógłbym to zrobić na dwa sposoby:

1) const isString = str => (Object.prototype.toString.call(str) === '[object String]');

2) const isString = str => ((typeof str === 'string') || (str instanceof String));

Oba są dość proste, więc co może wpłynąć na wydajność? Mówiąc ogólnie, wywołania funkcji mogą być kosztowne, szczególnie jeśli nie wiesz, co dzieje się w środku. W pierwszym przykładzie istnieje wywołanie funkcji do metody toString obiektu. W drugim przykładzie nie ma wywołań funkcji, ponieważ typeof i instanceof są operatorami. Operatory są znacznie szybsze niż wywołania funkcji.

Podczas testowania wydajności przykład 1 jest o 79% wolniejszy niż przykład 2!

Zobacz testy: https://jsperf.com/isstringtype


Łącze testowe nie działa, ale wierzę ci. Tego rodzaju informacje są bardzo ważne. IMHO powinna to być, jeśli nie najbardziej pozytywna odpowiedź, przynajmniej najbardziej pozytywny komentarz do bieżącej wiodącej odpowiedzi.
Coderer

typeof str === 'string' || str instanceof String(może upuścić nawias, który wolę w if (..)przypadkach); niezależnie od tego, sprawdzanie zarówno typów pierwotnych, jak i typów obiektów w # 2 jest jasne i wystarczające. Te kontrole i tak powinny być „rzadkie”.
user2864740,

12
if (s && typeof s.valueOf() === "string") {
  // s is a string
}

Działa zarówno z literałami łańcuchowymi, jak let s = 'blah'i obiektowymilet s = new String('blah')


3
Uwaga! Nie powiedzie się to na pustych ciągach, ponieważ są falsey.
Philipp Sumi


5

Myślę, że rozwiązanie @customcommander powinno wystarczyć w 90% twoich przypadków:

typeof str === 'string'

Powinien ci dobrze służyć (po prostu dlatego, że zwykle nie ma powodu, aby to mieć) new String('something') w kodzie).

Jeśli jesteś zainteresowany obsługą String obiektu (na przykład oczekujesz, że różni się od firmy trzeciej), to użycie lodash jako sugerowanej @ ClearCloud8 wydaje się jasnym, prostym i eleganckim rozwiązaniem.

Sugerowałbym jednak ostrożność w stosunku do bibliotek takich jak lodash ze względu na ich wielkość. Zamiast robić

import _ from 'lodash'
...
_.isString(myVar)

Co przynosi cały ogromny obiekt lodash, sugerowałbym coś takiego:

import { isString as _isString } from 'lodash'
...
_isString(myVar)

Z prostym pakietowaniem powinieneś być w porządku (odnoszę się tutaj do kodu klienta).


dlaczego === kiedy == wystarczy
zavr

4

Jeśli pracujesz w środowisku node.js, możesz po prostu użyć wbudowanej funkcji isString w utils.

const util = require('util');
if (util.isString(myVar)) {}

Edycja: jak wspomniano @Jehy, jest to przestarzałe od wersji 4.


Czy jest jakaś wymiana?
Anthony Kong

3
Dokumenty mówią „Użyj typeof value === 'string'zamiast”.
Rogers

x = new String('x'); x.isString(x);zwraca false . Istnieje util.types.isStringObject()jednak wartość false dla x = 'x'ciągu typu. Dwie funkcje narzędziowe, które absolutnie nie zapewniają żadnej użyteczności ...
spinkus

4

Poniższa metoda sprawdzi, czy jakakolwiek zmienna jest ciągiem (w tym zmienne, które nie istnieją ).

const is_string = value => {
  try {
    return typeof value() === 'string';
  } catch (error) {
    return false;
  }
};

let example = 'Hello, world!';

console.log(is_string(() => example)); // true
console.log(is_string(() => variable_doesnt_exist)); // false

3

Odkryłem również, że to też działa dobrze i jest znacznie krótsze niż w innych przykładach.

if (myVar === myVar + '') {
   //its string
} else {
   //its something else
}

Łącząc puste cudzysłowy, zamienia wartość w ciąg znaków. Jeśli myVarjest już ciągiem, to instrukcja if się powiodła.


3
Jedynym problemem jest to, że wymuszasz zmienną, gdy chcesz sprawdzić jej typ. To wydaje mi się trochę drogie w porównaniu z typeof.
Olical

1
Więc masz rację. jsperf powiedział, że jest o około 20% wolniejszy niż, typeofale wciąż nieco szybszy niż toString. Tak czy inaczej, chyba podoba mi się składnia wymuszania.
Chris Dolphin

4
nie działa to z typem String; var s = new String('abc'); > s === s + '' > false
user5672998,

1
Nie działa z new Stringcus, który tworzy rodzaj object. w3schools.com/js/tryit.asp?filename=tryjs_string_object2
Chris Dolphin

Dobra myśl, ale pomija przypadek ciągów zawiniętych w obiekty.
Anthony Rutledge

3
var a = new String('')
var b = ''
var c = []

function isString(x) {
  return x !== null && x !== undefined && x.constructor === String
}

console.log(isString(a))
console.log(isString(b))
console.log(isString(c))

Dlaczego musisz sprawdzać, czy wartość null lub undefined jest taka, że ​​x.constructor === Ciąg również zwraca wartość false dla null lub undefined?
Jules Manson

1
@JulesManson: Zgłasza błąd, a nie produkuje false.
Ry-

3

Uważam, że ta prosta technika jest przydatna do sprawdzania typu dla String -

String(x) === x // true, if x is a string
                // false in every other case

const test = x =>
  console.assert
    ( String(x) === x
    , `not a string: ${x}`
    )

test("some string")
test(123)           // assertion failed
test(0)             // assertion failed
test(/some regex/)  // assertion failed
test([ 5, 6 ])      // assertion failed
test({ a: 1 })      // assertion failed
test(x => x + 1)    // assertion failed

Ta sama technika działa również dla Number -

Number(x) === x // true, if x is a number
                // false in every other case

const test = x =>
  console.assert
    ( Number(x) === x
    , `not a number: ${x}`
    )

test("some string") // assertion failed
test(123)           
test(0)             
test(/some regex/)  // assertion failed
test([ 5, 6 ])      // assertion failed
test({ a: 1 })      // assertion failed
test(x => x + 1)    // assertion failed

A dla RegExp -

RegExp(x) === x // true, if x is a regexp
                // false in every other case

const test = x =>
  console.assert
    ( RegExp(x) === x
    , `not a regexp: ${x}`
    )

test("some string") // assertion failed
test(123)           // assertion failed
test(0)             // assertion failed
test(/some regex/)  
test([ 5, 6 ])      // assertion failed
test({ a: 1 })      // assertion failed
test(x => x + 1)    // assertion failed

To samo dla obiektu -

Object(x) === x // true, if x is an object
                // false in every other case

NB, wyrażenia regularne, tablice i funkcje są również uważane za obiekty.

const test = x =>
  console.assert
    ( Object(x) === x
    , `not an object: ${x}`
    )

test("some string") // assertion failed
test(123)           // assertion failed
test(0)             // assertion failed
test(/some regex/)  
test([ 5, 6 ])      
test({ a: 1 })      
test(x => x + 1)    

Ale sprawdzanie tablicy jest nieco inne -

Array.isArray(x) === x // true, if x is an array
                       // false in every other case

const test = x =>
  console.assert
    ( Array.isArray(x)
    , `not an array: ${x}`
    )

test("some string") // assertion failed
test(123)           // assertion failed
test(0)             // assertion failed
test(/some regex/)  // assertion failed
test([ 5, 6 ])      
test({ a: 1 })      // assertion failed
test(x => x + 1)    // assertion failed

Ta technika nie działa jednak w przypadku funkcji -

Function(x) === x // always false

var x = new String(x); String(x)===xzwraca false jednak ({}).toString.call(x).search(/String/)>0zawsze wraca po sznurki
niezsynchronizowane

1
function isClass(x,re){return ({}).toString.call(x).search(re)>0;}; isClass("hello",/String/) lub isClass(3,/Number/)lubisClass(null,/Null/)
niezsynchronizowany

2

Prostym rozwiązaniem byłoby:

var x = "hello"

if(x === x.toString()){
// it's a string 
}else{
// it isn't
}

1
to nie sprawdza, czy jest to ciąg znaków. Przekształca się w ciąg znaków, wiele rzeczy ma swoją toString()funkcję
Muhammad Umer

7
@MuhammadUmer Tak, konwertuje go na ciąg, ale następnie sprawdza tożsamość w stosunku do oryginalnej wartości, co będzie Prawdą, jeśli oryginalna wartość jest również ciągiem.
MrWhite

4
to jest złe: nie można ślepo wywoływać .toStringżadnych wartości; spróbuj, jeśli x, który ma być sprawdzony, ma wartość NULL lub jest niezdefiniowany, wyjątek
zgłaszania

1
Pomysł jest nadal użyteczny. x === Łańcuch (x) jest bezpieczny i działa.
Márton Sári

Naprawdę? To rozwiązanie wydaje mi się zbyt dziwne, ponieważ toString()metoda może zostać przesłonięta i może zgłosić wyjątek (z powodu określonej implementacji), a sprawdzenie na pewno nie zadziała. Główną ideą jest to, że nie powinieneś wywoływać metod niezwiązanych z tym, co chcesz uzyskać. Nie mówię nawet o niepotrzebnych kosztach związanych z tą toStringmetodą. Downvoting.
Rustem Zinnatullin

2

Pomocnik Typechecker:

function isFromType(variable, type){
  if (typeof type == 'string') res = (typeof variable == type.toLowerCase())
  else res = (variable.constructor == type)
  return res
}

stosowanie:

isFromType('cs', 'string') //true
isFromType('cs', String) //true
isFromType(['cs'], Array) //true
isFromType(['cs'], 'object') //false

Również jeśli chcesz, aby był rekurencyjny (jak tablica, która jest obiektem), możesz użyć instanceof.

( ['cs'] instanceof Object //true)


2

Idę inną drogą do pozostałych tutaj, które próbują stwierdzić, czy zmienna jest konkretnym typem, czy też członkiem określonego zestawu.
JS opiera się na kaczce; jeśli coś trzeszczy jak struna, możemy i powinniśmy użyć tego jak struny.

Jest 7ciąg? Dlaczego więc /\d/.test(7)działa?
Jest {toString:()=>('hello there')}ciąg? Dlaczego więc ({toString:()=>('hello there')}) + '\ngeneral kenobi!'działa?
To nie są pytania, które powinny powyższe prace, chodzi o to robią.

Więc stworzyłem duckyString()funkcję
Poniżej testuję wiele przypadków, które nie są pokrywane przez inne odpowiedzi. Dla każdego kodu:

  • ustawia zmienną łańcuchową
  • wykonuje na nim identyczną operację na łańcuchach i prawdziwy ciąg, aby porównać wyniki (udowadniając, że można je traktować jak ciągi)
  • konwertuje ciąg podobny do ciągu rzeczywistego, aby pokazać duckyString()normalizację danych wejściowych dla kodu, który oczekuje rzeczywistych ciągów
text = 'hello there';
out(text.replace(/e/g, 'E') + ' ' + 'hello there'.replace(/e/g, 'E'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');

text = new String('oh my');
out(text.toUpperCase() + ' ' + 'oh my'.toUpperCase());
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');

text = 368;
out((text + ' is a big number') + ' ' + ('368' + ' is a big number'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');

text = ['\uD83D', '\uDE07'];
out(text[1].charCodeAt(0) + ' ' + '😇'[1].charCodeAt(0));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');

function Text() { this.math = 7; }; Text.prototype = {toString:function() { return this.math + 3 + ''; }}
text = new Text();
out(String.prototype.match.call(text, '0') + ' ' + text.toString().match('0'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');

Jest to w tym samym stylu, co !!xw przeciwieństwie do x===truetestowania, czy coś jest podobne do tablicy, zamiast konieczności rzeczywistej tablicy.
obiekty jQuery; czy są tablice? Nie. Czy są wystarczająco dobre? Tak, możesz je dobrze uruchomić przez Array.prototypefunkcje.
Jest to elastyczność, która daje JS jego moc i testowania dla ciągów specjalnie czyni kod mniej interoperacyjne.

Wynikiem powyższego jest:

hEllo thErE hEllo thErE
Is string? true "hello there"

OH MY OH MY
Is string? true "oh my"

368 is a big number 368 is a big number
Is string? true "368"

56839 56839
Is string? true "😇"

0 0
Is string? true "10"

Chodzi o to, dlaczego chcesz wiedzieć, czy coś jest struną.
Jeśli, tak jak ja, przybyłeś tutaj z Google'a i chciałeś zobaczyć, czy coś jest w stylu sznurka , oto odpowiedź.
Nie jest nawet drogi, chyba że pracujesz z naprawdę długimi lub głęboko zagnieżdżonymi tablicami char.
Wynika to z faktu, że chodzi tu tylko o instrukcje if, żadne wywołania funkcji takie jak .toString().
Z wyjątkiem sytuacji, gdy próbujesz sprawdzić, czy tablica toString()znaków z obiektami, które mają tylko znaki wielobajtowe, w takim przypadku nie ma innego sposobu sprawdzenia niż wykonanie łańcucha i policzenie znaków, które bajty tworzą odpowiednio

function duckyString(string, normalise, unacceptable) {
    var type = null;
    if (!unacceptable)
        unacceptable = {};
    if (string && !unacceptable.chars && unacceptable.to == null)
        unacceptable.to = string.toString == Array.prototype.toString;

    if (string == null)
        ;

    //tests if `string` just is a string
    else if (
        !unacceptable.is &&
        (typeof string == 'string' || string instanceof String)
    )
        type = 'is';

    //tests if `string + ''` or `/./.test(string)` is valid
    else if (
        !unacceptable.to &&
        string.toString && typeof string.toString == 'function' && string.toString != Object.prototype.toString
    )
        type = 'to';

    //tests if `[...string]` is valid
    else if (
        !unacceptable.chars &&
        (string.length > 0 || string.length == 0)
    ) {
        type = 'chars';
        //for each char
        for (var index = 0; type && index < string.length; ++index) {
            var char = string[index];

            //efficiently get its length
            var length = ((duckyString(char, false, {to:true})) ?
                char :
                duckyString(char, true) || {}
            ).length;

            if (length == 1)
                continue;

            //unicode surrogate-pair support
            char = duckyString(char, true);
            length = String.prototype[Symbol && Symbol.iterator];
            if (!(length = length && length.call(char)) || length.next().done || !length.next().done)
                type = null;
        }
    }

    //return true or false if they dont want to auto-convert to real string
    if (!(type && normalise))
        //return truthy or falsy with <type>/null if they want why it's true
        return (normalise == null) ? type != null : type;

    //perform conversion
    switch (type) {
    case 'is':
        return string;
    case 'to':
        return string.toString();
    case 'chars':
        return Array.from(string).join('');
    }
}

Zawarte są opcje do

  • zapytaj, która metoda uznała to za ciąg-y
  • wyklucz metody wykrywania ciągów (np. jeśli nie lubisz .toString())

Oto więcej testów, ponieważ jestem uzupełniaczem:

out('Edge-case testing')
function test(text, options) {
    var result = duckyString(text, false, options);
    text = duckyString(text, true, options);
    out(result + ' ' + ((result) ? '"' + text + '"' : text));
}
test('');
test(null);
test(undefined);
test(0);
test({length:0});
test({'0':'!', length:'1'});
test({});
test(window);
test(false);
test(['hi']);
test(['\uD83D\uDE07']);
test([['1'], 2, new String(3)]);
test([['1'], 2, new String(3)], {chars:true});
  • Wszystkie negatywne przypadki wydają się być uwzględnione
  • Powinno to działać w przeglądarkach> = IE8
  • Tablice znaków z wieloma bajtami obsługiwane w przeglądarkach z obsługą iteratora ciągów

Wynik:

Edge-case testing
is ""
null null
null null
to "0"
chars ""
chars "!"
null null
chars ""
to "false"
null null
chars "😇"
chars "123"
to "1,2,3"

1

Wystarczy, aby rozwinąć @ Drax za odpowiedź , chciałbym to zrobić:

function isWhitespaceEmptyString(str)
{
    //RETURN:
    //      = 'true' if 'str' is empty string, null, undefined, or consists of white-spaces only
    return str ? !(/\S/.test(str)) : (str === "" || str === null || str === undefined);
}

Uwzględnia także nulls i undefinedtypy oraz zajmuje się typami nieciągłymi, takimi jak 0.


1

To mi wystarczy.

OSTRZEŻENIE: To nie jest idealne rozwiązanie. Zobacz dół mojego postu.

Object.prototype.isString = function() { return false; };
String.prototype.isString = function() { return true; };

var isString = function(a) {
  return (a !== null) && (a !== undefined) && a.isString();
};

I możesz użyć tego jak poniżej.

//return false
isString(null);
isString(void 0);
isString(-123);
isString(0);
isString(true);
isString(false);
isString([]);
isString({});
isString(function() {});
isString(0/0);

//return true
isString("");
isString(new String("ABC"));

OSTRZEŻENIE: Działa to niepoprawnie w przypadku:

//this is not a string
var obj = {
    //but returns true lol
    isString: function(){ return true; }
}

isString(obj) //should be false, but true

-1

Możesz użyć tej funkcji do określenia rodzaju czegokolwiek:

var type = function(obj) {
    return Object.prototype.toString.apply(obj).replace(/\[object (.+)\]/i, '$1').toLowerCase();
};

Aby sprawdzić, czy zmienna jest ciągiem:

type('my string') === 'string' //true
type(new String('my string')) === 'string' //true
type(`my string`) === 'string' //true
type(12345) === 'string' //false
type({}) === 'string' // false

https://codepen.io/patodiblasi/pen/NQXPwY?editors=0012


-2

Nie jestem pewien, czy masz na myśli wiedzieć, czy jest to typ stringniezależnie od jego zawartości, czy też jego zawartość jest liczbą lub łańcuchem, niezależnie od jego typu.

Aby wiedzieć, czy jego typ jest ciągiem, na to już odpowiedziano.
Ale żeby wiedzieć na podstawie jego zawartości, czy jest to ciąg znaków, czy liczba, użyłbym tego:

function isNumber(item) {
    return (parseInt(item) + '') === item;
}

I dla niektórych przykładów:

isNumber(123);   //true
isNumber('123'); //true
isNumber('123a');//false
isNumber('');    //false

Wydaje mi się, że pierwotnie pytałem, jak sprawdzić typ, chociaż wtedy nie wiedziałem nawet, jak sformułować pytanie. (i prawdopodobnie zrobiłbym to po prostu, /^\d+$/.test('123')aby uniknąć zawiłości potencjalnych problemów z analizą)
Olical
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.