Подтвердить что ты не робот

Вопрос о том, является ли значение примитивным или коробочным

Можно использовать 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.

Должны ли мы когда-нибудь заботиться о том, является ли ценность у нас примитивной или в штучной упаковке?

4b9b3361

Ответ 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/