
1.3.1 String类型的定义与调用
在JavaScript中,有3种定义字符串的方式,分别是字符串字面量,直接调用String()函数与new String()构造函数。
1. 字符串字面量
字符串字面量就是直接通过单引号或者双引号定义字符串的方式。
需要注意的是,在JavaScript中,单引号和双引号是等价的,都可以用来定义字符串,只不过使用单引号开头的字符串就要使用单引号结尾,使用双引号开头的字符串就要使用双引号结尾。
var str = 'hello JavaScript'; // 正确写法 var str2 = "hello html"; // 正确写法 var str = 'hello css"; // 错误写法,首尾符号不一样
2. 直接调用String()函数
直接调用String()函数,会将传入的任何类型的值转换成字符串类型,在转换时遵循的规则如下。
① 如果是Number类型的值,则直接转换成对应的字符串。
String(123); // '123' String(123.12); // '123.12'
② 如果是Boolean类型的值,则直接转换成'true'或者'false'。
String(true); // 'true' String(false); // 'false'
③ 如果值为null,则返回字符串'null';
String(null); // 'null'
④ 如果值为undefined,则返回字符串'undefined';
String(undefined); // 'undefined'
⑤ 如果值为字符串,则直接返回字符串本身;
String('this is a string'); // 'this is a string'
⑥ 如果值为引用类型,则会先调用toString()函数获取返回值,将返回值按照上述步骤①~⑤判断能否转换字符串类型,如果都不满足,则会调用对象的valueOf()函数获取返回值,并将返回值重新按照步骤①~⑤判断能否转换成字符串类型,如果也不满足,则会抛出类型转换的异常。
以下是通过toString()函数将对象正确转换成String类型的示例。
var obj = { age: 21, valueOf: function () { return this.age; }, toString: function () { return 'good'; } }; String(obj); // 'good'
以下是通过valueOf()函数将对象正确转换成String类型的示例。
var obj = { age: '21', valueOf: function () { return this.age; }, toString: function () { return []; } }; String(obj); // '21'
如果toString()函数和valueOf()函数返回的都是对象类型而无法转换成原生类型时,则会抛出类型转换的异常。
var obj = { age: '21', valueOf: function () { return []; }, toString: function () { return []; } }; String(obj); // 抛出异常TypeError: Cannot convert object to primitive value
3. new String()构造函数
new String()构造函数使用new运算符生成String类型的实例,对于传入的参数同样采用和上述String()函数一样的类型转换策略,最后的返回值是一个String类型对象的实例。
new String('hello JavaScript'); // String {"hello JavaScript"}
4. 三者在作比较时的区别
使用第一种字符串字面量方式和第二种直接调用String()函数的方式得到的字符串都是基本字符串,而通过第三种方式,new运算符生成的字符串是字符串对象。
基本字符串在作比较时,只需要比较字符串的值即可;而在比较字符串对象时,比较的是对象所在的地址。
我们看看以下用来测试相等的实例。
var str = 'hello'; var str2 = String(str); var str3 = String('hello'); var str4 = new String(str); var str5 = new String(str); var str6 = new String('hello'); str === str2; // true str2 === str3; // true str3 === str4; // false str4 === str5; // false str5 === str6; // false
首先对于str、str2和str3,因为都是基本字符串,只需要比较字符串的值即可,三者字符串值都为'hello',所以三者是互相严格相等的。
str === str2; // true str2 === str3; // true
其次,对于str4、str5和str6,因为是使用new运算符生成的String类型的实例,所以在比较时需要判断变量是否指向同一个对象,即内存地址是否相同,很明显str4、str5、str6都是在内存中新生成的地址,彼此各不相同。
str4 !== str5; // true str5 !== str6; // true str4 !== str6; // true
同样,对于基本字符串和字符串对象的比较,在判断严格相等时,也会返回“false”。
str === str4; // false str2 === str4; // false
5. 函数的调用
在String对象的原型链上有一系列的函数,例如indexOf()函数、substring()函数、slice()函数等,通过String对象的实例可以调用这些函数做字符串的处理。
但是我们发现,采用字面量方式定义的字符串没有通过new运算符生成String对象的实例也能够直接调用原型链上的函数。
'hello'.indexOf('e'); // 1 'hello'.substring(1); // 'ello' 'hello'.slice(1); // 'ello'
这是为什么呢?
实际上基本字符串本身是没有字符串对象的函数,而在基本字符串调用字符串对象才有的函数时,JavaScript会自动将基本字符串转换为字符串对象,形成一种包装类型,这样基本字符串就可以正常调用字符串对象的方法了。
基本字符串和字符串对象在经过eval()函数处理时,会产生不同的结果。
eval()函数会将基本字符串作为源代码处理,如果涉及表达式会直接进行运算,返回运算后的结果;而字符串对象则会被看作对象处理,返回对象本身。
var s1 = '2 + 2'; // 创建一个字符串字面量 var s2 = new String('2 + 2'); // 创建一个对象字符串 console.log(eval(s1)); // 4 console.log(eval(s2)); // String {"2 + 2"}
通过实例可以看出,在使用eval()函数处理字符串字面量时,进行了2 + 2 = 4的算术运算,并返回“4”;而使用eval()函数处理对象字符串时,会将'2 + 2'看成是一个对象,而不会进行运算,直接输出字符串本身。