JavaScript高级程序设计笔记(5)-引用类型之基本包装类型

基本包装类型

ECMAScript提供了三个特殊引用类型: Boolean、 Number 和 String。这些类型与其他引用类型相似,但同时具有与各自基本类型相应的特殊行为。实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本类型的包装对象,从而我们能够调用一些方法,来处理数据。

1
2
var s1 = 'some text';
var s2 = s1.substring(2);

上面,s1包含一个字符串,自然是基本类型了,而下一行调用了substring方法,并将结果保存在s2中。基本类型从逻辑上讲,不应该有方法,为什么s1还能调用方法呢。实际上,为了实现上述直观操作,后台已完成了一系列处理。当第二行代码访问s1时,访问过程处于一种读取状态,也就是从内存中读取字符串的值。在读取模式中访问字符串时,后台会自动完成以下处理:

1、创建一个String类型的实例
2、在实例上调用指定方法
3、销毁这个实例

引用类型和基本包装类型的主要区别在于对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前,都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码执行瞬间,然后立即被销毁。这意味着我们不能再运行时为基本类型值添加属性和方法。

1
2
3
var s1 = 'some text';
s1.color = 'red';
alert(s1.color);//undefined

之所以是undefined,就是因为第二行创建的String对象在执行第三行代码时,已经被销毁了。第三行代码又创建了自己的String对象,而该对象没有color属性。

可以显示调用Boolen、Number和String来创建基本包装类型的对象。但应该在绝对必要的情况下再这样做,因为这种做法容易让人分不清自己在处理基本类型还是引用类型的值。基本包装类型调用typeof 会返回 object,而且所有基本包装类型的对象都会被转换为布尔值 true

Object构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。

1
2
var obj = new Object('some text');
alert(obj instanceof String); //true

使用new 调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。

1
2
3
4
5
6
var value = '25';
var number = Number(value);//转型函数
alert(typeof number);//'number'

var obj = new Number(value);//构造函数
alert(typeof obj);//'object'

在上例中,变量number中保存的基本类型的值25, 而变量obj中保存的是Number的实例。

tips: 尽管不建议直接显示创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的,而每个基本包装类型都提供了操作相应值得便捷方法。

Boolean类型

Boolean类型是与布尔值对应的引用类型。要创建Boolean对象,可如下:

1
var booleanObject = new Boolean(true);

Boolean类型的实例重写了valueof()方法,返回基本类型值true或false;重写了toString()方法,返回字符串”true”和”false”。Boolean对象在ECMAScript中用处不大,经常会造成误解。其中最常见的问题就是在布尔表达式中使用Boolean对象。例:

1
2
3
4
5
6
7
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true

var falseValue = false;
result = falseVaule && true;
alert(result); // false

上述第一个alert之所以输出true,是因为布尔表达式中所有对象都会被转换为true。

基本类型与引用类型的布尔值有两个区别:
1、typeof 操作符对基本类型返回’boolean’,对引用类型返回’object’
2、由于Boolean 对象是Boolean类型的实例,所以使用instanceof 操作符测试Boolean对象会返回true, 而测试基本类型的布尔值则返回false。

1
2
3
4
5
alert(typeof falseObject); //'object'
alert(typeof falseVaule);//'boolean'

alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean);//false

建议永远不要使用Boolean对象

Number 类型

Number是数字值对应的引用类型。要创建Number对象,可以调用Number构造函数时,向其中传递相应的数值。例:

1
var numberObject = new Number(10);

与Boolean类型一样,Number类型也重写了valueof()、toLocaleString()和toString()。valueof()方法返回对象表示基本类型的数值,另外两个方法则返回字符串形式的数值。toString()方法传递一个表示基数的参数,告诉它以几进制的方式返回数值的字符串形式。

1
2
3
4
5
var num = 10;
alert(num.toString());//'10'
alert(num.toString(2));//'1010'
alert(num.toString(8));//'12'
alert(num.toString(10)); '10'

除了继承的方法之外,Number类型还提供了一些用于将数值格式化为字符串的方法。

toFixed()方法会按指定的小数位数返回数值的字符串表示

1
2
3
4
5
6
var num = 10;
alert(num.toFixed(2));//10.00
var num1 = 10.005;
alert(num1.toFixed(2));//10.01
var num2 = 10.007;
alert(num2.toFixed(2));//10.01

