JavaScript高级程序设计3:第5章 引用类型

引用类型的值(对象)是引用类型的一个实例。在 ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起。

5.1 Object类型

到目前为止,我们看到的大多数引用类型值都是 Object 类型的实例;

创建 Object 实例的方式有两种。

  1. new 操作符后跟 Object 构造函数

    var person = new Object(); 
    person.name = "Nicholas"; 
    person.age = 29;
  2. 使用对象字面量表示法

    var person = { 
     name : "Nicholas", 
     age : 29 
    };

    在使用对象字面量语法时,属性名也可以使用字符串

var person = { 
 "name" : "Nicholas", 
 "age" : 29, 
 5 : true 
};

使用对象字面量语法时,如果留空其花括号,则可以定义只包含默认属性和方法的对象

var person = {}; //与 new Object()相同
person.name = "Nicholas"; 
person.age = 29;

对象字面量也是向函数传递大量可选参 数的首选方式

访问对象属性时使用的都是点表示法,在 JavaScript 也可以使用方括号表示法来访问对象的属性。在使用方括号语法时,应该将要访问的属性以字符串的形式放在方括号中.

alert(person["name"]); //"Nicholas" 
alert(person.name); //"Nicholas"

方括号语法的主要优点是可以通过变量来访问属性

var propertyName = "name"; 
alert(person[propertyName]); //"Nicholas"

如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法

person["first name"] = "Nicholas";

通常,除非必须使用变量来访问属性,否则我们建议使用点表示法。

5.2 Array类型

ECMAScript 数组的每一项可以保存任何类型的数据。而且,ECMAScript 数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新增数据。

创建数组的基本方式有两种。

  1. 使用 Array 构造函数

    var colors = new Array();
    ​
    var colors = new Array(20);
    ​
    var colors = new Array("red", "blue", "green");
    ​

    在使用 Array 构造函数时也可以省略 new 操作符。

    var colors = Array(3); // 创建一个包含 3 项的数组
    var names = Array("Greg"); // 创建一个包含 1 项,即字符串"Greg"的数组

  2. 使用数组字面量表示法

    数组字面量由一对包含数组项的方括号表示,多个数组项之间以逗号隔开

    var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
    var names = []; // 创建一个空数组
    var values = [1,2,]; // 不要这样!这样会创建一个包含 2 或 3 项的数组
    var options = [,,,,,]; // 不要这样!这样会创建一个包含 5 或 6 项的数组

    数组的 length 属性很有特点——它不是只读的。因此,通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。

    利用 length 属性也可以方便地在数组末尾添加新项。

5.2.1 检测数组

Array.isArray()方法:最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的。

5.2.2 转换方法

调用数组的 toString()方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。而调用 valueOf()返回的还是数组

当调用数组的 toLocaleString()方法时,它也会创建一个数组值的以逗号分隔的字符串

var person1 = { 
 toLocaleString : function () { 
 return "Nikolaos"; 
 }, 
 
 toString : function() { 
 return "Nicholas"; 
 } 
}; 
var person2 = { 
 toLocaleString : function () { 
 return "Grigorios"; 
 }, 
 
 toString : function() { 
 return "Greg"; 
 } 
}; 
var people = [person1, person2]; 
alert(people); //Nicholas,Greg 
alert(people.toString()); //Nicholas,Greg 
alert(people.toLocaleString()); //Nikolaos,Grigorios

在将数组传递给 alert()时,输出结果是"Nicholas,Greg",因为调用了数组每一项的 toString()方法(同样,这与下一行显式调用 toString()方法得到的结果相同)。

使用 join()方法,则可以使用不同的分隔符来构建这个字符串

如果数组中的某一项的值是 null 或者 undefined,那么该值在 join()、toLocaleString()、toString()和 valueOf()方法返回的结果中以空字符串表示。

5.2.3 栈方法

push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。

pop()方法则从数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项。

5.2.4 队列方法

shift()移除数组中的第一个项并返回该项,同时将数组长度减 1。

结合使用 shift()和 push()方法,实现数组末端添加项 数组前端取得项。

var colors = new Array(); //创建一个数组
var count = colors.push("red", "green"); //推入两项
alert(count); //2 
count = colors.push("black"); //推入另一项
alert(count); //3 
var item = colors.shift(); //取得第一项
alert(item); //"red" 
alert(colors.length); //2

unshift()方法在数组前端添加任意个项并返回新数组的长度。

结合使用 unshift()和 pop()方法,实现数组的前端添加项,从数组末端移除项。

