JavaScript'te bir değişkenin string olup olmadığını kontrol edin


JavaScript'te bir değişkenin string mi yoksa başka bir şey mi olduğunu nasıl belirleyebilirim?

Cevap #1

Bu benim için işe yarayan şey:

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)}`); 
}

Cevap #2

typeof operatörünü kullanabilirsiniz:

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"

Bu web sayfasından örnek. (Örnek biraz değiştirilmiş olsa da).

Bu, new String() ile oluşturulan dizeler söz konusu olduğunda beklendiği gibi çalışmayacaktır, ancak bu nadiren kullanılır ve önerilmez[1][2]. Bunları nasıl ele alacağınız hakkında daha fazla bilgi için diğer cevaplara bakabilirsiniz, eğer isterseniz.

// 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)}`); 
}

  1. Google JavaScript Stil Rehberi, asla ilkel nesne kapsayıcılarını kullanmamayı söyler.
  2. Douglas Crockford, ilkel nesne sarmalayıcılarının kullanılmaktan kaldırılmasını önerdi.

Cevap #3

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

Veya, satır içi (Bunun için bir UltiSnip kurulumu yaptım):

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

Bilginize, Pablo Santa Cruz'un cevabı yanlış, çünkü typeof new String("string") object.

DRAX'ın cevabı doğru ve işlevseldir ve doğru cevap olmalıdır (çünkü Pablo Santa Cruz kesinlikle yanlıştır ve popüler oya karşı çıkmayacağım).

Ancak, bu cevap da kesinlikle doğrudur ve aslında en iyi cevaptır (belki de lodash/underscore kullanma önerisi hariç). feragatname: lodash 4 kod tabanına katkıda bulundum.

Orijinal cevabım (ki bu açıkça birçok kişinin kafasının üzerinden uçtu) şöyle:

Bunu underscore.js'ten dönüştürdüm:

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

Bu, isString, isNumber, vb.'yi tanımlayacaktır.


Node.js'te bu, bir modül olarak uygulanabilir:

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