toFixed()方法可以处理0-20个小数位的数字,但这只是规范而已,有些浏览器支持更多位数。

toExponential(),该方法返回指数表示法(e表示法)

与toFixed()方法一样,toExponential()也接收一个参数,而且该参数同样也是指定输出结果中的小数位数。

1
2
var num = 10;
alert(num.toExponential(1));//1.0e+1

toPrecision()

对于一个数值来说,toPrecision()方法可能返回固定大小(fixed)格式,也可能返回指数(exponential)格式,具体规则看哪种格式最合适。该方法接收一个参数,即表示数值的所有数字的位数(不包括指数部分)。

1
2
3
4
var num = 99;
alert(num.toPrecision(1));//'1e+2'
alert(num.toPrecision(2));//'99'
alert(num.toPrecision(2));'99.0'

实际上,toPrecision()会根据要处理的数值,决定到底调用toFixed()还是调用toExponential()。这三种方法都可以通过向上或向下舍入,做到以最准确的形式来表示带有正确的小数位数。

toPrecision()方法可以表现1到21位小数。某些浏览器支持范围更大。

与Boolean一样,不建议直接实例化Number类型。

1
2
3
4
5
6
var numberObject = new Number(10);
var numberVaule = 10;
alert(typeof numberObject); //'Object'
alert(typeof numberValue);//'number'
alert(numberObject instanceof Number);//'true'
alert(numberValue instanceof Number); //'false'

String类型

String类型是字符串的对象包装类型,可以使用String构造函数来创建。

1
var StringObject = new String('Hello world');

String对象的方法,也可以在所有基本的字符串值中来访问。其中,继承的valueOf()、toLocaleString()和toString()方法,都返回对象所表示的基本字符串值。

String类型的每个实例都有一个length属性,表示字符串中包含多少个字符。

1
2
var stringValue = 'hello world';
alert(stringVlue.length);//11

String类型提供了很多方法,用于辅助完成对ECMAScript中字符串的解析和操作。

字符方法

charAt()和charCodeAt()两个方法都接收一个参数,即基于0的字符位置。

charAt(): 以单字符字符串的形式返回给定位置的那个字符。
charCodeAt():返回指定位置的字符的字符编码

1
2
3
4
5
6
7
8
var stringValue = 'hello world';

alert(stringValue.charAt(1)); //'e'

alert(stringCodeAt(1));//'101'

//ECMAScript还定义另一个访问个别字符的方法
alert(stringVlaue[1]);//'e'

字符串操作方法

1、 concat()方法: 用于将一个或多个字符串拼接起来,返回拼接得到的心字符串。实际应用中,拼接字符串使用更多的是加号操作符(+)。

1
2
3
4
5
6
7
var stringValue = 'hello ';
var result = stringValue.conat('world');
alert(result) = 'hello world';
alert(stringVaule) = 'hello ';

var result1 = stringValue.concat('world', '!');
alert(result1);//'hello world!'

2 、 ECMAScript还提供了三个基于字符串创建新字符串的方法: slice()、substr()、substring()。这三种方法都会返回备操作字符串的一个子字符串,而且都接收一或两个参数。第一个参数指定子字符串的起始位置,第二个参数(在指定的情况下)表示字符串结束的位置。
slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而substr()的第二个参数指定的则是返回的字符个数。如果没有传递第二个参数,则将字符串的长度作为结束位置,不包含该字符。与concat方法一样,slice()、substr()和substring()也不会修改字符串本身的值,它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。

1
2
3
4
5
6
7
8
var stringValue = 'hello world';
alert(stringValue.slice(3));//'lo world'
alert(stringValue.substring(3));//'lo world'
alert(stringValue.substr(3));//'lo world'

alert(stringVaule.slice(3, 7));//'lo w'
alert(stringValue.substring(3, 7)); 'lo w'
alert(stringValue.substr(3, 7)); 'lo worl'

substr()第二个参数表示返回的字符串个数,所以返回了7个字符。

在传递给这些方法的参数是负值的情况下,它们的行为就不尽相同了。slice()方法会将传入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串长度,而将第二个参数转换为0。最后,substring()方法会将所有负值参数都转换为0.