var colors = new Array(); //创建一个数组
var count = colors.unshift("red", "green"); //推入两项
alert(count); //2
count = colors.unshift("black"); //推入另一项
alert(count); //3 
var item = colors.pop(); //取得最后一项
alert(item); //"green" 
alert(colors.length); //2

5.2.5 重排列方法

reverse():会反转数组项的顺序

sort():按升序排列数组项,比较的也是字符串

var values = [0, 1, 5, 10, 15]; 
values.sort(); 
alert(values); //0,1,10,15,5

sort()方法可以接收一个比较函数作为参数

比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数。

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);
alert(values); //0,1,5,10,15

对于数值类型或者其 valueOf()方法会返回数值类型的对象类型,可以使用一个更简单的比较函数。这个函数只要用第二个值减第一个值即可。

function compare(value1, value2){ 
 return value2 - value1; 
}

5.2.6 操作方法

concat()方法可以基于当前数组中的所有项创建一个新数组不会改变原数组

var colors = ["red", "green", "blue"]; 
var colors2 = colors.concat("yellow", ["black", "brown"]); 
alert(colors); //red,green,blue 
alert(colors2); //red,green,blue,yellow,black,brown

slice()能够基于当前数组中的一或多个项创建一个新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置。不会改变原数组

在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。

如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。

var colors = ["red", "green", "blue", "yellow", "purple"]; 
var colors2 = colors.slice(1); 
var colors3 = colors.slice(1,4); 
alert(colors2); //green,blue,yellow,purple 
alert(colors3); //green,blue,yellow

splice()的主要用途是向数组的中部插入项

  • 删除:指定 2 个参数:要删除的第一项的位置和要删除的项数。例如,splice(0,2)会删除数组中的前两项。

  • 插入:提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。例如,splice(2,0,"red","green")会从当前数组的位置 2 开始插入字符串"red"和"green"。

  • 替换:指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如,splice (2,1,"red","green")会删除当前数组位置 2 的项,然后再从位置 2 开始插入字符串"red"和"green"。

splice()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组)。

var colors = ["red", "green", "blue"]; 
var removed = colors.splice(0,1); // 删除第一项
alert(colors); // green,blue 
alert(removed); // red,返回的数组中只包含一项
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
alert(colors); // green,yellow,orange,blue 
alert(removed); // 返回的是一个空数组
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
alert(colors); // green,red,purple,orange,blue 
alert(removed); // yellow,返回的数组中只包含一项

5.2.7 位置方法

indexOf()和 lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。

