如何确定变量是字符串还是JavaScript中的其他变量?


当前回答

取自lodash:

function isString(val) {
   return typeof val === 'string' || ((!!val && typeof val === 'object') && Object.prototype.toString.call(val) === '[object String]');
}

console.log(isString('hello world!')); // true
console.log(isString(new String('hello world'))); // true

其他回答

由于有580+人投票给了一个错误的答案,而有800+人投票支持一个有效但猎枪式的答案,我认为应该用一种大家都能理解的更简单的形式来重复我的答案。

function isString(x) {
  return Object.prototype.toString.call(x) === "[object String]"
}

或者,内联(我有一个UltiSnip设置):

Object.prototype.toString.call(myVar) === "[object String]"

仅供参考,巴勃罗·圣克鲁斯的答案是错误的,因为新字符串(“String”)的类型是对象

DRAX的答案准确且实用,应该是正确的答案(因为巴勃罗·圣克鲁斯(Pablo Santa Cruz)绝对是错误的,我不会反对全民投票。)

然而,这个答案也绝对正确,实际上是最好的答案(除了使用lodash/下划线的建议)。免责声明:我为lodash 4代码库做了贡献。

我最初的答案(很明显,很多人都是这么想的)如下:

我从underscore.js代码转换了这个:

['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'].forEach( 
    function(name) { 
        window['is' + name] = function(obj) {
              return toString.call(obj) == '[object ' + name + ']';
    }; 
});

这将定义isString、isNumber等。


在Node.js中,这可以作为一个模块实现:

module.exports = [
  'Arguments',
  'Function', 
  'String', 
  'Number', 
  'Date', 
  'RegExp'
].reduce( (obj, name) => {
  obj[ 'is' + name ] = x => toString.call(x) == '[object ' + name + ']';
  return obj;
}, {});

[编辑]:Object.protype.toString.call(x)也可以在函数和异步函数之间进行描述:

const fn1=()=>new Promise((resolve,reject)=>setTimeout(()=>resolve({}),1000))常量fn2=async()=>({})console.log('fn1',Object.pr原型.toString.call(fn1))console.log('fn2',Object.pr原型.toString.call(fn2))

老实说,我不明白为什么在这种情况下不简单地使用typeof:

if (typeof str === 'string') {
  return 42;
}

是的,它会对对象包装的字符串(例如,新字符串('o'))失败,但这些被广泛认为是一种糟糕的做法,大多数现代开发工具可能会阻止它们的使用。(如果您看到一个,请修复它!)

Object.prototype.toString技巧是所有前端开发人员在其职业生涯中的某一天都会犯下的错误,但不要让它通过巧妙的打磨来欺骗你:只要有人修补Object原型,它就会崩溃:

constisString=thing=>Object.protype.toString.call(thing)=='[objectString]';console.log(isString('fo'));Object.prototype.toString=()=>42;console.log(isString('fo'));

这对我来说已经足够好了。

警告:这不是一个完美的解决方案。请看我帖子的底部。

Object.prototype.isString = function() { return false; };
String.prototype.isString = function() { return true; };

var isString = function(a) {
  return (a !== null) && (a !== undefined) && a.isString();
};

你可以像下面这样使用。

//return false
isString(null);
isString(void 0);
isString(-123);
isString(0);
isString(true);
isString(false);
isString([]);
isString({});
isString(function() {});
isString(0/0);

//return true
isString("");
isString(new String("ABC"));

警告:在以下情况下,此操作不正确:

//this is not a string
var obj = {
    //but returns true lol
    isString: function(){ return true; }
}

isString(obj) //should be false, but true

我有一个愚蠢的技巧。但直截了当。

if(maybeAString.toUpperCase)
  weHaveAString(maybeAString)

是的,这远非完美。但这很简单。

这是一个很好的例子,说明了为什么性能很重要:

如果做得不正确,对字符串进行测试这样简单的操作可能会很昂贵。

例如,如果我想写一个函数来测试某个东西是否是字符串,我可以用以下两种方法之一:

1) const isString=str=>(Object.pr原型.toString.call(str)=='[Object String]');

2) const isString=str=>((typeof str=='string')||(str instanceof string));

这两个都非常直接,那么什么可能会影响性能呢?一般来说,函数调用可能会很昂贵,特别是如果您不知道内部发生了什么。在第一个示例中,有一个对Object的toString方法的函数调用。在第二个示例中,没有函数调用,因为typeof和instanceof是运算符。运算符比函数调用快得多。

测试性能时,示例1比示例2慢79%!

参见测试:https://jsperf.com/isstringtype