1
2
3
4
5
6
7
8
var stringValue = 'hello world';
alert(stringValue.slice(-3));//'rld'
alert(stringValue.substring(-3));'hello world'
alert(stringValue.substr(-3)); 'rld';

alert(stringValue.slice(3, -4));//'lo w'
alert(stringValue.substring(3, -4));'hel'
alert(stringValue.substr(3, -4)); ''(空字符串)

IE的Javascript实现在处理向substr()方法传递负值得情况时存在问题,它会返回原始的字符串。IE9修复了这个问题。

3、 字符串位置方法

indexOf()和lastIndexOf():这两个方法都是从一个字符串中搜索给定的子字符串,然后返回子字符串的位置,如果没有找到就返回-1。
idnexOf()从字符串开头向后寻找,而lastIndexOf()方法是从字符串末尾向前搜索。

1
2
3
var stringValue = 'hello world';
alert(stringValue.indexof('o'));// 4,第一次出现位置
alert(stringValue.lastIndexOf('o'));// 7

这两个方法都可接受第二个参数,表示从字符串的哪个位置开始搜索。

1
2
3
var stringValue = 'hello world';
alert(stringValue.indexof('o', 6));// 7
alert(stringValue.lastIndexOf('o', 6));// 4

通过循环调用indexOf()或lastIndexOf()来找到所有匹配的字符串。

1
2
3
4
5
6
7
8
var stringValue = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit';
var positions = [];
var pos = stringValue.indexOf('e');
while(pos > -1){
positions.push(pos);
pos = stringValue.indexOf('e', pos + 1);
}
alert(positions);//3, 24, 32, 35, 52

4、 trim()方法
trim()方法会创建一个字符串的副本,删除前置及后缀所有的空格,然后返回结果。

1
2
3
var stringVaule = '  hello wolrd  ';
alert(stringValue.trim());//'hello world';
alert(stringValue);//' hello world '

部分浏览器还支持非标准的trimLeft()和trimRight()方法

5、字符串大小写转换
toLowerCase()/toLocaleCase(): 小写转换,后一种针对地区语言保证实现。
toUperCase()/toLocaleUpercase(): 大写转换,后一种针对地区语言保证实现。

6、字符串模式匹配

第一种方法: match()。本质上与调用RegExp的exec()方法相同。macth()只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象。该方法返回一个数组。

1
2
3
4
5
6
var s = 'hat, cat, at, bat';
var pattern = /.at/;
var pattern0 = /.at/g;
console.log(s.match(pattern));//["cat", index: 0, input: "cat,hat,at,bat"]
console.log(s.match(pattern).index);//0
console.log(s.match(pattern0));//["cat", "hat", ",at", "bat"]

第二种方法: search()。该方法的唯一参数与match()方法参数相同:由字符串或者RegExp对象指定的一个正则表达式。search()方法返回字符中第一个匹配项的索引;如果没有找到匹配项,返回 -1。

1
2
var s = 'hat, cat, at, bat';
console.log(s.search(/at/));//1

第三种方法: replace()。该方法接受两个参数,第一个参数:可以是一个RegExp对象或者一个字符串,第二个参数可以是一个字符串,或者一个函数。

1
2
3
4
5
6
var s = 'hat, cat, at, bat';
var rs = s.replace('at','ond');
console.log(rs); //'hond, cat, at, bat';

var rs0 = s.replace(/at/g, 'ond');
console.log(rs0);//'hond, cond, ond, bond';

localeCompare()方法。

localeCompare()返回三个值: 负数(大部分是-1)、0 、正数(大部分是1)。

1
2
3
4
var s = 'yellow';
console.log(s.localeCompare('brick'));// 1,字符串('yellow')在字母表中应该排在字符串参数('brick')之后,则返回一个正数。
console.log(s.localeCompare('yellow'));// 0,字符串('yellow')在字母表中与字符串参数('yellow')相等,则返回0。
console.log(s.localeCompare('zoo'));// -1,字符串('yellow')在字母表中应该排在字符串参数('zoo')之前,则返回一个负数。

fromCharCode()方法

与charCodeAt()执行的是相反的操作,该方法接收一或多个字符编码,然后将他们转换成一个字符串。

1
console.log(String.fromCharCode(104,101,108,108,111));//'hello'

HTML方法