indexOf()方法从数组的开头(位置 0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。

这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回-1。

5.2.8 迭代方法

every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true

filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。

var numbers = [1,2,3,4,5,4,3,2,1]; 
var filterResult = numbers.filter(function(item, index, array){ 
 return (item > 2); 
}); 
alert(filterResult); //[3,4,5,4,3]

forEach():对数组中的每一项运行给定函数。这个方法没有返回值。

map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

var numbers = [1,2,3,4,5,4,3,2,1]; 
var mapResult = numbers.map(function(item, index, array){ 
 return item * 2; 
}); 
alert(mapResult); //[2,4,6,8,10,8,6,4,2]

some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true

以上方法都不会修改数组中的包含的值。

5.2.9 归并方法

reduce()和 reduceRight():迭代数组的所有项,然后构建一个最终返回的值。

reduce()方法从数组的第一项开始,逐个遍历到最后。而 reduceRight()则从数组的最后一项开始,向前遍历到第一项。

传给 reduce()和 reduceRight()的函数接收 4 个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。

var values = [1,2,3,4,5]; 
var sum = values.reduce(function(prev, cur, index, array){ 
 return prev + cur; 
}); 
alert(sum); //15

第一次执行回调函数,prev 是 1,cur 是 2。第二次,prev 是 3(1 加 2 的结果),cur 是 3(数组的第三项)。这个过程会持续到把数组中的每一项都访问一遍,最后返回结果。

5.3 Date类型

var now = new Date(); 如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数。

Date.parse()方法接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数

实际上,如果直接将表示日期的字符串传递给 Date 构造函数,也会在后台调用 Date.parse()。

var someDate = new Date(Date.parse("May 25, 2004"));

var someDate = new Date("May 25, 2004");

Date.UTC()的参数分别是年份、基于 0 的月份(一月是 0,二月是 1,以此类推)、月中的哪一天(1 到 31)、小时数(0 到 23)、分钟、秒以及毫秒数。

// 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));

// 本地时间 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);

Data.now()方法,返回表示调用这个方法时的日期和时间的毫秒数。

//取得开始时间
var start = Date.now(); 
//调用函数
doSomething(); 
//取得停止时间
var stop = Date.now(), 
 result = stop – start;

在不支持它的浏览器中,使用+操作符把 Data 对象转换成字符串,也可以达到同样的目的。

//取得开始时间
var start = +new Date(); 
//调用函数
doSomething(); 
//取得停止时间
var stop = +new Date(), 
 result = stop - start;

5.3.1 继承的方法

Date 类型的 valueOf()方法,则根本不返回字符串,而是返回日期的毫秒表示。因此,可以方便使用比较操作符(小于或大于)来比较日期值

5.3.2 日期格式化方法

5.3.3 日期/时间组件方法

方法说明
getTime()返回表示日期的毫秒数;与valueOf()方法返回的值相同
getFullYear()取得4位数的年份(如2007而非仅07)
setFullYear(年)设置日期的年份。传入的年份值必须是4位数字(如2007而非仅07)
getMonth()返回日期中的月份,其中0表示一月,11表示十二月
setMonth(月)设置日期的月份。传入的月份值必须大于0,超过11则增加年份
getDate()返回日期月份中的天数(1到31)
setDate(日)设置日期月份中的天数。如果传入的值超过了该月中应有的天数,则增加月份
getDay()返回日期中星期的星期几(其中0表示星期日,6表示星期六)
getHours()返回日期中的小时数(0到23)

5.4 RegExp类型

var expression = / pattern / flags ;

 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;

与其他语言中的正则表达式类似,模式中使用的所有元字符都必须转义。正则表达式中的元字符包括:

( [ { \ ^ $ | ) ? * + .]}

/* 
* 匹配第一个"bat"或"cat",不区分大小写
*/
var pattern1 = /[bc]at/i; 
/* 
* 匹配第一个" [bc]at",不区分大小写
*/ 
var pattern2 = /\[bc\]at/i; 
/* 
* 匹配所有以"at"结尾的 3 个字符的组合,不区分大小写
*/ 
var pattern3 = /.at/gi; 
/* 
* 匹配所有".at",不区分大小写
*/ 
var pattern4 = /\.at/gi;

前面举的这些例子都是以字面量形式来定义的正则表达式。另一种创建正则表达式的方式是使用RegExp 构造函数,它接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串。可以使用字面量定义的任何表达式,都可以使用构造函数来定义。

/* 
* 匹配第一个"bat"或"cat",不区分大小写
*/ 
var pattern1 = /[bc]at/i; 
/* 
* 与 pattern1 相同,只不过是使用构造函数创建的
*/ 
var pattern2 = new RegExp("[bc]at", "i");

ECMAScript 5 明确规定,使用正则表达式字面量必须像直接调用 RegExp 构造函数一样,每次都创建新的 RegExp 实例

5.4.1 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"

5.4.2 RegExp实例方法

exec()方法是专门为捕获组而设计的。exec()接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回 null。

在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串。

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()则都会在字符串中继续查找新匹配项。

var text = "cat, bat, sat, fat"; 
var pattern1 = /.at/; 
var matches = pattern1.exec(text); 
alert(matches.index); //0 
alert(matches[0]); //cat 
alert(pattern1.lastIndex); //0 
matches = pattern1.exec(text); 
alert(matches.index); //0 
alert(matches[0]); //cat 
alert(pattern1.lastIndex); //0 


var pattern2 = /.at/g; 
var matches = pattern2.exec(text); 
alert(matches.index); //0 
alert(matches[0]); //cat 
alert(pattern2.lastIndex); //3
matches = pattern2.exec(text); 
alert(matches.index); //5 
alert(matches[0]); //bat 
alert(pattern2.lastIndex); //8

test()方法接受一个字符串参数。在模式与该参数匹配的情况下返回true;否则,返回 false。

5.4.3 RegExp构造函数属性

5.4.4 模式的局限性

5.5 Function类型

定义函数的方法:

  1. 使用函数声明语法定义

    function sum (num1, num2) { 
     return num1 + num2; 
    }
  2. 使用函数表达式定义

    var sum = function(num1, num2){ 
     return num1 + num2; 
    };
  3. 使用Function构造函数定义

    Function 构造函数可以接收任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。

    var sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐

函数是对象,函数名是指针

由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。换句话说,一个函数可能会有多个名字。

function sum(num1, num2){ 
 return num1 + num2; 
} 
alert(sum(10,10)); //20 

// 使用不带圆括号的函数名是访问函数指针,而非调用函数
var anotherSum = sum; 
alert(anotherSum(10,10)); //20 

sum = null; 
alert(anotherSum(10,10)); //20

5.5.1 没有重载(深入理解)

var addSomeNumber = function (num){ 
 return num + 100; 
}; 
addSomeNumber = function (num) { 
 return num + 200; 
}; 
var result = addSomeNumber(100); //300

在创建第二个函数时,实际上覆盖了引用第一个函数的变量 addSomeNumber

5.5.2 函数声明与函数表达式

解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

5.5.3 作为值的函数

因为 ECMAScript 中的函数名本身就是变量,所以函数也可以作为值来使用。 不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回.

function callSomeFunction(someFunction, someArgument){ 
 return someFunction(someArgument); 
}

function add10(num){ 
 return num + 10; 
} 
var result1 = callSomeFunction(add10, 10); 
alert(result1); //20

function createComparisonFunction(propertyName) { 
 return function(object1, object2){ 
 var value1 = object1[propertyName]; 
 var value2 = object2[propertyName]; 
 if (value1 < value2){ 
 	return -1; 
 } else if (value1 > value2){ 
 	return 1; 
 } else { 
 	return 0; 
 } 
 }; 
}

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}]; 
data.sort(createComparisonFunction("name")); 
alert(data[0].name); //Nicholas

