和Java类似,为了便于操作基本类型值,ECMAScript也提供了3个特殊的引用类型:Boolean
、Number
和String
。每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。有点类似于Java的自动拆装箱过程,以String
类型为例:
var s1 = "some text"; var s2 = s1.substring(2);
在访问s1
时,访问过程处于读取模式,后台自动完成下列处理:
- 创建
String
类型的一个实例; - 在实例上调用指定的方法;
- 销毁这个实例。
以上三个步骤可以想象成下列代码:
var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;
以上三个步骤同样适用于Boolean
和Number
类型对应的布尔值和数字值。
引用类型与基本包装类型主要区别就是对象的生存期:使用new
操作符创建的引用类型的实例,在执行流离开当前引用域之前一直都保存在内存中。而自动创建的基本包装类型的对象,则只存在一行代码的执行瞬间,然后立即销毁。这意味着不能在运行时为基本类型值添加属性和方法,如下:
var s1 = "hello"; s1.name = "Jack"; alert(s1.name); // undefined
对基本包装类型的实例调用typeof会返回object,所有基本包装类型的对象都会被转换为布尔值true。
Object构造函数会根据传入值的类型返回相应的基本包装类型:
var obj1 = new Object("hello"); var obj2 = new Object(12); var obj3 = new Object(true); alert(obj1 instanceof String); // true alert(obj2 instanceof Number); // true alert(obj3 instanceof Boolean); // true
注意,使用new调用基本包装类型的构造函数,与直接调用同名的转型函数不一样:
var val = "10"; var num = Number(val); // 转型函数 alert(typeof num); // number var obj = new Number(val); // 构造函数 alert(typeof obj); // object
Boolean类型
Boolean类型是与布尔值对应的引用类型。创建Boolean类型对象:调用Boolean构造函数并传入true或false值。
var trueObj = new Boolean(true); var falseObj = new Boolean(false);
Boolean类型的实例重写了valueOf()方法,返回基本类型值true或false;重写toString()方法,返回字符“true”或“false”。
在布尔表达式中使用Boolean对象时要特别注意:布尔表达式中的所有对象都会被转换为true。
var falseObj = new Boolean(false); var result = falseObj && true; // ① alert(result); // true var falseVal = false; result = falseVal && true; // ② alert(result); // false
上面的例子中,首先创建了一个false值的Boolean对象falseObj。①处将falseObj与基本类型值true进行&&运算。这里特别要注意:falseObj会转换为true。所以结果为true。②处都是基本类型,进行&&运算结果为false、
基本类型与引用类型的布尔值还有两个区别:
- typeof操作符对基本类型返回“boolean”,而引用类型返回“object”
- 使用instanceof操作符测试Boolean对象会返回true,而测试基本类型的布尔值则返回false
看下面的例子:
alert(typeof falseObj); // object alert(typeof falseVal); // boolean alert(falseObj instanceof Boolean); // true alert(falseVal instanceof Boolean); // false
建议永远不要使用Boolean
对象。
Number类型
Number是与数字值对应的引用类型。创建Number类型对象:调用Number构造函数时向其中传递相应的数值
var numObj = new Number(100);
Number类型重写了valueOf()、toLocaleString()和toString()方法,重写后valueOf()返回对象表示的基本类型的数值,toLocaleString()和toString()方法返回字符串形式的数值。toString()方法传递一个表示基数的参数,告诉它返回几进制数值的字符串形式。
var num = 11; alert(num.toString()); // "11" alert(num.toString(2)); // "1011" alert(num.toString(8)); // "13" alert(num.toString(10)); // "11" alert(num.toString(16)); // "b"
另外,Number提供了一些将数值格式化为字符串的方法。
1.toFixed()
toFixed()方法会按照指定的小数位返回值得字符串表示。如果数值本身包含的小数位比指定的还多,那么接近制定的最大小数位的值会舍入:
var num1 = 11; alert(num1.toFixed(2)); // "11.00" var num2 = 11.005; alert(num1.toFixed(2)); // "11.01"
2.toExponential()
toExponential()方法用于格式化,返回指数表示法(也称e表示法),表示的数值的字符串形式。可以传入一个参数,指定输出结果中的小数位数。
var num = 11; alert(num.toExponential(1)); // “1.0e+1”
3.toPrecision()
toPrecision()方法可能返回固定大小格式,也可能返回指数格式。可以接收一个参数,表示数值的所有数字的位数(不含指数部分)
var num = 99; alert(num.toPrecision(1)); // "1e+2",即100,无法准确表示99 alert(num.toPrecision(2)); // "99" alert(num.toPrecision(3)); // "99.0"
与Boolean类型相似,使用typeof和instanceof操作基本类型数值和引用类型数值时,得到的结果完全不同。
var numObj = new Number(11); var numVal = 11; alert(typeof numObj); // "object" alert(typeof numVal); // "number" alert(numObj instanceof Number); // true alert(numObj instanceof Number); // false
不建议直接实例化Number类型。
String类型
String类型是字符串的对象包装类型,创建String类型:
var strObj = new String("hello javascript");
String类型继承的valueOf()、toLocaleString()和toString()方法,都返回对象所表示的基本字符串值。
String类型的每个实例都有一个length属性,表示字符串中包含多少个字符。
String类型提供了很多方法,用于完成字符串的解析和操作:
1.字符方法
两个用于访问字符串中特定字符的方法:charAt()和charCodeAt()。都接收一个参数:基于0的字符位置
- charAt():以单字符串的形式返回给定位置的那个字符
- charCodeAt():返回字符的编码
var strVal = "hello"; alert(strVal.char(1)); // "e" alert(strVal.charCodeAt(1)); // "101"
也可以通过方括号加数字索引来访问字符串中的特定字符:
var strVal = "hello"; alert(strVal[1]); // "e"
2.字符串操作方法
- concat():用于将一个或多个字符串拼接起来,可以接收多个参数,返回拼接得到的新字符串,--------------不改变原来的字符串。
var strVal = "hello "; var result = strVal.concat("javascript"); alert(result); // "hello javascript" alert(strVal); // "hello " var result1 = strVal.concat("world", "!") alert(result1); // "hello world!"
实践中使用更多的是加号操作符(+)。
下面的三个方法都返回被操作字符串的子字符串,接收1或2个字符串。不同的是: --------------不改变原来的字符串。
- slice():第一个参数表示起始位置,第二个参数表示结束位置(子字符串最后一个字符后面的位置)(不包含)
- substr():第一个参数表示起始位置,第二个参数表示返回的字符个数(不包含)
- substring():第一个参数表示起始位置,第二个参数表示结束位置(子字符串最后一个字符后面的位置)(不包含)
var str = "hello world"; alert(str.slice(3)); // "lo world" alert(str.slice(3, 7)); // "lo w" alert(str.substr(3)); // "lo world" alert(str.substr(3, 7)); // "lo worl" alert(str.substring(3)); // "lo world" alert(str.substring(3, 7)); // "lo w"
当参数为负数时,上面的三个方法行为各不相同:
- slice():将传入的负值与字符串的长度相加
- substr():将负的第一个参数加上字符串的长度,将负的第二个参数转换为0
- substring():将所有负值参数都转换为0
var strVal = "hello world"; alert(strVal.slice(-3)); // "rld" alert(strVal.substr(-3)); // "rld" alert(strVal.substring(-3));// "hello world" alert(strVal.slice(3, -4)); // "lo w" alert(strVal.substr(3, -4));// "" alert(strVal.substring(3, -4));// "hel"
下面对第二个参数是负值的情况作出解释:
- 由于slice()会将第二个负的参数加上字符串的长度,所以
strVal.slice(3,-4)
会转换为strVal.slice(3, 7)
,因此返回“lo w”。- substr()会将第二个参数转换为0,
strVal.substr(3, -4)
会转换为strVal.substr(3, 0)
,因此返回的是空串。- substring()会将第二个负的参数转换为0,
strVal.substring(3, -4)
会转换为strVal.substring(3, 0)
,但是,substring()会将较小的数作为开始位置,将较大的数作为结束位置,因此,最终转换为strVal.substring(0, 3)
,所以返回结果为“hel”。
3.字符串位置方法
从字符串查找子字符串的方法:indexOf()
和lastIndexOf()
。它们都从字符串中查找子字符串,返回子字符串的位置(如果没有找到子字符串,则返回-1),区别在于:
- indexOf():字符串开头向后搜索子字符串
- lastIndexOf():从字符串的末尾向前搜索子字符串
var strVal = "hello world"; alert(strVal.indexOf("o")); // 4 alert(strVal.lastIndexOf("o")); // 7
这两个方法可以接收可选的第二个参数,表示搜索的开始位置。indexOf()会从该参数指定的位置向后搜索,忽略该位置之前的所有字符,lastIndexOf()会从指定的位置向前搜索,忽略该位置之后的所有字符。
var strVal = "hello world"; alert(strVal.indexOf("o", 6)); // 7 alert(strVal.lastIndexOf("o", 6)); // 4
在使用第二个参数的情况下,可以通过循环调用indexOf()或lastIndexOf()来找到所有匹配的子字符串:
var strVal = "Only hard work forever as a necessary of life; even if there is no hope of harvest, but also a calm to continue farming."; var positions = new Array(); var pos = strVal.indexOf("o"); while(pos > -1) { positions.push(pos); pos = strVal.indexOf("o", pos + 1); } alert(positions); // 11,16,38,65,68,72,91,101,104
4.trim()
trim()会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。 --------------不改变原来的字符串。
var strVal = " hello world "; var trimStrVal = strVal.trim(); alert(strVal); // " hello world " alert(trimStrVal); // "hello world"
5.字符串大小写转换方法
四种:toLowerCase()
、toLocaleLowerCase()
、toUpperCase()
和toLocaleUpperCase()
。
var strVal = "heLLo woRLd"; alert(strVal.toLocaleUpperCase()); // "HELLO WORLD" alert(strVal.toUpperCase()); // "HELLO WORLD" alert(strVal.toLocaleLowerCase()); // "hello world" alert(strVal.toLowerCase()) // "hello world"
6.字符串模式匹配方法
- match()方法:接收一个正则表达式或者一个RegExp对象,返回一个数组,数组的第一项是与整个模式匹配的字符串,之后的每一项保存着与正则表达式中的捕获组匹配的字符串。
var text = "cat, bat, sat, fat"; var pattern = /.at/; // 与pattern.exec(text)相同 var matches = text.match(pattern); alert(matches.index); // 0 alert(matches[0]); // "cat" alert(pattern.lastIndex); // 0
- search():接收一个正则表达式,返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1
var text = "cat, bat, sat, fat"; var pos = text.search(/at/); alert(pos); // 1
- replace():该方法接收两个参数,第一个参数是RegExp对象或字符串,第二个参数可以是字符串或一个函数。当第一个参数是一个字符串时,只会替换第一个子字符串。想替换所有字符串只能提供一个正则表达式,并且要指定全局(g)标志。
var text = "cat, bat, sat, fat"; var result = text.replace("at", "ond"); alert(result); // cond, bat, sat, fat result = text.replace(/at/g, "ond"); alert(result); // cond, bond, sond, fond
-
如果第二个参数是字符串,那么还可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中。下表列出了ECMAScript提供的这些特殊的字符序列。
字符序列 替换文本 $$ $ $& 匹配整个模式的子字符串。与RegExp.lastMatch的值相同 $’ 匹配的子字符串之前的子字符串。与RegExp.leftContext的值相同 $` 匹配的子字符串之前的子字符串。与RegExp.rightContext的值相同 $n 匹配第n个捕获组的子字符组,其中nn等于0~9。例如,$1是匹配第一个捕获组的子字符串,$2是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串 $nn 匹配第nn个捕获组的子字符串,其中nn等于01~99。例如$01是匹配第一个捕获组的子字符串,$02是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串 通过这些特殊的字符序列,可以使用最近一次匹配结果中的内容,如下
var text = "cat, bat, sat, fat"; result = text.replace(/(.at)/g, "word ($1)"); alert(result); //word (cat), word (bat), word(sat), word (fat)
-
当第二个参数是一个函数时,在只有一个匹配项的情况下,会向这个函数传递3个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。在正则表达式中定义了多个捕获组的情况下,传递给函数的参数一次是模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项……,但最后两个参数仍然分别是模式匹配项在字符串中的位置和原始字符串。
function htmlEscape(text) { return text.replace(/[<>"&]/g, function(match, pos, originalText) { switch (match) { case "<": return "<"; case ">": return ">"; case "&": return "&"; case """: return """; } }); } alert(htmlEscape("<p class="greeting">Hello world!</p>")); // <p class="greeting">Hello world!</p>
-
- split():可以指定基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。split()还可以接收可选的第二个参数, 用于指定数组的大小。
var colorText = "red, blue, green, yellow"; var colors1 = colorText.split(","); alert(colors1); // ["red", "blue", "green", "yellow"] var colors2 = colorText.split(",", 2); // ["red", "blue"]
7.localeCompare()方法
localeCompare()用于比较两个字符串,并返回下列结果之一:
- 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(多数情况为-1,具体由实现而定)
- 如果字符串等于字符串的参数,则返回0;
- 如果字符串在字母表中应该排在字符串参数之后,则返回一个整数(多数情况为1,具体由实现而定)
var strVal = "yellow"; alert(strVal.localeCompare("brick")); // -1 alert(strVal.localeCompare("yellow")); // 0 alert(strVal.localeCompare("zoo")); // 1
8.fromCharCode()
String构造函数本身有一个静态方法:fromCharCode()。这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。与charCodeAt()执行的是相反的操作
alert(String.fromCharCode(104, 101, 108, 108, 111)); // "hello"