Sjekk om en variabel er en streng i JavaScript
Hvordan kan jeg avgjøre om en variabel er en streng eller noe annet i JavaScript?
Svar #1
Dette er det som fungerer for meg:
if (typeof myVar === 'string' || myVar instanceof String)
// it's a string
else
// it's something else
// Test this approach:
let isString = value => typeof value === 'string' || value instanceof String;
let falseCases = [
[ 'null', null ],
[ 'undefined', undefined ],
[ 'object', { a: 1, b: 2 } ],
[ 'array', [ 1, 2, 3 ] ],
[ 'number', 123 ],
[ 'zero', 0 ],
[ 'RegExp', new RegExp('hello') ],
[ 'number with valueOf returning string', Object.assign(10, { valueOf: () => 'abc' }) ],
[ 'object pretending to be string', { constructor: String } ]
];
let trueCases = [
[ 'empty literal string', '' ],
[ 'unicode string literal', String.fromCharCode(10000) ],
[ 'empty boxed string', new String('') ],
[ 'unicode boxed string', new String(String.fromCharCode(10000)) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: Array }) ],
[ 'string with overwritten "toString"', Object.assign('hi', { toString: 123 }) ],
[ 'string with overwritten "valueOf"', Object.assign('hi', { valueOf: 123 }) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: RegExp }) ],
[ 'proxied string', new Proxy(new String('hello'), {}) ],
];
console.log('NEGATIVE TESTS:');
for (let [ name, val ] of falseCases) {
console.log(`Test ${name}:\n Expect: false\n Got: ${isString(val)}`);
}
console.log('\nPOSITIVE TESTS:');
for (let [ name, val ] of trueCases) {
console.log(`Test ${name}:\n Expect: true\n Got: ${isString(val)}`);
}Svar #2
Du kan bruke typeof-operatoren:
var booleanValue = true;
var numericalValue = 354;
var stringValue = "This is a String";
var stringObject = new String("This is a String Object");
console.log(typeof booleanValue) // displays "boolean"
console.log(typeof numericalValue) // displays "number"
console.log(typeof stringValue) // displays "string"
console.log(typeof stringObject) // displays "object"Eksempel fra denne nettsiden. (Eksempelet ble imidlertid litt endret).
Dette vil ikke fungere som forventet i tilfelle av strenger opprettet med new String(), men dette brukes sjelden og anbefales ikke[1][2]. Se de andre svarene for hvordan du kan håndtere disse, hvis du ønsker det.
// Test this approach:
let isString = value => typeof value === 'string';
let falseCases = [
[ 'null', null ],
[ 'undefined', undefined ],
[ 'object', { a: 1, b: 2 } ],
[ 'array', [ 1, 2, 3 ] ],
[ 'number', 123 ],
[ 'zero', 0 ],
[ 'RegExp', new RegExp('hello') ],
[ 'number with valueOf returning string', Object.assign(10, { valueOf: () => 'abc' }) ],
[ 'object pretending to be string', { constructor: String } ]
];
let trueCases = [
[ 'empty literal string', '' ],
[ 'unicode string literal', String.fromCharCode(10000) ],
[ 'empty boxed string', new String('') ],
[ 'unicode boxed string', new String(String.fromCharCode(10000)) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: Array }) ],
[ 'string with overwritten "toString"', Object.assign('hi', { toString: 123 }) ],
[ 'string with overwritten "valueOf"', Object.assign('hi', { valueOf: 123 }) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: RegExp }) ],
[ 'proxied string', new Proxy(new String('hello'), {}) ],
];
console.log('NEGATIVE TESTS:');
for (let [ name, val ] of falseCases) {
console.log(`Test ${name}:\n Expect: false\n Got: ${isString(val)}`);
}
console.log('\nPOSITIVE TESTS:');
for (let [ name, val ] of trueCases) {
console.log(`Test ${name}:\n Expect: true\n Got: ${isString(val)}`);
}- Google JavaScript stilguide sier å aldri bruke primitive objektinnpakninger.
- Douglas Crockford anbefalte at primitive objektwrapperne bør avvikles.
Svar #3
function isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
Eller, inline (jeg har en UltiSnip-oppsett for dette):
Object.prototype.toString.call(myVar) === "[object String]"
FYI, Pablo Santa Cruz sitt svar er feil, fordi typeof new String("string") er object
DRAXs svar er nøyaktig og funksjonelt og bør være det riktige svaret (siden Pablo Santa Cruz definitivt tar feil, og jeg vil ikke argumentere mot den populære mening).
Imidlertid er dette svaret også definitivt korrekt, og faktisk det beste svaret (bortsett fra, kanskje, forslaget om å bruke lodash/underscore). ansvarsfraskrivelse: Jeg bidro til lodash 4-kodebasen.
Mitt opprinnelige svar (som åpenbart fløy rett over hodene på mange) følger:
Jeg transkodet dette fra underscore.js:
['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'].forEach(
function(name) {
window['is' + name] = function(obj) {
return toString.call(obj) == '[object ' + name + ']';
};
});
Det vil definere isString, isNumber, osv.
I Node.js kan dette implementeres som en modul:
module.exports = [
'Arguments',
'Function',
'String',
'Number',
'Date',
'RegExp'
].reduce( (obj, name) => {
obj[ 'is' + name ] = x => toString.call(x) == '[object ' + name + ']';
return obj;
}, {});
[rediger]: Object.prototype.toString.call(x) fungerer også for å skille mellom funksjoner og asynkrone funksjoner:
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))// Test this approach:
function isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
let falseCases = [
[ 'null', null ],
[ 'undefined', undefined ],
[ 'object', { a: 1, b: 2 } ],
[ 'array', [ 1, 2, 3 ] ],
[ 'number', 123 ],
[ 'zero', 0 ],
[ 'RegExp', new RegExp('hello') ],
[ 'number with valueOf returning string', Object.assign(10, { valueOf: () => 'abc' }) ],
[ 'object pretending to be string', { constructor: String } ]
];
let trueCases = [
[ 'empty literal string', '' ],
[ 'unicode string literal', String.fromCharCode(10000) ],
[ 'empty boxed string', new String('') ],
[ 'unicode boxed string', new String(String.fromCharCode(10000)) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: Array }) ],
[ 'string with overwritten "toString"', Object.assign('hi', { toString: 123 }) ],
[ 'string with overwritten "valueOf"', Object.assign('hi', { valueOf: 123 }) ],
[ 'string with overwritten "constructor"', Object.assign('hi', { constructor: RegExp }) ],
[ 'proxied string', new Proxy(new String('hello'), {}) ],
];
console.log('NEGATIVE TESTS:');
for (let [ name, val ] of falseCases) {
console.log(`Test ${name}:\n Expect: false\n Got: ${isString(val)}`);
}
console.log('\nPOSITIVE TESTS:');
for (let [ name, val ] of trueCases) {
console.log(`Test ${name}:\n Expect: true\n Got: ${isString(val)}`);
}Svar #4
Jeg anbefaler å bruke de innebygde funksjonene fra jQuery eller lodash/Underscore. De er enklere å bruke og lettere å lese.
Begge funksjonene vil håndtere tilfellet DRAX nevnte... det vil si, de begge sjekker om (A) variabelen er en strengliteral eller (B) om det er en instans av String-objektet. I begge tilfeller identifiserer disse funksjonene korrekt verdien som en streng.
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
Se lodash-dokumentasjonen for _.isString() for mer informasjon.
Se jQuery-dokumentasjonen for $.type() for mer informasjon.
Svar #5
Rediger: Den nåværende måten å gjøre det på er typeof value === 'string'. For eksempel:
const str = 'hello';
if (typeof str === 'string') { ... }
Nedenfor har vært foreldet siden node v4.
Hvis du jobber i node.js-miljøet, kan du enkelt bruke den innebygde funksjonen isString i utils.
const util = require('util');
if (util.isString(myVar)) {}
Svar #6
function isString (obj) {
return (Object.prototype.toString.call(obj) === '[object String]');
}
Jeg så det her:
http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
Svar #7
Beste måte:
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');
Hver av disse har blitt konstruert av sin respektive klassefunksjon, som "new Object()" osv.
Også, Duck-Typing: "Hvis det ser ut som en and, går som en and, og lukter som en and - må det være et Array" Betydning, sjekk egenskapene dens.
Håper dette hjelper.
Rediger; 12.05.2016
Husk, du kan alltid bruke kombinasjoner av tilnærminger også. Her er et eksempel på å bruke et inline-kart over handlinger med typeof:
var type = { 'number': Math.sqrt.bind(Math), ... }[ typeof datum ];
Her er et mer 'virkelighetsnært' eksempel på bruk av inline-kart:
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
Denne funksjonen vil bruke [tilpasset] "type-konvertering" -- eller heller "type-/verdi-kartlegging" -- for å finne ut om en variabel faktisk "eksisterer". Nå kan du dele det vanskelige skillet mellom null og 0!
Mange ganger bryr du deg ikke engang om typen. En annen måte å omgå typing på er å kombinere Duck-Type-sett:
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) ...;
}
Både Number.prototype og String.prototype har en .toString()-metode. Du sørget bare for at strengen som tilsvarer tallet var den samme, og deretter sørget du for at du passerte det inn i http-funksjonen som et Number. Med andre ord, vi brydde oss ikke engang om hvilken type det hadde.
Håper det gir deg mer å jobbe med :)
Svar #8
Jeg kan ærlig talt ikke se hvorfor man ikke bare skulle bruke typeof i dette tilfellet:
if (typeof str === 'string') {
return 42;
}
Ja, det vil feile mot objekt-innpakkede strenger (f.eks. new String('foo')), men disse anses generelt som dårlig praksis, og de fleste moderne utviklingsverktøy vil sannsynligvis fraråde bruk av dem. (Hvis du ser en, bare rett den!)
Trikset Object.prototype.toString er noe som alle front-end-utviklere har blitt funnet skyldige i å gjøre en dag i sin karriere, men la deg ikke lure av dets glans av smarthet: det vil slutte å fungere så snart noe gjør monkey-patch på Object-prototypen:
const isString = thing => Object.prototype.toString.call(thing) === '[object String]';
console.log(isString('foo'));
Object.prototype.toString = () => 42;
console.log(isString('foo'));Svar #9
Ytelse
I dag 2020.09.17 utfører jeg tester på MacOs HighSierra 10.13.6 på Chrome v85, Safari v13.1.2 og Firefox v80 for valgte løsninger.
Resultater
For alle nettlesere (og begge testtilfellene)
- løsninger
typeof||instanceof(A, I) ogx===x+''(H) er raske/raskest - løsning
_.isString(lodash-bibliotek) er middels/rask - løsningene B og K er tregest
Oppdatering: 2020.11.28 Jeg oppdaterer resultater for x=123 Chrome-kolonnen - for løsning I var det sannsynligvis en feil i verdien tidligere (=69M for lav) - jeg bruker Chrome 86.0 for å gjenta testene.
Detaljer
Jeg utfører 2 testtilfeller for løsningene A B C D E F G H I J K L
- når variabelen er en streng - kan du kjøre den HER
- når variabelen IKKE er en streng - kan du kjøre den HER
Nedenfor viser utdraget forskjeller mellom løsningene
// https://stackoverflow.com/a/9436948/860099
function A(x) {
return (typeof x == 'string') || (x instanceof String)
}
// https://stackoverflow.com/a/17772086/860099
function B(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
// https://stackoverflow.com/a/20958909/860099
function C(x) {
return _.isString(x);
}
// https://stackoverflow.com/a/20958909/860099
function D(x) {
return $.type(x) === "string";
}
// https://stackoverflow.com/a/16215800/860099
function E(x) {
return x?.constructor === String;
}
// https://stackoverflow.com/a/42493631/860099
function F(x){
return x?.charAt != null
}
// https://stackoverflow.com/a/57443488/860099
function G(x){
return String(x) === x
}
// https://stackoverflow.com/a/19057360/860099
function H(x){
return x === x + ''
}
// https://stackoverflow.com/a/4059166/860099
function I(x) {
return typeof x == 'string'
}
// https://stackoverflow.com/a/28722301/860099
function J(x){
return x === x?.toString()
}
// https://stackoverflow.com/a/58892465/860099
function K(x){
return x && typeof x.valueOf() === "string"
}
// https://stackoverflow.com/a/9436948/860099
function L(x) {
return x instanceof String
}
// ------------------
// PRESENTATION
// ------------------
console.log('Solutions results for different inputs \n\n');
console.log("'abc' Str '' ' ' '1' '0' 1 0 {} [] true false null undef");
let tests = [ 'abc', new String("abc"),'',' ','1','0',1,0,{},[],true,false,null,undefined];
[A,B,C,D,E,F,G,H,I,J,K,L].map(f=> {
console.log(
`${f.name} ` + tests.map(v=> (1*!!f(v)) ).join` `
)})<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
This shippet only presents functions used in performance tests - it not perform tests itself!Og her er eksempelresultater for Chrome
Svar #10
Dette er et flott eksempel på hvorfor ytelse er viktig:
Å gjøre noe så enkelt som en test for en streng kan være kostbart hvis det ikke gjøres riktig.
For eksempel, hvis jeg ønsket å skrive en funksjon for å teste om noe er en streng, kunne jeg gjort det på en av to måter:
1) const isString=str => (Object.prototype.toString.call(str) === '[object String]');
2) const isString=str => ((typeof str === 'string') || (str instanceof String));
Begge disse er ganske enkle, så hva kan muligens påvirke ytelsen? Generelt sett kan funksjonskall være kostbare, spesielt hvis du ikke vet hva som skjer inni. I det første eksempelet er det et funksjonskall til Objects toString-metode. I det andre eksempelet er det ingen funksjonskall, ettersom typeof og instanceof er operatorer. Operatorer er betydelig raskere enn funksjonskall.
Når ytelsen testes, er eksempel 1 79 % tregere enn eksempel 2!
Se testene: https://jsperf.com/isstringtype
Svar #11
Jeg liker å bruke denne enkle løsningen:
var myString = "test";
if(myString.constructor === String)
{
//It's a string
}
Svar #12
Jeg synes denne enkle teknikken er nyttig for å type-sjekke for 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 failedDen samme teknikken fungerer for Nummer også -
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 failedOg for 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 failedDet samme gjelder for Objekt -
Object(x) === x // true, if x is an object
// false in every other case
NB, regex, arrays og funksjoner regnes også som objekter.
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) Men å sjekke for Array er litt annerledes -
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 failedDenne teknikken fungerer ikke for Funksjoner derimot -
Function(x) === x // always false
For @Faither -
const fmt = JSON.stringify
function test1() {
const a = "1"
const b = 1
console.log(`Number(${fmt(a)}) === ${fmt(b)}`, Number(a) === b) // true
}
function test2() {
const a = "1"
const b = 1
console.log(`Number.isInteger(${fmt(a)})`, Number.isInteger(a)) // false
console.log(`Number.isInteger(${fmt(b)})`, Number.isInteger(b)) // true
}
function test3() {
name = 1 // global name will always be a string
console.log(fmt(name)) // "1"
console.log(`String(${fmt(name)}) === ${fmt(name)}`, String(name) === name) // true
}
function test4() {
const name = 1 // local name
console.log(fmt(name)) // 1
console.log(`String(${fmt(name)}) === ${fmt(name)}`, String(name) === name) // false
}
test1(); test2(); test3(); test4()Svar #13
if (s && typeof s.valueOf() === "string") {
// s is a string
}
Fungerer både for streng-litteraler let s='blah' og for objekt-strenger let s=new String('blah')
Svar #14
Tatt fra lodash:
function isString(val) {
return typeof val === 'string' || ((!!val && typeof val === 'object') && Object.prototype.toString.call(val) === '[object String]');
}
console.log(isString('hello world!')); // true
console.log(isString(new String('hello world'))); // true
Svar #15
En enkel og rask måte å teste på kan være å bruke konstruktørens navn-attributt.
let x = "abc";
console.log(x.constructor.name === "String"); // true
let y = new String('abc');
console.log(y.constructor.name === "String"); // true
Ytelse