[düzenle]: Object.prototype.toString.call(x) ayrıca fonksiyonlar ile asenkron fonksiyonlar arasında ayırt etmek için de çalışır:

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)}`); 
}

Cevap #4

jQuery veya lodash/Underscore içindeki yerleşik fonksiyonları kullanmanızı tavsiye ederim. Kullanımları daha basit ve okunmaları daha kolaydır.

Her iki fonksiyon da DRAX'in bahsettiği durumu ele alacaktır... yani, her ikisi de (A) değişkenin bir string literali olup olmadığını veya (B) String nesnesinin bir örneği olup olmadığını kontrol eder. Her iki durumda da, bu fonksiyonlar değerin bir string olduğunu doğru bir şekilde tespit eder.

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

Daha fazla detay için _.isString() hakkında lodash belgelerine bakın.

Daha fazla detay için jQuery Belgelerine $.type() bakın.

Cevap #5

Düzenleme: Bunu yapmanın mevcut yolu typeof value === 'string'. Örneğin:

const str = 'hello';
if (typeof str === 'string') { ... }

Aşağıdakiler node v4'ten bu yana kullanımdan kaldırıldı.

Eğer node.js ortamında çalışıyorsanız, utils içindeki yerleşik isString fonksiyonunu basitçe kullanabilirsiniz.

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

Cevap #6

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

Bunu burada gördüm:

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

Cevap #7

En iyi yol:

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');

Bunların her biri, uygun sınıf fonksiyonu ile oluşturulmuştur, örneğin "new Object()" gibi.

Ayrıca, Ördek-Tipi: "Eğer bir ördek gibi görünüyorsa, bir ördek gibi yürüyor ve bir ördek gibi kokuyorsa - bu bir Dizi olmalı" Anlamı, özelliklerini kontrol edin.

Umarım bu yardımcı olur.

Düzenleme; 12/05/2016

Unutmayın, her zaman farklı yaklaşımların kombinasyonlarını da kullanabilirsiniz. İşte typeof ile inline map kullanımına bir örnek:

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

İşte satır içi haritaların kullanımına dair daha 'gerçek dünya' bir örnek:

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

Bu fonksiyon, bir değişkenin gerçekten "var olup olmadığını" anlamak için [ özel ] "tip dönüştürme" -- daha doğrusu, "tip/-değer eşleme" -- kullanır. Artık o can sıkıcı farkı null ve 0 arasında ayırabilirsiniz!

Çoğu zaman onun türünü umursamazsınız bile. Yazma türünden kaçınmanın bir başka yolu, Duck-Type setlerini birleştirmektir:

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) ...;
}

Hem Number.prototype hem de String.prototype bir .toString() metoduna sahiptir. Sayının string eşdeğerinin aynı olduğundan emin oldunuz ve sonra da bunu http fonksiyonuna bir Number olarak geçirdiğinizden emin oldunuz. Başka bir deyişle, türünün ne olduğuna önem bile vermedik.

Umarım bu sana daha fazla çalışma malzemesi sağlar :)

Cevap #8

Dürüst olmak gerekirse, birinin bu durumda neden basitçe typeof kullanmayacağını göremiyorum:

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

Evet, nesne sarmallı stringlerde (ör. new String('foo')) başarısız olacaktır, ancak bunlar genel olarak kötü bir uygulama olarak kabul edilir ve modern geliştirme araçlarının çoğu bunların kullanımını teşvik etmeyecektir. (Böyle bir şey görürseniz, sadece düzeltin!)

Object.prototype.toString hilesi, tüm ön yüz geliştiricilerinin kariyerlerinde bir gün yapmakla suçlandığı bir şeydir ama onun zekice parlatmasına aldanmayın: Object prototipine herhangi bir şekilde müdahale eden bir şey olduğunda bunu bozacaktır:

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

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

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

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

Cevap #9

Performans

Bugün 2020.09.17 tarihinde seçilen çözümler için MacOs HighSierra 10.13.6 üzerinde Chrome v85, Safari v13.1.2 ve Firefox v80 üzerinde testler gerçekleştiriyorum.

Sonuçlar

Tüm tarayıcılar için (ve her iki test durumu için)

  • çözümler typeof||instanceof (A, I) ve x===x+'' (H) hızlı/en hızlıdır
  • çözüm _.isString (lodash kütüphanesi) orta/hızlıdır
  • B ve K çözümleri en yavaştır

Güncelleme: 28.11.2020 x=123 Chrome sütunu için sonuçları güncelliyorum - I çözümü için muhtemelen daha önce bir hata değeri vardı (=69M çok düşük) - testleri tekrarlamak için Chrome 86.0 kullanıyorum.

Detaylar

Çözümler A B C D E F G H I J K L için 2 test vakası gerçekleştiriyorum

  • değişken bir dize olduğunda - bunu BURADA çalıştırabilirsiniz
  • değişken string değilse - bunu BURADA çalıştırabilirsiniz

Aşağıdaki snippet çözümler arasındaki farkları sunar

// 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!

Ve işte Chrome için örnek sonuçlar

Cevap #10

Bu, performansın neden önemli olduğuna dair harika bir örnek:

Bir dizge için test yapmak gibi basit bir şey, doğru yapılmazsa pahalı olabilir.

Örneğin, bir şeyin string olup olmadığını test etmek için bir fonksiyon yazmak isteseydim, bunu iki yoldan biriyle yapabilirdim:

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

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

Her ikisi de oldukça basit, peki performansı ne etkileyebilir? Genel olarak, fonksiyon çağrıları maliyetli olabilir, özellikle içinde neler olup bittiğini bilmiyorsanız. İlk örnekte, Object'in toString metoduna bir fonksiyon çağrısı var. İkinci örnekte ise fonksiyon çağrısı yok, çünkü typeof ve instanceof operatörlerdir. Operatörler, fonksiyon çağrılarından çok daha hızlıdır.

Performans test edildiğinde, örnek 1, örnek 2'den %79 daha yavaştır!

Testlere bakın: https://jsperf.com/isstringtype

Cevap #11

Bu basit çözümü kullanmayı seviyorum:

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

Cevap #12

Bu basit tekniği String için yazım denetimi yaparken faydalı buluyorum -

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

Aynı teknik Sayı için de işe yarar -

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

Ve RegExp için -

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

Aynı şekilde Obje için de -

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

Not: Düzenli ifadeler, diziler ve fonksiyonlar da nesne olarak kabul edilir.

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)    

Ama, Array kontrolü yapmak biraz farklıdır -

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

Ancak bu teknik Fonksiyonlar için çalışmaz -

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

@Faither için -

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()

Cevap #13

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

Hem string literal'ler için let s='blah' hem de Nesne String'ler için let s=new String('blah') için çalışır

Cevap #14

Lodash'tan alınmıştır:

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

Cevap #15

Basit ve hızlı bir test yöntemi, yapıcı ad niteliğini kullanmak olabilir.

let x = "abc";
console.log(x.constructor.name === "String"); // true

let y = new String('abc');
console.log(y.constructor.name === "String"); // true

Performans

İlgili makaleler