在《JavaScript中数据类型转换》一文中主要学习了JavaScript中的数据类型、数据类型检测和数据类型转换。从这篇文章中了解到了通过String()
和toString()
可以将值转换为字符串。那么在JavaScript中还有很多有意思的东西,也是让我这样的生手感到困惑的东西。比如String()
和new String()
有何不同,又比如这篇文章的标题toString()
和valueOf()
又有何不同。
String() vs toString()
通过前面的学习,知道String()
和toString()
都可以转换为字符串类型,但这两者之间还是有所区别的。
在JavaScript中,可以将JavaScript中任何数据类型转换为字符串。
console.log(String(123), typeof String(123));
console.log(String('123'), typeof String('123'));
console.log(String(function fn(){return 1}), typeof String(function fn(){return 1}));
console.log(String([1,2,3]), typeof String([1,2,3]));
console.log(String({a: 1}), typeof String({a: 1}));
console.log(String(null), typeof String(null));
console.log(String(undefined), typeof String(undefined));
console.log(String(new Date()), typeof String(new Date()));
console.log(String(/^(.)*$/), typeof String(/^(.)*$/));
Image may be NSFW.
Clik here to view.
在JavaScript中,每个数据类型都有一个.toString()
的方法:
Image may be NSFW.
Clik here to view.
在JavaScript中除了null
和undefined
之外的任何数据类型都可以通过.toString()
方法转换成字符串。比如:
console.log('=========数组:array.toString()========')
var months = ['Jan', 'Feb', 'Mar'];
console.log(months.toString(), typeof months.toString());
console.log('=========布尔值:boolean.toString()========')
var bool = true;
console.log(bool.toString(), typeof bool.toString());
console.log('=========日期:date.toString()========')
var date = new Date();
console.log(date.toString(), typeof date.toString());
console.log('=========函数:function.toString()========')
var fn = function(a, b) {return a + b};
console.log(fn.toString(), typeof fn.toString());
console.log('=========数值:number.toString()========')
var count = 10;
console.log(count.toString(), typeof count.toString());
console.log('=========对象:object.toString()========')
var obj = {a: 123}
console.log(obj.toString(), typeof obj.toString());
console.log('=========正则:regExp.toString()========')
var reg = /^(.)*$/;
console.log(reg.toString(), typeof reg.toString())
console.log('=========字符串:string.toString()========')
var str = '123abc'
console.log(str.toString(), typeof str.toString());
console.log('=========symbol.toString()========')
var sym = Symbol('desc');
console.log(sym.toString(), typeof sym.toString())
Image may be NSFW.
Clik here to view.
前面也提到过,null
和undefined
值没有toString()
。因此在对这两个值进行了toString()
后,如果变量为null
或者undefined
的时候就会报错。
Image may be NSFW.
Clik here to view.
多数情况下,调用toString()
方法不必传递参数。但是,在调用数值的number.toString()
方法时,可以传递一个参数,输出数值的基数。默认情况下,number.toString()
方法以十进制格式返回数值的字符串表示。而通过传递基数,number.toString()
可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串。
var count = 10;
console.log(count.toString()); // => 10
console.log(count.toString(2)); // => 1010
console.log(count.toString(8)); // => 12
console.log(count.toString(10)); // => 10
console.log(count.toString(16)); // => a
通过这个例子可以看出,通过指定基数,number.toString()
方法会改变输出的值。而数值10
根据基数的不同,可以在输出时被转换为不同的数值格式。注意,默认的(没有参数的)输出值与指定基数10
时的输出值相同。
在JavaScript中,如果不知道要转换的值是不是null
或undefined
的情况下,建议使用String()
,因为这个函数能够将任何类型的值转换为字符串。如果值有toString()
方法,则调用该方法(没有参数)并返回相应的结果。
toString()
和String()
的主要区别就在于String()
还能转换null
和undefined
值,也可以说String()
是toString()
增强版,在开发中直接使用String()
似乎更好,这样能避免潜在的转换风险。
String() vs new String()
在JavaScript中有各种内建类型,通常称为原生类型,比如String()
就是一种原生类型。原生类型实际上是内建函数。
JavaScript的String()
看起来像是曾经用来创建字符串的String(...)
构造器。在很多时候可以看到这样的代码:
var str = new String('W3cplus');
console.log(str.toString()); // => 'W3cplus'
这些原生类型可以被用作一个原生类型的构造器。但是被构建出来的东西和我们想象的还是有所不同:
var str = 'W3cplus';
console.log(String(str), typeof String(str));
console.log(str.toString(), typeof str.toString());
console.log(new String(str), typeof new String(str));
Image may be NSFW.
Clik here to view.
上面的示例很明显看出来,它们的不同之处。String()
和toString()
转出来的是string
,但new String()
转换出来的是一个object
。而这个对象是一个对基本类型值str
的包装器对象。
var a = new String('w3cplus');
typeof a; // => object
a instanceof String; // => true
Object.prototype.toString.call(a); // => [object String]
Image may be NSFW.
Clik here to view.
重点是:new String('w3cplus')
为'w3cplus'
创建了一个字符串包装器对象,而不仅是基本类型值w3cplus
本身:
var a = 'w3cplus';
String(a) === a.toString(); // => true
String(a) === new String(a); // => false
a.toString() === new String(a); // => false
String
作为普通函数时会产生一个字符串(一个原始值)。作为构造函数时会产生一个String
对象的实例.后者在JavaScript中很少用到,所以基本上你可以忽略掉String
作为构造函数的用法,但一定要记得它是个转换函数.
另外有趣的是:
var a = 'w3cplus';
console.log(new String(a));
console.log(typeof new String(a));
console.log(new String(a).toString());
console.log(String(new String(a)));
Image may be NSFW.
Clik here to view.
从上面的示例中,使用toString()
或String()
将字符串对象转换为non-object
字符串。可能很多人都从没有想过调用String.toString()
可能是有用的。从这个示例中,也让初学者感到困惑:为什么在JavaScript中有两种字符串?
JavaScript中有两种类型的字符串:字面字符串和String对象。他们的行为有所不同。两者之间的主要区别在于你可以向
String
对象添加其他方法和属性。
来看个简单的示例:
var strObj = new String('object mode');
strObj.string_mode = 'object';
strObj.get_string_mode = function () {
return this.string_mode
}
str = strObj.toString(); // => 'object_mode'
这个时候,字符串文字只是临时转换为String
对象来执行任何核心方法。 同样的概念也适用于其他数据类型。
另外,new String()
转换出来的是一个String
对象。使用typeof
来判断后,其结果为object
,其实这个时候它就打上了一个内部的标签属性[[Class]]
。这个也常常称为内部属性。这个内部属性不能直接被访问,但通常可以间接地通过在这个值上借用默认的Object.prototype.toString(...)
方法调用来展示:
console.log(Object.prototype.toString.call([1,2,3])) // => [object Array]
console.log(Object.prototype.toString.call(true)) // => [object Boolean]
console.log(Object.prototype.toString.call(42)) // => [object Number]
所以对于上面的示例而言,数组内部的[[Class]]
值是'Array'
,布尔值它是'Boolean'
,数值是'Number'
。在大多数情况下,这个内部的[[Class]]
值对应于关联这个值的内建的原生类型构造器,但事实却不总是这样。
基本类型呢?首先,null
和undefined
:
Object.prototype.toString.call( null ); // => "[object Null]"
Object.prototype.toString.call( undefined ); // => "[object Undefined]"
你会注意到,不存在Null()
和Undefined()
原生类型构造器,但不管怎样"Null"
和"Undefined"
是被暴露出来的内部[[Class]]
值。
但是对于像string
,number
,和boolean
这样的简单基本类型,实际上会启动另一种行为,自动包装成一个封装对象,这种行为通常也被称为封箱。
Object.prototype.toString.call( "abc" ); // => "[object String]"
Object.prototype.toString.call( 42 ); // => "[object Number]"
Object.prototype.toString.call( true ); // => "[object Boolean]"
另外在JavaScript中,基本类型没有 .length
和.toString()
等这样的属性和方法,需要封装对象才可使用,此时JavaScript会为基本类型值自动包装成一个封装对象,浏览器对此也进行了优化,因此应优先考虑用基本类型值,而不是new String("abc")
新对象。
var str = 'w3cplus';
str.length; // => 7
一般来说,基本上没有理由直接使用对象形式。让封箱在需要的地方隐式地发生会更好。换句话说,永远也不要做new String("abc")
,new Number(42)
这样的事情——应当总是偏向于使用基本类型字面量"abc"
和42
。
在实际的使用中,一般不推荐直接使用封装对象,如果想要自行封装基本类型值,可以使用Object(...)
函数,而不带new
关键字:
var a = 'w3cplus';
var b = new String(a);
var c = Object(a);
console.log(typeof a); // => string
console.log(typeof b); // => object
console.log(typeof c); // => object
console.log(a instanceof String); // => false
console.log(b instanceof String); // => true
console.log(c instanceof String); // => true
console.log(Object.prototype.toString.call(a)); // => [object String]
console.log(Object.prototype.toString.call(b)); // => [object String]
console.log(Object.prototype.toString.call(c)); // => [object String]
开箱 valueOf()
有封装就有开箱,如果你有一个包装对象,但你又想取出底层的基本类型值,这个时候就可以使用valueOf()
方法。
var a = new String( "abc" );
var b = new Number( 42 );
var c = new Boolean( true );
a.valueOf(); // => "abc"
b.valueOf(); // => 42
c.valueOf(); // => true
在JavaScript中,valueOf()
函数算是一个非常少用的内建函数,但这个valueOf()
却十分重要。许多封装的对象都有这个valueOf()
函数,比如Boolean.valueOf()
、Number.valueOf()
和String.valueOf()
等。
console.log('=====boolean.valueOf()=====');
var bool = new Boolean();
console.log(typeof bool);
console.log(bool.valueOf());
console.log('=====number.valueOf()=====')
var count = new Number(100);
console.log(typeof count);
console.log(count.valueOf());
console.log('=====string.valueOf()=====')
var str = new String('w3cplus');
console.log(typeof str);
console.log(str.valueOf());
console.log('=====date.valueOf()=====')
var date = new Date()
console.log(typeof date);
console.log(date.valueOf());
console.log('=====object.valueOf()=====')
var obj = new Object();
obj.name = 'w3cplus';
obj.age = 7;
console.log(obj);
console.log(typeof obj);
console.log(obj.valueOf());
console.log('=====regExp.valueOf()=====')
var reg = new RegExp('^a*b+', 'g');
console.log(typeof reg);
console.log(reg.valueOf());
console.log('=====function.valueOf()=====')
var fn = function (a, b) {return a + b};
console.log(typeof fn);
console.log(fn.valueOf());
console.log('=====Symbol.valueOf()=====')
var sym = Symbol('foo');
console.log(typeof sym);
console.log(sym.valueOf());
Image may be NSFW.
Clik here to view.
前面也提到过了,null
和undefined
是属于特殊用途的,他们并没有new Null()
和new Undefined()
这样的封装器,也就是说他们是没有对应的封装对象。从而没有对应的valueOf()
。
在JavaScript中,当我们比较两个变量时,使用==
比较的是两个变量的值,那么像下面这样其值是true
:
var str1 = 'w3cplus';
var str2 = new String('w3cplus');
typeof(str1); // => string
typeof(str2); // => object
str1 == str2 // => true
这个结果令我感到困惑,str1
是一个String
类型,而str2
却是一个Object
类型,但用==
比较两个变量时,结果却为true
。后来才知道,在JavaScript中会帮我们自动转换类型,然后再进行比对。
事实上,当JavaScript任意东西在进行比较运算时,比如==
、!=
、<
、<=
、>
、>=
等等,都会先执行valueOf()
或toString()
函数,取回其原始类型的值。当拿到了原始类型的值之后,再进行比较。
除了原始类型之外,还有其他类型存在。而这些类型在默认情况下是无法进行比较的。比如:
var obj1 = {};
var obj2 = {};
obj1 == obj2; // => false
obj1 < obj2; // => false
obj1 > obj2; // => false
这个时候,就算我们采用了valueOf()
或toString()
方法,比较出来的结果依旧是false
。
Object.prototype.valueOf = function() {
return this.name.length;
}
Object.prototype.toString = function() {
return this.name
}
var a1 = {'name': 'w3cplus'}
var a2 = {'name': 'w3cplus'}
a1 == a2; // => false
a1 > a2; // => false
a1 < a2; // => false
所以,在JavaScript中,所有的对象都是不相等的,每一个都是独立的对象实例(Object Instance),这是一个非常重要的特性,即便你的操作中使用了valueOf()
和toString()
方法,依旧是无法对自定义对象进行任何相等比较运算。
为了在JavaScript中进行比较运算,一定要先将对象通过valueOf()
或toString()
方法转换成原始类型的值。比如下面这个小示例:
var obj1 = {'name': 'W3cplus'}
var obj2 = {'name': 'Edison'};
obj1.valueOf();
obj2.valueOf();
obj1.toString();
obj2.toString();
obj1 == obj2;
obj1 > obj2;
obj1 < obj2;
Object.prototype.valueOf= function (){
return this.name.length;
}
obj1 > obj2;
obj1 < obj2;
obj1.valueOf();
obj2.valueOf();
Object.prototype.toString = function() {
return this.name
}
obj1 > obj2;
obj1 < obj2;
delete Object.prototype.valueOf
obj1 > obj2;
obj1 < obj2;
Image may be NSFW.
Clik here to view.
总结
这篇文章是学习JavaScript中String()
、new String()
、toString()
和valueOf()
的相关知识。整理的有点乱,但相对而言,对这几个东东有了更深一层的了解和理解。我想在今后的使用中,应该会更易了。因为只有了解了才能更好的使用,当然在实际使用的时候肯定还会碰到坑,只有填坑是最好的验证方法。
扩展阅读
- JavaScript中数据类型转换
- 你不懂JS:类型与文法 第三章:原生类型
- 前端工程研究:關於 JavaScript 中物件的 valueOf 方法
- JavaScript中,如何将一个值转换为字符串
- JavaScript学习笔记01
- String cast VS toString() VS String.valueOf()
如需转载,烦请注明出处:https://www.w3cplus.com/javascript/toString-vs-String-vs-valueOf.html