2011-07-22 8 views
16

Se puede usar typeof para determinar si un valor es primitivo o encuadrado.Da igual si un valor es primitivo o en recuadro

considerar:

typeof "foo"; // "string" 
typeof new String("foo"); // "object" 

En combinación con Object.prototype.toString podríamos definir las siguientes dos funciones

var toString = Object.prototype.toString; 

var is_primitive_string = function(s) { 
    return toString.call(s) === "[object String]" && typeof s === "string"; 
}; 

var is_boxed_string = function(s) { 
    return toString.call(s) === "[object String]" && typeof s === "object"; 
}; 

¿Hay alguna casos de uso para estas dos funciones? (O funciones similares para Number, Boolean, etc.).

El concepto detrás de esta pregunta proviene de la siguiente Comment by T.J.Crowder.

¿Deberíamos preocuparnos si el valor que tenemos es primitivo o encuadrado?

Respuesta

7

yo diría que no hay prácticamente ningún punto , casi nunca le importa si está tratando con una primitiva string o un objeto String.

Hay cajas de borde. Por ejemplo, un objeto String es un objeto real, puede agregarle propiedades. Esto le permite hacer cosas como esta:

function test(arg) { 
    arg.foo = "bar"; 
} 

Si llama código pasa en un string primitiva:

var s1 = "str"; 
test(s1); 

... arg es ascendido a un objeto String y obtiene una propiedad añadido a la misma , pero ese objeto String no es utilizado por nada después de test devuelve.

Por el contrario, si se llama código pasa en un objetoString:

var s2 = new String("str"); 
test(s2); 

... entonces la propiedad se añade a ese objeto y el código de llamada puede verlo. Considere (live copy):

var s1, s2; 

s1 = "str"; 

display("[Before] typeof s1.foo = " + typeof s1.foo); 
test(s1); 
display("[After] typeof s1.foo = " + typeof s1.foo); 

s2 = new String("str"); 

display("[Before] typeof s2.foo = " + typeof s2.foo); 
test(s2); 
display("[After] typeof s2.foo = " + typeof s2.foo); 

function test(arg) { 
    arg.foo = "bar"; 
} 

Salida:

[Before] typeof s1.foo = undefined 
[After] typeof s1.foo = undefined 
[Before] typeof s2.foo = undefined 
[After] typeof s2.foo = string

Tenga en cuenta que s2.foo es una cadena, pero no es s1.foo (porque s1 era una cadena primitiva, el objeto creado cuando promocionamos en test no tiene nada que ver con el código de llamada).

¿Hay algún caso de uso para esto? No sé. Yo diría que sería un caso extremadamente nervioso si es así.

+0

El hecho de que los valores encuadrados se "pasen por referencia" en comparación con los primitivos puede tener algunas consecuencias interesantes. – Raynos

+1

@Raynos, ¿qué consecuencias? Las primitivas son inmutables, por lo que no debería haber diferencias observables entre el valor de paso y la referencia de paso para las primitivas. No creo que haya ningún programa que pueda escribir que pueda detectar si todos los 'verdaderos' se pasan como referencia a un objeto inmutable que reside en una sola ubicación de memoria (como en Rhino) y uno donde es una unión etiquetada que se copia como en la mayoría de los otros intérpretes. –

3

Todas las cosas de toString parecen ser un intento de solucionar problemas con la mezcla de fotogramas cruzados de diferentes constructores String incorporados. Eso es innecesario para verificar si algo es una cadena primitiva - typeof es suficiente, por lo que no hay caso de uso para is_primitive_string.

muy rara vez veo argumentos pasados ​​como String casos así que no puedo ver por qué yo tendría que comprobar si algo es un ejemplo String cruz-marco en lugar de simplemente coaccionar a un valor medio de String("" + s) o String(s). La única vez que utilicé un valor de String en el código de producción fue cuando necesitaba una cadena vacía que era cierta en algún highly optimized code.

Por lo que respecta a los demás, las instancias de la clase Boolean no se comportan como cabría esperar en las condiciones.

if (new Boolean(false)) { 
    alert("WTF!"); 
} else { 
    alert("OK"); 
} 

Boolean.prototype.not = function() { return !this; }; 

if (new Boolean(false).not()) { 
    alert("OK"); 
} else { 
    alert("Really, WTF!"); 
} 

if (false.not()) { // Autoboxing 
    alert("OK"); 
} else { 
    alert("Cmon, WTF!"); 
} 

!(false) es true, pero cuando se utiliza crear una instancia de la clase Boolean, el operador ! se aplica al valor del objeto, y valores de los objetos son siempre Truthy.

creo EcmaScript 5 modo estricto está cambiando la forma this se presenta de modo que el último ejemplo (false.not()) se comportará como uno podría esperar ingenuamente cuando se añade "use strict"; a la parte superior de Boolean.prototype.not en un intérprete ES5 válida.

Con Number s, las comparaciones que utilizan < son correctas y además los operadores de adición y otros tienden a funcionar como se esperaba. new Number(0) y new Number(NaN) tienen los mismos problemas que new Boolean(false) alrededor de condiciones, y por supuesto

alert(NaN === NaN); // false 
var NAN = new Number(NaN); 
alert(NAN === NAN); // true 

y === y !== comparan por referencia para todos String, Number y Boolean.

+0

Aparte de la lógica booleana y el operador '!'. ¿Hay algo más que actúe de manera estrangulada en los tipos en caja frente a los primitivos? ¿Y deberíamos revisar/andar en contra de esto? – Raynos

+0

@Raynos, obviamente 'new Number (0)' es truey y 'var NAN = new Number (NaN); alerta (NAN === NAN && !! NAN) '. –

-2

Uso los métodos de underscore.js para detectar el tipo de la variable.Trate de usar: estaVacia, isElement, isArray, isArguments, isFunction, isString, ISNUMBER, IsBoolean, ISDATE, isRegExp isNaN, isnull, isUndefined

describen a continuación: http://documentcloud.github.com/underscore/

+1

No estamos hablando de tipo, estábamos hablando de verificar si un valor es un tipo primitivo o encuadrado para un tipo particular (Cadena, Número, Booleano) – Raynos

+0

Perdón. Yo malentendí la pregunta. – czerasz

Cuestiones relacionadas