5.5.4 函数内部属性

在函数内部,有两个特殊的对象:arguments 和 this

arguments 是一个类数组对象,包含着传入函数中的所有参数。虽然 arguments 的主要用途是保存函数参数,

但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。

function factorial(num){ 
   if (num <=1) { 
       return 1; 
   } else { 
      return num * factorial(num-1) 
      // 问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起,为了消除这种紧密耦合的现象
  	  // return num * arguments.callee(num-1)
   } 
}

this引用的是函数据以执行的环境对象

5.5.5 函数属性和方法

ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length 和 prototype

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

在 ECMAScript 5 中,prototype 属性是不可枚举的,因此使用 for-in 无法发现。

每个函数都包含两个非继承而来的方法:apply()和 call()

apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是arguments 对象。

function sum(num1, num2){ 
 return num1 + num2; 
} 
function callSum1(num1, num2){ 
 return sum.apply(this, arguments); // 传入 arguments 对象
} 
function callSum2(num1, num2){ 
 return sum.apply(this, [num1, num2]); // 传入数组
} 
alert(callSum1(10,10)); //20 
alert(callSum2(10,10)); //20

在使用call()方法时,传递给函数的参数必须逐个列举出来。

function sum(num1, num2){ 
 return num1 + num2; 
} 
function callSum(num1, num2){ 
 return sum.call(this, num1, num2); 
} 
alert(callSum(10,10)); //20

传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域

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)时,函数的执行环境就不一样了,因为此时函数体内的 this 对象指向了 o
sayColor.call(o); //blue

bind()方法会创建一个函数的实例,其 this 值会被绑定到传给 bind()函数的值。

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){ 
 alert(this.color); 
} 
var objectSayColor = sayColor.bind(o); 
objectSayColor(); //blue

5.6 基本包装类型

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

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

所有基本包装类型的对象都会被转换为布尔值 true

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

var value = "25"; 
var number = Number(value); //转型函数
alert(typeof number); //"number" 
var obj = new Number(value); //构造函数
alert(typeof obj); //"object"

5.6.1 Boolean类型

我们的建议是永远不要使用 Boolean 对象

5.6.2 Number类型

Number 类型还提供了一些用于将数值格式化为字符串的方法

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

var num = 10.005; 
alert(num.toFixed(2)); //"10.01"

toExponential()用于格式化数值,接收一个参数,而且该参数同样也是指定输出结果中的小数位数

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

如果你想得到表示某个数值的最合适的格式,就应该使用 toPrecision()方法。

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

5.6.3 String类型

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

1. 字符方法

charAt()方法以单字符字符串的形式返回给定位置的那个字符

var stringValue = "hello world"; 
alert(stringValue.charAt(1)); //"e"

如果你想得到的不是字符而是字符编码,那么就要像下面这样使用 charCodeAt()

var stringValue = "hello world"; 
alert(stringValue.charCodeAt(1)); //输出"101"

可以使用方括号加数字索引来访问字符串中的特定字符,

var stringValue = "hello world"; 
alert(stringValue[1]); //"e"

2. 字符串操作方法

concat()用于将一或多个字符串拼接起来,返回拼接得到的新字符串

var stringValue = "hello "; 
var result = stringValue.concat("world"); 
alert(result); //"hello world" 
alert(stringValue); //"hello"

var result = stringValue.concat("world", "!"); 
alert(result); //"hello world!"

虽然 concat()是专门用来拼接字符串的方法,但实践中使用更多的还是加号操作符(+)

