Вопрос о том, является ли значение примитивным или коробочным
Можно использовать typeof
, чтобы определить, является ли значение примитивным или коробочным.
Рассмотрим:
typeof "foo"; // "string"
typeof new String("foo"); // "object"
В сочетании с Object.prototype.toString
мы могли бы определить следующие две функции
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";
};
Существуют ли любые варианты использования для этих двух функций? (Или аналогичные функции для Number
, Boolean
и т.д.).
Концепция этого вопроса исходила из следующего комментария T.J.Crowder.
Должны ли мы когда-нибудь заботиться о том, является ли ценность у нас примитивной или в штучной упаковке?
Ответы
Ответ 1
Я бы сказал, что практически нет смысла, вам почти все равно, имеете ли вы дело с примитивом string
или string
.
Есть краевые случаи. Например, объект string
является фактическим объектом, вы можете добавлять к нему свойства. Это позволяет делать такие вещи:
function test(arg) {
arg.foo = "bar";
}
Если код вызова проходит в примитиве string
:
var s1 = "str";
test(s1);
... arg
получает статус string
и получает свойство, добавленное к нему, но этот объект string
не используется ничем после возвращения test
.
В отличие от этого, если код вызова проходит в объекте string
:
var s2 = new String("str");
test(s2);
... тогда свойство добавляется к этому объекту, и вызывающий код может его увидеть. Рассмотрим (живую копию):
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";
}
Вывод:
[Before] typeof s1.foo = undefined
[After] typeof s1.foo = undefined
[Before] typeof s2.foo = undefined
[After] typeof s2.foo = string
Обратите внимание, что s2.foo
является строкой, но s1.foo
не является (поскольку s1
был примитивом строки, объект, созданный, когда мы продвигаем его в test
, не имеет ничего общего с вызывающим кодом).
Есть ли какой-либо прецедент для этого? Не знаю. Я бы сказал, что это будет очень резкий край, если так.
Ответ 2
Все вещи toString
, похоже, являются попыткой обходных проблем с межкадровым смешиванием разных встроенных конструкторов String
. Это необязательно для проверки того, является ли что-то примитивной строкой - typeof
достаточно, поэтому нет смысла использовать для is_primitive_string
.
Я очень редко вижу аргументы, переданные как String
экземпляры, поэтому я не могу понять, почему мне нужно будет проверить, является ли что-то одним кросс-кадром String
вместо того, чтобы просто прибегнуть к значению String
через ("" + s)
или String(s)
. Единственный раз, когда я использовал значение String
в производственном коде, было то, что мне нужна была пустая строка, которая была правдой в некотором высоко оптимизированном коде.
Что касается остальных, экземпляры класса Boolean
не ведут себя так, как можно было бы ожидать в условиях.
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)
- true
, но когда вы используете создать экземпляр класса Boolean
, оператор !
применяется к значению объекта, а значения объекта всегда правдивы.
Я считаю, что строгий режим EcmaScript 5 меняет способ this
, поэтому последний пример (false.not()
) будет вести себя так, как можно было бы наивно ожидать, когда "use strict";
добавляется в начало Boolean.prototype.not
в действительном ES5.
С Number
s сравнения с использованием <
являются ОК, а добавление и другие операторы имеют тенденцию работать должным образом. new Number(0)
и new Number(NaN)
имеют те же проблемы, что и new Boolean(false)
вокруг условий, и, конечно,
alert(NaN === NaN); // false
var NAN = new Number(NaN);
alert(NAN === NAN); // true
и ===
и !==
сравнивают по ссылке для всех String
, Number
и Boolean
.
Ответ 3
Я использую методы underscore.js для определения типа переменной. Попробуй использовать:
isEmpty, isElement, isArray, isArguments, isFunction, isString, isNumber, isBoolean, isDate, isRegExp isNaN, isNull, isUndefined
Описан здесь:
http://documentcloud.github.com/underscore/