Saltar al contenido

Compruebe si una variable es una cadena en JavaScript

septiembre 25, 2021
apple touch icon@2

Voy a ir por una ruta diferente al resto aquí, que intentará decir si una variable es un tipo específico, o un miembro de un conjunto específico.
JS se basa en la tipificación de pato; si algo grazna como una cuerda, podemos y debemos usarlo como una cuerda.

Es 7 ¿una cuerda? Entonces, ¿por qué /d/.test(7) ¿trabaja?
Es {toString:()=>('hello there')} ¿una cuerda? Entonces, ¿por qué ({toString:()=>('hello there')}) + 'ngeneral kenobi!' ¿trabaja?
Estas no son preguntas sobre deberían el trabajo anterior, el punto es que lo hacen.

Entonces hice un duckyString() función
A continuación, pruebo muchos casos no atendidos por otras respuestas. Para cada código:

  • establece una variable similar a una cadena
  • ejecuta una operación de cadena idéntica en él y una cadena real para comparar las salidas (demostrando que pueden tratarse como cadenas)
  • convierte la cadena en una cadena real para mostrarte duckyString() para normalizar las entradas para el código que espera cadenas reales
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');

Esto está en la misma línea que !!x Opuesto a x===true y probando si algo es una matrizigual que en lugar de necesitar una matriz real.
objetos jQuery; son matrices? No. ¿Son lo suficientemente buenos? Sí, puedes ejecutarlos Array.prototype funciona bien.
Es esta flexibilidad la que le da a JS su poder y pruebas por strings específicamente hace que su código sea menos interoperable.

El resultado de lo anterior es:

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"

Entonces, se trata de por qué quieres saber si algo es una cadena.
Si, como yo, llegaste aquí desde Google y quisieras ver si algo estaba como una cuerda, aquí tienes una respuesta.
Ni siquiera es caro a menos que esté trabajando con matrices de caracteres muy largas o profundamente anidadas.
Esto se debe a que son todas declaraciones if, ninguna función llama como .toString().
Excepto si está tratando de ver si una matriz de caracteres con objetos que solo tienen toString()‘s o caracteres de varios bytes, en cuyo caso no hay otra forma de verificar excepto para hacer la cadena y contar los caracteres que componen los bytes, respectivamente

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

Se incluyen opciones para

  • pregunta qué método lo consideró string-y
  • excluir métodos de detección de cadenas (por ejemplo, si no le gusta .toString())

Aquí hay más pruebas porque soy completista:

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(['uD83DuDE07']);
test([['1'], 2, new String(3)]);
test([['1'], 2, new String(3)], {chars:true});
  • Todos los casos negativos parecen contabilizarse
  • Esto debería ejecutarse en navegadores> = IE8
  • Matrices de caracteres con varios bytes admitidas en navegadores con soporte de iterador de cadenas

Producción:

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"
close