与concat()方法一样,slice()、substr()和 substring()也不会修改字符串本身的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。

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" 
alert(stringValue.substr(3, 7)); //"lo worl"

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

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)); //""(空字符串)

3.字符串位置方法

indexOf()和 lastIndexOf()。这两个方法都是从一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)。这两个方法的区别在于: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

4. trim()方法

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

var stringValue = " hello world "; 
var trimmedStringValue = stringValue.trim(); 
alert(stringValue); //" hello world " 
alert(trimmedStringValue); //"hello world"

5. 字符串大小写转换方法

toLowerCase()、toLocaleLowerCase()、toUpperCase()和 toLocaleUpperCase()

6. 字符串的模式匹配方法

第一个方法就是 match(),在字符串上调用这个方法,本质上与调用 RegExp 的 exec()方法相同。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()。这个方法的唯一参数与 match()方法的参数相同:由字符串或 RegExp 对象指定的一个正则表达式。search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。而且,search()方法始终是从字符串开头向后查找模式。

var text = "cat, bat, sat, fat"; 
var pos = text.search(/at/); 
alert(pos); //1

为了简化替换子字符串的操作,ECMAScript 提供了 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"

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(/[^\,]+/); //["", ",", ",", ",", ""] 

7. localeCompare()方法

这个方法比较两个字符串,并返回下列值中的一个:

 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定);

 如果字符串等于字符串参数,则返回 0;

 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是 1,具体的值同样要视实现而定)。

var stringValue = "yellow"; 
alert(stringValue.localeCompare("brick")); //1 
alert(stringValue.localeCompare("yellow")); //0 
alert(stringValue.localeCompare("zoo")); //-1

8. fromCharCode()方法

这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。

9. HTML方法

5.7 单体内置对象

5.7.1 Global对象

1. URI编码方法

Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如空格。而这两个 URI 编码方法就可以对 URI 进行编码,它们用特殊的 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。

encodeURI()不会对本身属于 URI 的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而

encodeURIComponent()则会对它发现的任何非标准字符进行编码。

2. eval()方法

eval()方法就像是一个完整的 ECMAScript 解析器,它只接受一个参数,即要执行的 ECMAScript(或 JavaScript)字符串。

eval("alert('hi')"); 
这行代码的作用等价于下面这行代码:
alert("hi");

在 eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,它们被包含在一个字符串中;它们只在 eval()执行的时候创建。

3. Global对象的属性

特殊的值undefined、NaN 以及 Infinity 都是 Global 对象的属性。此外,所有原生引用类型的构造函数,像Object 和 Function,也都是 Global 对象的属性。

4. window对象

在全局作用域中声明的所有变量和函数,就都成为了 window对象的属性。

var color = "red"; 
function sayColor(){ 
 alert(window.color); 
} 
window.sayColor(); //"red"

这里定义了一个名为color的全局变量和一个名为sayColor()的全局函数。在sayColor()内部,我们通过 window.color 来访问 color 变量,以说明全局变量是 window 对象的属性。然后,又使用window.sayColor()来直接通过 window 对象调用这个函数,结果显示在了警告框中。

5.7.2 Math对象

1. Math 对象的属性

2. min()和 max()方法

要找到数组中的最大或最小值,可以像下面这样使用 apply()方法。

var values = [1, 2, 3, 4, 5, 6, 7, 8]; 
var max = Math.max.apply(Math, values);

3. 舍入方法

 Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;

 Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;

 Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数(这也是我们在数学课上学到的舍入规则)。

alert(Math.ceil(25.9)); //26 
alert(Math.ceil(25.5)); //26 
alert(Math.ceil(25.1)); //26 

alert(Math.round(25.9)); //26 
alert(Math.round(25.5)); //26 
alert(Math.round(25.1)); //25 
 
alert(Math.floor(25.9)); //25 
alert(Math.floor(25.5)); //25 
alert(Math.floor(25.1)); //25

4. random()方法

Math.random()方法返回大于等于 0 小于 1 的一个随机数。

5.8 小结

对象在 JavaScript 中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,现简要总结如下:

 引用类型与传统面向对象程序设计中的类相似,但实现不同;

 Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为;

 Array 类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;

 Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;

 RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。

函数实际上是 Function 类型的实例,因此函数也是对象;而这一点正是 JavaScript 最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当作对象来访问。三种基本包装类型分别是:Boolean、Number 和 String。以下是它们共同的特征:

 每个包装类型都映射到同名的基本类型;

 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;

 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。

在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和 Math。在大多数 ECMAScript实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变量和函数都是 Global 对象的属性。Math 对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值