目录
尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构。
在ECMAScript中,引用类型是一种类似于类的数据结构。
ECMAScript提供了很多原生引用类型(例如Object),以便开发人员用以实现常见的计算任务。
一、Object类型
Object是ECMAScript中使用最多的一个类型。
1.1、创建Object实例的方式
①使用Object构造函数
var person = new Object();
person.name = "Nicholas";
person.age = 29;
②使用对象字面量
var person = {
name: "Nicholas",
age: 29
};
在使用对象字面量语法时,属性名也可以使用字符串
var person = {
"name": "Nicholas",
"age": 29
};
1.2、访问对象属性的方法
①点表示法
alert(person.name); //"Nicholas"
②方括号表示法
alert(person["name"]); //"Nicholas"
方括号语法的主要优点是可以通过变量来访问属性:
var propertyName = "name"
alert(person[propertyName]); //"Nicholas"
如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法,例如:
person["first name"] = "Nicholas";
二、Array类型
ECMAScript数组的每一项可以保存任何类型的数据。
ECMAScript数组的大小是可以动态调整的。
2.1、创建数组的方式
①使用Array构造函数
var colors = new Array();
var colors2 = new Array(20); //指定数组长度
var colors3 = new Array("red", "blue", "green"); //直接加入数组元素
②使用数组字面量
var colors = []; //创建一个空数组
var colors2 = ["red", "blue", "green"] //加入数组元素
2.2、length属性
数组的项数保存在其length属性中
var colors2 = ["red", "blue", "green"]
alert(colors2.length); //3
length属性不是只读的,可以通过设置这个属性来删除元素或添加元素
var colors = ["red", "blue", "green"];
colors.length = 2; //删除了第三项
alert(colors[2]); //undefined
2.3、转换方法
数组转换为字符串方法
- toString()
- toLocaleString()
- valueOf()
- join()
var colors = ["red", "blue", "green"];
alert(colors.toString()); // red,blue,green
alert(colors.toLocaleString()); // red,blue,green
alert(colors.valueOf()); // red,blue,green
alert(colors); // red,blue,green
alert(colors.join(",")); // red,blue,green
alert(colors.join("||")); // red||blue||green
2.4、栈方法和队列方法
- push() —— 接收任意数量参数,将它们逐个添加到数组末尾,并返回修改后数组的长度。
- pop() —— 从数组末尾移除最后一项,并返回该项。
- unshift() —— 在数组前端添加任意个项并返回修改后数组的长度。
- shift() —— 移除数组中的第一个项并返回该项。
栈示例:
var colors = new Array();
var count = colors.push("red", "green");
console.log(count); //2
var item = colors.pop(); //取得最后一项
console.log(item); //"black"
队列示例:
var colors = new Array();
var count = colors.push("red", "green");
console.log(count); //2
var item = colors.shift();
console.log(item); //"red"
2.5、重排序方法
- reverse() —— 反转数组项的顺序
- sort() —— 为数组排序
var values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values); //5, 4, 3, 2, 1
function compare(value1 , value2){
if(value1 < value2){
return 1;
}else if(value1 > value2){
return -1;
}else{
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values); //15, 10, 5, 1, 0
2.6、操作方法
- concat() —— 合并数组
- slice() —— 可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,返回从该参数指定位置开始到当前数组末尾的所有项。
- splice(index, delete, add) —— 可以用于删除、插入和替换数组元素
var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);
console.log(colors2); //red,green,blue,yellow,black,brown
var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1, 4);
console.log(colors2); //green,blue,yellow,purple
console.log(colors3); //green,blue,yellow
var colors = ["red", "green", "blue"];
var removed = colors.splice(0, 1); //删除第一项
console.log(colors); // green,blue
console.log(removed); //red
colors.splice(1, 0, "yellow", "orange"); //从位置1开始插入两项
console.log(colors); //green,yellow.orange,blue
colors.splice(1, 1, "red", "purple"); //替换
console.log(colors); //green, red, purple, orange, blue
2.7、位置方法
- indexOf(element, index) —— 从左往右查找数组元素
- lastIndexOf(element, index) —— 从右往左查找数组元素
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
console.log(numbers.indexOf(4)); //3
console.log(numbers.lastIndexOf(4)); //5
console.log(numbers.indexOf(4, 4)); //5
console.log(numbers.lastIndexOf(4, 4)); //3
2.8、迭代方法
- every() —— 对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true
- some() —— 对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true
- filter() —— 对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
- map() —— 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
- forEach() —— 对数组中的每一项运行给定函数,这个方法没有返回值
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
var everyResult = numbers.every(function(item, index, array){
return (item > 2);
});
console.log(everyResult); //false
var someResult = numbers.some(function(item, index, array){
return (item > 2);
});
console.log(someResult); //true
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});
console.log(filterResult); //[3, 4, 5, 4, 3]
var mapResult = numbers.map(function(item, index, array){
return item * 2;
});
console.log(mapResult); //[2, 4, 6, 8, 10, 8, 6, 4, 2]
numbers.forEach(function(item, index, array){
//执行某些操作
});
2.9、归并方法
- reduce() —— 从数组的第一项开始,迭代数组的所有项,然后构建一个最终返回的值
- reduceRight() —— 从数组的最后一项开始,迭代数组的所有项,然后构建一个最终返回的值
var values = [1, 2, 3, 4, 5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
sum = values.reduceRight(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
三、Date类型
Date类型保存的日期能够精确到1970年1月1日之前或之后的100 000 000年。
在调用Date构造函数而不传递参数的情况下,新创建的对象自动获得当前日期和时间:
var now = new Date(); //自动获得当前日期和时间
如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数(即从UTC时间1970年1月1日午夜起至该日期止经过的毫秒数)。
为了简化这一计算过程,ECMAScript提供了两个方法:Date.parse()和Date.UTC()
3.1、Date.parse()
Date.parse()方法接收一个表示日期的字符串参数,然后根据这个字符串返回相应日期的毫秒数。
ECMA-262没有定义Date.parse()应该支持哪种日期格式,因此这个方法的行为因实现而异,而且通常是因地区而异。
将地区设置为美国的浏览器通常都接受下列日期格式:
- "月/日/年",如6/13/2004
- "英文月名 日,年",如January 12, 2004
- "英文星期几 英文月名 日 年 时:分:秒 时区",如Tue May 25 2004 00:00:00 GMT-0700
- ISO 8601 扩展格式 YYYY-MM-DDTHH:mm:ss.sssZ(例如 2004-05-25T00:00:00)
例如为2004年5月25日创建一个日期对象:
var someDate = new Date(Date.parse("May 25, 2004"));
实际上,如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse()。下面的代码与前面的示例是等价的:
var someDate = new Date("May 25, 2004");
3.2、Date.UTC()
Date.UTC()方法同样也返回表示日期的毫秒数,但它与Date.parse()在构建时使用不同的信息。
Date.UTC()的参数分别是:
- 年份
- 基于0的月份(一月是0,二月是1,以此类推)
- 月中的哪一天(1到31)
- 小时数(0到23)
- 分钟
- 秒
- 毫秒数。
在这些参数中,只有前两个参数(年和月)是必需的。如果没有提供月中的天数,则假设天数为1,如果省略其他参数,则统统假设为0.
示例:
// GMT时间2000年1月1日午夜零时
var y2k = new Date(Date.UTC(2000, 0));
// GMT时间2005年5月5日下午5:55:55
var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
注:GMT时间是指格林尼治所在地的标准时间。
如同模仿Date.parse()一样,Date构造函数也会模仿Date.UTC(),但有一点明显不同:日期和时间都基于本地时区而非GMT来创建。
示例:
// 本地时间2000年1月1日午夜零时
var y2k = new Date(2000, 0);
// 本地时间2005年5月5日下午5:55:55
var allFives = new Date(2005, 4, 5, 17, 55, 55);
3.3、Date.now()
ECMAScript5添加了Date.now()方法,返回表示调用这个方法时的日期和时间的毫秒数。
在不支持它的浏览器中,使用+操作符获取Date对象的时间戳,也可以达到同样的目的。
//取得开始时间
var start = Date.now();
//调用函数
doSomething();
//取得停止时间,使用+符号将字符串转为数值
var stop = +new Date();
var result = stop - start;
3.4、继承的方法
- toLocaleString() —— 不返回时区信息
- toString() —— 返回时区信息
- valueOf() —— 返回日期的毫秒表示
由于Date类型的valueOf()方法,返回的是number类型的日期的毫秒表示。
因此,可以方便使用比较操作符来比较日期值。
示例:
var date1 = new Date(2007, 0, 1); // "January 1, 2007"
var date2 = new Date(2007, 1, 1); // "February 1, 2007"
console.log(date1 < date2); // true
console.log(date1 > date2); // false
3.5、日期/时间组件方法
四、RegExp类型
4.1、对象字面量形式
ECMAScript通过RegExp类型来支持正则表达式。使用下面的语法就可以创建一个正则表达式:
var expression = / pattern / flags;
pattern(模式)部分可以是任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、向前查找以及反向引用。
flags(标志)用以标明正则表达式的行为。支持下列3个标志:
- g —— 表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止
- i —— 表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写。
- m —— 表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。
示例:
//匹配字符串中所有"at"的实例
var pattern1 = /at/g;
//匹配第一个"bat"或"cat",不区分大小写
var pattern2 = /[bc]at/i;
//匹配所有以"at"结尾的3个字符的组合,不区分大小写
var pattern3 = /.at/gi;
模式中使用的所有元字符都必须转义,元字符包括:
( [ { \ ^ $ | ) ? * + . ] }
这些元字符在正则表达式中都有一或多种特殊用途,因此如果想要匹配字符串中包含的这些字符,就必须对它们进行转义。
示例:
//匹配第一个"[bc]at",不区分大小写
var pattern2 = /\[bc\]at/i;
//匹配所有".at",不区分大小写
var pattern4 = /\.at/gi;
4.2、RegExp构造函数
另一种创建正则表达式的方式是使用RegExp构造函数。
它接收两个参数:
- 要匹配的字符串模式
- 另一个是可选的标志字符串
示例:
//匹配第一个"bat"或"cat",不区分大小写
var pattern = new RegExp("[bc]at", "i");
由于RegExp构造函数的模式参数是字符串,所以在某些情况下要对字符串进行双重转义:
4.3、RegExp实例属性
RegExp的每个实例都具有下列属性:
- global —— 布尔值,表示是否设置了g标志
- ignoreCase —— 布尔值,表示是否设置了i标志
- lastIndex —— 整数,表示开始搜索下一个匹配项的字符位置,从0算起
- multiline —— 布尔值,表示是否设置了m标志
- source —— 正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回
示例:
var pattern1 = /\[bc\]at/i;
alert(pattern1.global); //false
alert(pattern1.ignoreCase); //true
alert(pattern1.multiline); //false
alert(pattern1.lastIndex); //0
alert(pattern1.source); //"\[bc\]at"
var pattern2 = new RegExp("\\[bc\\]at", "i");
alert(pattern2.global); //false
alert(pattern2.ignoreCase); //true
alert(pattern2.multiline); //false
alert(pattern2.lastIndex); //0
alert(pattern2.source); //"\[bc\]at"
4.4、RegExp实例方法
①exec()
RegExp对象的主要方法是exec(),该方法是专门为捕获组而设计的。
exec()接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。
返回的的数组虽然是Array的实例,但包含两个额外的属性:
- index —— 表示匹配项在字符串中的位置
- input —— 表示应用正则表达式的字符串
在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。
示例:
var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);
alert(matches.index); // 0
alert(matches.input); // "mom and dad and baby"
alert(matches[0]); // "mom and dad and baby"
alert(matches[1]); // " and dad and baby"
alert(matches[2]); // " and baby"
对于exec()方法而言,在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息。
即使在模式中设置了全局标志(g),它每次也只会返回一个匹配项,而每次调用exec()则都会在字符串中继续查找新匹配项,例如:
var text = "cat, bat, sat, fat";
var pattern1 = /.at/;
var matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern1.lastIndex); // 0
matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern1.lastIndex); // 0
var pattern2 = /.at/g;
var matches = pattern2.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern2.lastIndex); // 3
matches = pattern2.exec(text);
console.log(matches.index); // 5
console.log(matches[0]); // bat
console.log(pattern2.lastIndex); // 8
②test()
正则表达式的第二个方法是test()。
它接受一个字符串参数,在模式与该参数匹配的情况下返回true,否则,返回false。
在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,使用这个方法非常方便。
示例:
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if(pattern.test(text)){
alert("The pattern was matched.");
}
③继承的方法
- toLocaleString() —— 返回正则表达式的字面量
- toString() —— 返回正则表达式的字面量
var pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.toString()); // /\[bc\]at/gi
console.log(pattern.toLocaleString()); // /\[bc\]at/gi
4.5、RegExp构造函数属性
RegExp构造函数包含一些属性(这些属性在其他语言中被看成是静态属性)。
这些属性适用于作用域中的所有正则表达式,并且基于所执行的最近一次正则表达式操作而变化。
关于这些属性的另一个独特之处,就是可以通过两种方式访问它们。即这些属性分别有一个长属性名和一个短属性名。
这些属性可以从exec()或test()执行的操作中提取出更具体的信息。
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if(pattern.test(text)){
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
console.log(RegExp.multiline); // false
}
上述使用的长属性名都可以用相应的短属性名来代替。
由于这些短属性名大都不是有效的ECMAScript标识符,因此必须通过方括号语法来访问它们。
示例:
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if(pattern.test(text)){
console.log(RegExp.$_); // this has been a short summer
console.log(RegExp["$`"]); // this has been a
console.log(RegExp["$'"]); // summer
console.log(RegExp["$&"]); // short
console.log(RegExp["$+"]); // s
console.log(RegExp["$*"]); // false
}
还有9个用于存储捕获组的构造函数属性。
访问这些属性的语法是RegExp.$1、RegExp.$2......RegExp.$9。
这些属性分别用于存储第一、第二......第九个匹配的捕获组。
示例:
var text = "this has been a short summer";
var pattern = /(..)or(.)/g;
if(pattern.test(text)){
console.log(RegExp.$1); // sh
console.log(RegExp.$2); // t
}
五、Function类型
每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。
由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。
5.1、定义函数的方式
①函数声明语法
function sum(num1, num2){
return num1 + num2;
}
②函数表达式
var sum = function(num1, num2){
return num1 + num2;
};
③Function构造函数
var sum = new Function("num1", "num2", "return num1 + num2");
Function构造函数的最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。
由于这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串)导致影响性能,所以不推荐使用这种方法定义函数。
5.2、没有重载
function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num){
return num + 200;
}
var result = addSomeNumber(100); //300
这个例子中声明了两个同名函数,而结果则是后面的函数覆盖了前面的函数,以上代码与下面的代码没有什么区别:
var addSomeNumber = function(num){
return num + 100;
};
addSomeNumber = function(num){
return num + 200;
};
var result = addSomeNumber(100); //300
5.3、函数声明与函数表达式
解析器在向执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)。
至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
函数声明:
alert(sum(10, 10)); //20
function sum(num1, num2){
return num1 + num2;
}
函数表达式:
alert(sum(10, 10)); //报错
var sum = function(num1, num2){
return num1 + num2;
}
5.4、作为值的函数
因为ECMAScript中的函数名本身就是变量,所以函数也可以作为值来使用。
不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
示例:
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10); //函数作为参数
alert(result1); //20
5.5、函数内部属性
①arguments.length
arguments是一个类数组对象,包含着传入函数中的所有参数。
arguments对象有一个callee的属性,该属性指向拥有这个arguments对象的函数。
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * factorial(num - 1);
}
}
上面定义的阶乘函数的函数名factorial与函数体代码紧密耦合在一起,为了消除这种紧密耦合,可以像下面这样使用arguments.callee:
function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1);
}
}
这样,无论引用函数时使用的是什么名字,都可以保证正常完成递归调用,例如:
var trueFactorial = factorial;
factorial = function(){
return 0;
};
alert(trueFactorial(5)); //120
alert(factorial(5)); //0
②this
函数中的this引用的是函数执行时所在执行环境的环境对象。
示例:
window.color = "red";
var o = {
color: "blue"
};
function sayColor(){
alert(this.color);
}
sayColor(); //"red"
o.sayColor = sayColor;
o.sayColor(); //"blue"
5.6、函数属性和方法
①caller
ECMAScript5规范化了一个函数对象的属性:caller,这个属性中保存着调用当前函数的函数的引用。
function outer(){
inner();
}
function innner(){
alert(inner.caller); //"outer"
}
outer();
为了实现更松散的耦合,可以通过arguments.callee.caller来访问相同的信息。
function outer(){
inner();
}
function innner(){
alert(arguments.callee.caller); //"outer"
}
outer();
②length
length属性表示函数希望接收的命名参数的个数
function sayName(name){
alert(name);
}
function sum(num1, num2){
return num1 + num2;
}
function sayHi(){
alert("hi");
}
alert(sayName.length); //1
alert(sum.length); //2
alert(sayHi,length); //0
③prototype
prototype属性保存函数的原型对象,prototype属性是不可枚举的,因此使用for-in无法实现。
④apply()方法和call()方法
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
示例:
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, [num1, num2]); //参数是数组类型的
}
function callSum2(num1, num2){
return sum.call(this, num1, num2); //参数是逐个列举出来的
}
alert(callSum1(10, 10)); //20
alert(callSum2(10, 10)); //20
这两个方法真正强大的地方是能够扩充函数赖以运行的作用域。
示例:
window.color = "red";
var o = {
color: "blue"
};
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
⑤bind()方法
ECMAScript5还定义了一个方法:bind()
这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值
window.color = "red";
var o = {
color: "blue"
};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
⑥toLocaleString()、toString()和valueOf()方法
这三个方法都返回函数代码。
六、基本包装类型
为了便于操作基本类型值,ECMAScript提供了3个特殊的引用类型:
- Boolean
- Number
- String
每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。
var s1 = "some text";
var s2 = s1.substring(2);
第二行代码访问s1时,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值。
在读取模式中访问字符串时,后台会自动完成下列处理:
- ①创建String类型的一个实例
- ②在实例上调用指定的方法
- ③销毁这个实例
可以将以上三个步骤想象成是执行了下列ECMAScript代码:
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
引用类型与基本包装类型的主要区别就是对象的生存期:
- 使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。
- 而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。
6.1、Boolean类型
Boolean类型是与布尔值对应的引用类型,可以像下面这样调用Boolean构造函数并传入true或false值:
var booleanObject = new Boolean(true);
Boolean对象在ECMAScript中的用处不大,因为它经常会造成人们的误解:
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true
var falseValue = false;
result = falseValue && true;
alert(result); //false
布尔表达式中的所有对象都会被转换为true,因此falseObject对象在布尔表达式中代表的是true。
所以,最好永远不要使用Boolean对象。
6.2、Number类型
Number是与数字值对应的引用类型。
要创建Number对象,可以在调用Number构造函数时向其中传递相应的数值:
var numberObject = new Number(10);
①继承的方法
- toLocaleString() —— 返回字符串形式的数值
- toString() —— 返回字符串形式的数值。可以传递一个表示基数的参数,以返回特定进制数值的字符串形式
- valueOf() —— 返回对象表示的基本类型的数值
示例:
var num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
②格式化数值的方法
- toFixed() —— 按照指定的小数位返回数值的字符串表示
- toExponential() —— 返回以指数表示法表示的数值的字符串形式。也接收一个指定输出结果小数位数的参数。
- toPrecision() —— 返回某个数值的最合适格式的字符串表示。可能会返回固定大小(fixed)格式,也可能返回指数(exponential)格式。接收一个参数,表示数值的所有数字的位数(不包括指数部分)。
示例:
var num = 10.005;
console.log(num.toFixed(2)); //"10.o1"
var num = 10;
console.log(num.toExponential(1)); //"1.0e+1"
var num = 99;
console.log(num.toPrecision(1)); // "1e+2"
console.log(num.toPrecision(2)); // "99"
console.log(num.toPrecision(3)); // "99.0"
6.3、String类型
String类型是字符串的对象包装类型,可以像下面这样使用String构造函数来创建:
var stringObject = new String("hello world");
①length属性
String类型的每个实例都有一个length属性,表示字符串中包含多少个字符
示例:
var stringValue = "hello world";
alert(stringValue.length); // 11
②继承的方法
- valueOf()
- toLocaleString()
- toString()
以上三个方法都返回对象表示的基本字符串值。
③字符方法
两个用于访问字符串中特定字符的方法是:
- charAt() —— 以单字符字符串的形式返回给定位置的那个字符
- charCodeAt() —— 以字符编码字符串的形式放回给定位置的那个字符
示例:
var stringValue = "hello world";
alert(stringValue.charAt(1)); // "e"
alert(stringValue.charCodeAt(1)); // "101"
另外,还可以使用方括号加数字索引来访问字符串中的特定字符:
var stringValue = "hello world";
alert(stringValue[1]); // "e"
④字符串操作方法
- concat() —— 用于将一个或多个字符串拼接起来,返回拼接得到的新字符串
- slice() —— 截取子字符串
- substring() —— 截取子字符串
- substr() —— 截取子字符串
示例1:
var stringValue = "hello ";
var result = stringValue.concat("world");
alert(result); // "hello world";
alert(stringValue); // "hello"
示例2:
var stringValue = "hello world";
alert(stringValue.slice(3)); // "lo world"
alert(stringValue.substring(3)); // "lo world"
alert(stringValue.substr(3)); // "lo world"
alert(stringValue.slice(3, 7)); // "lo w"
alert(stringValue.substring(3, 7)); // "lo w"
// substr()方法的第二个参数指定的是返回字符的个数
alert(stringValue.substr(3, 7)); // "lo worl"
⑤字符串位置方法
- indexOf() —— 从字符串的开头向后搜索子字符串的位置
- lastIndexOf() —— 从字符串的末尾向前搜索子字符串的位置
示例:
var stringValue = "hello world";
alert(stringValue.indexOf("o")); // 4
alert(stringValue.lastIndexOf("o")) // 7
这两个方法都可以接受可选的第二个参数,表示从字符串中的哪个位置开始搜索。
示例:
var stringValue = "hello world";
alert(stringValue.indexOf("o", 6)); // 7
alert(stringValue.lastIndexOf("o", 6)); // 4
⑥trim()方法
trim()方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。
示例:
var stringValue = " hello world ";
var trimmedStringValue = stringValue.trim();
alert(stringValue); // " hello world "
alert(trimmedStringValue); // "hello world"
⑥字符串大小写转换方法
ECMAScript中涉及字符串大小写转换的方法有4个:
- toLowerCase()
- toLocaleLowerCase()
- toUpperCase()
- toLocaleUpperCase()
toLocaleLowerCase()和toLocaleUpperCase()方法是针对特定地区的实现。
对有些地区来说,针对地区的方法与其通用方法得到的结果相同,但少数语言会为Unicode大小写转换应用特殊规则,这时候就必须使用针对地区的方法来保证实现正确的转换。
var stringValue = "hello world";
console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD"
console.log(stringValue.toUpperCase()); // "HELLO WORLD"
console.log(stringValue.toLocaleLowerCase()); // "hello world"
console.log(stringValue.toLowerCase()); // "hello world"
⑦字符串的模式匹配方法
String类型定义了几个用于在字符串中匹配模式的方法。
第一个方法就是match(),在字符串上调用这个方法,本质上与调用RegExp的exec()方法相同。
match()方法只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象。
示例:
var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches = text.match(pattern);
console.log(matches.index); //0
console.log(matches[0]); //"cat"
console.log(pattern.lastIndex); //0
另一个用于查找模式的方法是search()。
这个方法的唯一参数与match()方法的参数相同:由字符串或RegExp对象指定的一个正则表达式。
search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。
而且,search()方法始终是从字符串开头向后查找模式。
示例:
var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
console.log(pos); //1
为了简化子字符串的操作,ECMAScript提供了replace()方法。
这个方法接受两个参数:
- 第一个参数可以是一个RegExp对象或者一个字符串(这个字符串不会被转换成正则表达式)
- 第二个参数可以是一个字符串或者一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的方法就是提供一个正则表达式,而且要指定全局(g)标志。
示例:
var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
console.log(result); //"cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
console.log(result); //"cond, bond, sond, fond"
如果第二个参数是字符串,那么还可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中。
下表列出了ECMAScript提供的这些特殊的字符序列:
示例:
var text = "cat, bat, sat, fat";
var result = text.replace(/(.at)/g, "word ($1)");
console.log(result); // word (cat), word (bat), word (sat), word (fat)
replace()方法的第二个参数也可以是一个函数。
在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递3个参数:
- 模式的匹配项
- 模式匹配项在字符串中的位置
- 原始字符串
在正则表达式中定义了多个捕获组的情况下,传递给函数的参数依次是:
- 模式的匹配项
- 第一个捕获组的匹配项
- 第二个捕获组的匹配项
- 。。。。
- 模式的匹配项在字符串中的位置
- 原始的字符串
这个函数应该返回一个字符串,表示应该被替换的匹配项。
示例:
function htmlEscape(text){
return text.replace(/[<>"&]/g, function(match, pos, originalText){
switch(match){
case "<" :
return "<";
case ">" :
return ">";
case "&" :
return "&";
case "\"":
return """;
}
});
}
console.log(htmlEscape("<p calss=\"greeting\">Hello world!</p>"));
// <p calss="greeting">Hello world!</p>
split()这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。
分隔符可以是字符串,也可以是一个RegExp对象(这个方法不会将字符串看成正则表达式)。
split()可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。
示例:
var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"]
var colors2 = colorText.split(",", 2); // ["red", "blue"]
var colors3 = colorText.split(/[^\,]+/); // ["", ",", ",", ",", ""]
⑧localeCompare()方法
localeCompare()这个方法比较两个字符串,并返回下列值中的一个:
- 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定)
- 如果字符串等于字符串参数,则返回0
- 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是1,具体的值要视实现而定)
var stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1
⑨fromCharCode()方法
String构造函数本身还有一个静态方法:fromCharCode()
这个方法的任务是接收一或多个字符编码,然后将他们转换成一个字符串。
从本质上来看,这个方法与实例方法charCodeAt()执行的是相反的操作。
示例:
console.log(String.fromCharCode(104, 101, 108, 108, 111)); // "hello"
七、单体内置对象
ECMA-262对内置对象的定义是:由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。
例如Object、Array和String都是内置对象,ECMA-262还定义了两个单体内置对象:Global和Math
7.1、Global对象
ECMAScript中的Golbal对象在某种意义上是作为一个终极的“兜底儿对象”来定义的。
换句话说,不属于任何其他对象的属性和方法,最终都是它的属性和方法。
事实上,没有全局变量或全局函数,所有在全局作用域中定义的属性和函数,都是Golbal对象的属性。
诸如isNaN()、isFinite()、parseInt()以及parseFloat(),实际上全都是Global对象的方法。
除此之外,Global对象还包含其他一些方法:
①URI编码方法
Global对象的encodeURI()和encodeURIComponent()方法可以对URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。
有效的URI中不能包含某些字符,例如空格。
而这两个URI编码方法就可以对URI进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接收和理解。
其中,encodeURI()主要用于整个URI(例如,http://www.wrox.com/illegal value.htm),而encodeURIComponent()主要用于对URI中的某一段(例如前面URI中的illegal value.htm)进行编码。
它们的主要区别在于:
encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。
示例:
var uri = "http://www.wrox.com/illegal value.htm#start";
//"http://www.wrox.com/illegal%20value.htm#start"
console.log(encodeURI(uri));
//"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
console.log(encodeURIComponent(uri));
与上面两个方法对应的是以下两个方法:
- decodeURI() —— 只能对使用encodeURI()替换的字符进行编码。例如它可将%20替换成一个空格,但不会对%23作任何处理,因为%23表示井字号(#),而井字号不是使用encodeURI()替换的。
- decodeURIComponent() —— 能够解码使用encodeURIComponent()编码的所有字符,即它可以解码任何特殊字符的编码
示例:
var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
// "http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start"
console.log(decodeURI(uri));
// "http://www.wrox.com/illegal value.htm#start"
console.log(decodeURIComponent(uri));
②eval()方法
eval()方法就像是一个完整的ECMAscript解析器,它只接收一个参数,即要执行的ECMAScript(或JavaScript)字符串。
示例:
eval("alert('hi')"); // 等价于alert("hi")
当解析器发现代码中调用eval()方法时,它会将传入的参数当作实际的ECMAScript语句来解析,然后把结果插入到原位置。
通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链。
这意味着通过eval()执行的代码可以引用在包含环境中定义的变量,例如:
var msg = "hello world";
eval("alert(msg)"); // "hello world"
在eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字符串中;它们只在eval()执行的时候创建。
7.2、Math对象
ECMAScript还为保存数学公式和信息提供了一个公共位置,即Math对象。
①Math对象的属性
②min()和max()方法
min()和max()方法用于确定一组数值中的最小值和最大值。
示例:
var max = Math.max(3, 54, 32, 16);
console.log(max); // 54
var min = Math.min(3, 54, 32, 16);
console.log(min); // 3
要找到数组中的最大值或最小值,可以像下面这样使用apply()方法:
var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
③舍入方法
下面来介绍将小数值舍入为整数的几个方法:
- Math.ceil() —— 执行向上舍入,即它总是将数值向上舍入为最接近的整数
- Math.floor() —— 执行向下舍入,即它总是将数值向下舍入为最接近的整数
- Math.round() —— 执行标准舍入,即它总是将数值四舍五入为最接近的整数
示例:
console.log(Math.ceil(25.5)); // 26
console.log(Math.floor(25.5)); // 25
console.log(Math.round(25.5)); // 26
④random()方法
Math.random()方法返回大于等于0小于1的一个随机数。
套用下面的公式,就可以利用Math.random()从某个范围内随机选择一个值。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
示例:
// 随机选择一个介于2到10之间的值
var num = Math.floor(Math.random() * 9 + 2);
⑤其他方法
Math对像中还包含其他一些与完成各种简单或复杂计算有关的方法: