如何在JavaScript中确定一个变量是字符串还是其他类型?
这是对我有效的方法:
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)}`);
}
typeof
运算符:
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"
来自此网页的示例(虽然稍作修改)。
对于使用new String()
创建的字符串,这种方法不会按预期工作,但这种方法很少使用并且不建议使用[1][2]。如果您需要处理这些字符串,请参阅其他答案中的方法。
// 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)}`);
}
typeof
来检测 JavaScript 的数据类型,但有人反对这种方法在处理像 new String('foo')
这样被对象包装的字符串时会出现问题。不过这并不重要,因为被对象包装的字符串是一个毫无价值的功能,你不应该使用它们。Google 的代码风格指南禁止使用它们,Douglas Crockford 建议将它们弃用,而且没有任何库使用它们。假设它们不存在,放心使用 typeof
。 - Mark Amerytypeof
?(参考链接:http://www.crockford.com/javascript/recommend.html) - Daniel Lefunction isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
Object.prototype.toString.call(myVar) === "[object String]"
typeof new String("string")
是object
DRAX的回答准确且功能齐全,应该是正确的答案(因为Pablo Santa Cruz绝对是错误的,我不会反对大多数人的投票结果)['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'].forEach(
function(name) {
window['is' + name] = function(obj) {
return toString.call(obj) == '[object ' + name + ']';
};
});
那将定义isString、isNumber等。
module.exports = [
'Arguments',
'Function',
'String',
'Number',
'Date',
'RegExp'
].reduce( (obj, name) => {
obj[ 'is' + name ] = x => toString.call(x) == '[object ' + name + ']';
return obj;
}, {});
Object.prototype.toString.call(x)
可以用来区分函数和异步函数:
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)}`);
}
global || window
替代window
,但这是解决本来不应该存在的问题的一种糟糕方法)。 - Benjamin Gruenbaum我建议使用 jQuery 或 lodash/Underscore 中的内置函数。它们更简单易用,易于阅读。
任意一个函数都可以处理DRAX所提到的情况......也就是说,它们都会检查变量是否为字符串字面量或String对象的实例。在任何一种情况下,这些函数都可以正确地识别该值为字符串。
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
查看lodash文档了解_.isString()的更多细节。
查看jQuery文档了解$.type()的更多细节。
_.every()
在开始使用时有点混乱,并且一些简单的函数,例如 _.isBoolean()
已经让我们公司的开发人员感到困惑了。有一个开发者错误地认为,当值为布尔值且为 false 时,该函数会返回 false。对我来说,英语比德语更容易阅读,因为我不懂德语。学习 JavaScript,一切都会变得清晰明了。 - John Harding编辑:目前实现此操作的方法为 typeof value === 'string'
。例如:
const str = 'hello';
if (typeof str === 'string') { ... }
如果您使用 node.js 环境,可以直接使用 utils 中的内置函数 isString。
const util = require('util');
if (util.isString(myVar)) {}
typeof value === 'string'
替代。” - Mr Rogersutil.types.isStringObject()
,但对于 x = 'x'
类型的字符串它也返回 false。这两个实用函数完全没有任何用处... - spinkusfunction isString (obj) {
return (Object.prototype.toString.call(obj) === '[object String]');
}
我在这里看到:
http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
Object.prototype.toString.call(obj) === '[object String]'
周围加上括号? - StubbornShowaGuy最佳方法:
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');
var type = { 'number': Math.sqrt.bind(Math), ... }[ typeof datum ];
以下是一个更贴近实际的使用内联地图的例子:
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
null
和0
!许多时候,您甚至不关心它的类型。规避类型的另一种方法是结合鸭子类型集: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) ...;
}
Number.prototype
和String.prototype
都有一个.toString()方法
。你只需确保数字的字符串等效性相同,然后确保将其作为Number
传递给http
函数。换句话说,我们甚至不关心它的类型。(o.constructor === Number || s.constructor === Boolean)
)。有趣的是,parseInt
和NaN
是脆弱但功能强大的工具。只需记住,非数字不等于非数字,未定义可以被定义。 - Codyif(thing.call) { '它是一个函数'; }
或者 if(thing.defineProperties) { '它是一个对象'; }
。感谢您的输入,axkibe! - Cody我真的不明白为什么在这种情况下不直接使用typeof
:
if (typeof str === 'string') {
return 42;
}
是的,它不能对包装为对象的字符串(例如new String('foo')
)起作用,但这被广泛认为是一种不好的做法,大多数现代开发工具可能会不鼓励使用它们。(如果你看到这样的代码,只需要修复它!)
Object.prototype.toString
技巧是所有前端开发人员在职业生涯中都曾犯过的错误,但不要被其聪明的外表所迷惑:一旦有东西monkey-patch了Object原型,它就会出问题。
const isString = thing => Object.prototype.toString.call(thing) === '[object String]';
console.log(isString('foo'));
Object.prototype.toString = () => 42;
console.log(isString('foo'));
Object.prototype.toString
以返回不同的结果...坦白地说,那是他们的问题!在我看来,这种可能性不应成为决定使用哪种方法的因素。(我个人不会费心;我采用您展示的简单方法 - 但我不是编写库代码。) - ToolmakerSteve今天2020.09.17我在MacOS HighSierra 10.13.6上使用Chrome v85、Safari v13.1.2和Firefox v80对选定的解决方案进行测试。
对于所有浏览器(以及两个测试用例)
typeof||instanceof
(A, I) and x===x+''
(H) 是快/最快的_.isString
(lodash lib) 是中等快速更新:2020.11.28 我更新了x=123 Chrome
列的结果 - 对于解决方案,之前可能存在错误值(=69M太低) - 我使用Chrome 86.0重复测试。
我为以下解决方案执行了2个测试用例
A B C D E F G H I J K L以下代码段介绍了解决方案之间的差异
// https://dev59.com/HW855IYBdhLWcg3w-JQr#9436948
function A(x) {
return (typeof x == 'string') || (x instanceof String)
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#17772086
function B(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#20958909
function C(x) {
return _.isString(x);
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#20958909
function D(x) {
return $.type(x) === "string";
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#16215800
function E(x) {
return x?.constructor === String;
}
// https://stackoverflow.com/a/42493631/860099
function F(x){
return x?.charAt != null
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#57443488
function G(x){
return String(x) === x
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#19057360
function H(x){
return x === x + ''
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#4059166
function I(x) {
return typeof x == 'string'
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#28722301
function J(x){
return x === x?.toString()
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#58892465
function K(x){
return x && typeof x.valueOf() === "string"
}
// https://dev59.com/HW855IYBdhLWcg3w-JQr#9436948
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!
以下是Chrome的示例结果:
new String("string")
创建的字符串,x + '' === x
失败。也许它应该限制为正确的测试,或者至少为每个测试结果添加列,以进行简单的测试套件,例如null
,undefined
,123
,new Object()
(应全部返回false
),以及""
,"abc"
,new String("")
,new String("abc")
(应全部返回true
)。 - MikeBeaton==
而不是===
可以获得轻微的加速效果,但不确定这是否重要。 - MikeBeatonconst isString = str => (Object.prototype.toString.call(str) === '[object String]');
2)const isString = str => ((typeof str === 'string') || (str instanceof String));
这两种方法都比较直接,那么到底什么可能会影响性能呢?一般来说,函数调用可能非常昂贵,特别是如果不知道内部发生了什么。在第一个示例中,存在对 Object 的 toString 方法的函数调用。在第二个示例中,没有函数调用,因为 typeof 和 instanceof 是运算符。运算符比函数调用快得多。
instanceof
检查是毫无意义的噪音,除非你遵循一些非常不寻常的编码实践。此回答未对其作用或使用原因进行解释,唯一需要它的原因是如果你使用对象封装字符串,但是对象封装字符串是一个毫无价值的功能,没有人使用,Google和Crockford都谴责其为不良实践。(https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Wrapper_objects_for_primitive_types#Wrapper_objects_for_primitive_types, http://www.crockford.com/javascript/recommend.html) - Mark Amerytypeof
和instanceof
都是明智之举。如果你在问“我刚刚发送了什么 postmessage”,那么 @MarkAmery 的“postmessage”边界情况很重要 - 但你期望它在接口处得到处理,并且不会传播。在其他地方,即使某些 JS 爱好者不赞成这些方法,正确处理非淘汰的编码方法是正确的。除非真正接受字符串,否则永远不要将您的代码注释为接受字符串! - Dewi Morgan