第五章=》引用类型
第五章 引用类型
引用类型的值(对象)是引用类型的一个实例。在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起。引用类型有时候也被称为对象定义,因为他们描述的是一类对象所具有的属性和方法。
5.1 Object类型
5.1.1创建Object实例的方式有两种
a.使用new操作符后跟Object构造函数
var person = new Object();
b.对象字面量表示法
var person = { name:”111”,age:22 };
在通过对象字面量定义对象时,实际上不会调用Object构造函数。
对象字面量也是向函数传递大量可选参数的首选方式。
5.1.2 访问对象属性
a.使用点表示法访问对象属性,这也是很多面向对象语言中通用的方法。
b.使用方括号表示法来访问对象的属性。在使用方括号语法时,应该将要访问的属性以字符串的形式放在方括号中。
c.方括号语法的优点:可以通过变量来访问属性,(比如for循环时的arr[i])
5.2 Array类型
ECMAScript数组的每一项可以保存任何类型的数据。
5.2.1 创建数组的基本方式
a.使用Array构造函数
var colors = new Array();
如果预先知道数组要保存的项目数量,可以给构造函数传递该数量,而该数量会自动变成length属性的值。也可以向Array构造函数传递数组中应该包含的项。
当然,给构造函数传递一个值也可以创建数组
b. 使用数组字面量表示法创建数组
数组字面量由一对数组项的方括号表示,多个数组项之间以逗号隔开
5.2.2读取数组每一项的值
在读取和设置数组的值时,要使用方括号并提供相应值的基于0的数字索引。
利用length属性也可以方便地在数组末尾添加新项
5.2.3 检测数组
instanceof 操作符问题在于,它假定单一的全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
为了解决这个问题,ECMAScript5 新增了Array.isArray()方法。这个方法的目的是最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的。
5.2.4 转换方法
toString():会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。
valueOf():返回的还是数组
*/ alert()要接收字符串参数,所以它会在后台调用toString()方法 /*
toLocaleString(): 会返回一个数组值的以逗号分隔的字符串。调用每一项的toLocaleString()方法。
join() :可以使用不同的分隔符来构建这个字符串。join()方法只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串。
5.2.3 栈方法
后进先出
push(): 可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
pop(): 从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
5.2.4 队列方法
先进先出
push()
shift():移出数组中的第一个项并返回该项,同时数组长度减1。
unshift():在数组前端添加任意个项,并返回新数组的长度。
5.2.5 重排序方法
reverse(): 反转数组项的顺序
sort():方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。为了实现排序,sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,以确定如何排序。即使数组中的每一项都是数值,sort()方法比较的也是字符串。
sort()方法可以接收一个比较函数作为参数,以便我们制定哪个值位于前面。
reverse()和sort()方法的返回值是经过排序之后的数组。
5.2.6 操作方法
concat():可以基于当前数组中的所有项创建一个新数组。具体来说,这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。
slice():接收一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项,如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。
splice():主要用途是向数组中部插入项。
删除:只需指定2个参数:要删除的第一项的位置和要删除的项数
例如,splice(0,2)会删除数组中的前两项。
插入/替换:可以向指定位置插入任意数量的项,需提供三个(或更多)参数
第一个参数=》起始位置,第二个参数=》要删除的项数(0,即是不删除,出入若干项),之后的参数=》要插入的若干项。
5.2.7 位置方法
indexOf()与lastIndexOf():接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中,indexOf()方法从数组的开头(位置0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回-1。
5.2.8 迭代方法
ECMAScript为数组定义了5个迭代方法。每个方法都接收两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象——影响this的值。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。根据使用方法的不同,这个函数执行后的返回值可能会也可能不会影响访问的返回值。
every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
forEach(): 对数组中每一项运行给定函数。这个方法没有返回值。
map(): 对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
some(): 对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
5.2.9 缩小方法
reduce()与reduceRight(): 这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。其中,reduce()方法从数组的第一项开始,逐个遍历到最后。而reduceRight()则从数组的最后一项开始,向前遍历到第一项。
这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)作为缩小基础的初始值。传给reduce()和reduceRight()的函数接收四个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。
5.3 Date类型
创建一个日期对象
var now = new Date();
在调用Date构造函数而不传递参数的情况下,新创建的对象自动获得当前日期和时间。如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数(即从UTC时间1970年1月1日午夜起至该日期止经过的毫秒数)。为了简化这一计算过程,ECMAScript提供了两个方法:Date.parse()和Date.UTC()。
Date.parse():接受一个标示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数。ECMA-262没有定义Date.parse()应该支持哪种日期格式,因此这个方法的行为因实现而异,而且通常是因地区而异。通常接受下列日期格式:
“月/日/年”, 如6/13/2004;
“英文月 日,年”如 January 12,2004;
ISO 8601扩展格式YYYY-MM-DDTHH:mm:ss (例如 2004-05-25T00:00:00)。这有兼容ECMAScript 5 的实现支持这种格式。
如果传入Date.parse()方法的字符串不能表示日期,那么它会返回NaN。实际上,如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse()。
Date.UTC()方法同样也返回表示日期的毫秒数,但它与Date.parse()再构建值时使用不同的信息。Date.UTC()的参数分别是年份,基于0的月份(一月是0)、月中的哪一天(1到31)、小时数(0到23)、分钟、秒以及毫秒数。在这些参数中,只有前年是必须的(年也不写会返回NaN)。如果没有提供月中天数为1;如果省略其他参数,则统统假设为0。
ECMAScript 5 添加了Date.now()方法,返回表示调用这个方法时的日期和时间的毫秒数。
5.3.1 继承的方法
Date类型重写了toLocaleString()、toString()和valueOf()方法;
toLocaleString(): 按照与浏览器设置的地区相适应的格式返日期和时间。这大致意味着时间格式中会包含AM或PM,但不会包含时区信息。
toString(): 通常返回带有时区信息的日期和时间,其中时间一般以军用时间表示
valueOf(): 返回日期的毫秒表示。因此,可以方便实用比较操作符(小于或大于)来比较日期值。
5.3.2 日期格式化方法
Date类型还有一些专门用于将日期格式化为字符串的方法
toDateString()——以特定于实现的格式显示星期几、月、日和年;toTimeString()——以特定于实现的格式显示时、分、秒和时区;toLocaleDateString()——以特定于地区的格式显示星期几、月、日和年;toLocaleTimeString()——以特定于地区的格式显示时、分、秒和时区;
toUTCString()——以特定于实现的格式显示完整的UTC日期。
5.3.3 众多的日期/时间组件方法(随用随查)
5.4 RegExp 类型
ECMAScript通过RegExp类型来支持正则表达式。
var expression = /pattern/flags;
其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符串、限定符、分组、向前查找以及反向引用。每个正则表达式都可带有一或多个标志(flags),用来标明正则表达式的行为。
5.4.1 正则表达式的匹配模式支持下列3个标志
g: 表示全局(global)模式。即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止。
i: 表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m: 表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在于模式匹配的项。
5.4.2 模式中使用的所有元字符都必须转义
( , ) , [ , ] , { , } , \ , ^ , $ , | , ? , * , + , .
这些元字符在正则表达式都有一或多种特殊用途,因此如果想要匹配字符串中包含的这些字符,就必须对它们进行转义。
5.4.3 以字面量形式来定义的正则表达式
5.4.4 使用RegExp构造函数
它接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串。
传递给RegExp构造函数的两个参数都是字符串(不能把正则表达式字面量传递给RegExp构造函数)。由于RegExp构造函数的模式参数都是字符串,所以在某些情况下要对字符进行双重转义。那些已经转义过的字符也是如此,例如:字符\在字符串中通常被转义为\\,而在正则表达式字符串中就会变成\\\\。
5.4.5 RegExp实例属性
global: 布尔值,表示是否设置了g标志。
ignoreCase: 布尔值,表示是否设置了i标志。
lastIndex: 整数,表示开始搜索下一个匹配项的字符位置,从0算起。
multiline: 布尔值,表示是否设置了m标志。
source: 正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
5.4.6 RegExp 实例方法
exec(): 专门为捕获组而设计的,接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。返回的数组虽然是Array的实例,但包含两个额外的属性:index和input其中,index表示匹配项在字符串中的位置,而input表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。
对于exec()方法而言,即使在模式中设置了全局标志(g),它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配项。
第一个模式pattern1不是全局模式,因此每次调用exec()返回的都是第一个匹配项(”cat”)。而第二个模式pattern2是全局模式,因此每次调用exec()都会返回字符串中的下一个匹配项,直至搜索到字符串末尾为止。此外,还应该注意模式的lastIndex属性的变化情况。在全局匹配模式下,lastIndex的值每次调用exec()后都会增加,而在非全局模式下始终保持不变。
正则表达式的第二个方式是test(),它接受一个字符串参数。在模式与该参数匹配的情况下返回true;否则,返回false。在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,使用这个方法非常方便。因此,test()方法经常被用在if语句中。
5.4.7 RegExp构造函数属性
RegExp构造函数包含一些属性。这些属性适用于作用域中的所有正则表达式,并且基于所执行的最近一次正则表达式操作而变化。关于这些属性的另一个独特之处,就是可以通过两种方式访问它们。换句话说,这些属性分别有一个长属性名和一个短属性名。
长属性名 |
短属性名 |
说明 |
input |
$_ |
最近一次要匹配的字符串。 |
lastMatch |
$& |
最近一次的匹配项 |
lastParen |
$+ |
最近一次匹配的捕获组 |
leftContext |
$` |
Input字符串中lastMatch之前的文本 |
multiline |
$* |
布尔值,表示是否所有表达式都使用多行模式 |
rightContext |
$’ |
Input字符串中lastMatch之后的文本 |
使用这些属性可以从exec()或test()执行的操作中提取出更具体的信息。
5.5 Function类型
函数实际上是对象。每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是使用函数声明语法定义的。
5.5.1 没有重载
如果在ECMAScript中定义了两个名字相同的函数,则该名字只属于后定义的函数。
5.5.2 函数声明与函数表达式
解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
5.5.3 作为值的函数
因为ECMAScript中的函数名本身就是变量,所以函数也可以作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
可以从一个函数中返回另一个函数,而且这也是极为有用的一种技术。假设有一个对象数组,我们想要根据某个对象属性对数组进行排序。而传递给数组sort()方法的比较函数要接收两个参数,即要比较的值。可是,我们需要一种方式来指明按照那个属性来排序。要解决这个问题,可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数。
5.5.4 函数内部属性
在函数内部,有两个特殊的对象:arguments和this。
arguments的主要用途是保存函数参数,这个对象还有一个名叫callee的属性,
该属性是一个指针,指向拥有这个arguments对象的函数。
函数内部的另一个特殊对象是this,this引用的是函数据以执行的环境对象——或者也可以说是this值(当在网页的全局作用域中调用函数时,this对象引用的就是window)。
5.5.5 函数属性和方法
每个函数都包含两个属性: length和prototype。
length属性表示函数希望接收的命名参数的个数。
对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都保存在prototype名下。在ECMAScript5中,prototype属性是不可枚举的,因此使用for-in无法发现。
每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先,apply()方法接收两个参数:一个是其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array的实例,也可以是arguments对象。
call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于call()方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。
apply()和call()真正的用武之地在于能够扩充函数赖以运行的作用域。
bind():这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
函数继承的toLocaleString()和toString()方法始终都返回函数的代码。
5.6 基本包装类型
3个特殊的引用类型: Boolean、Number和String。(实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据)
5.6.1 Boolean类型
要创建Boolean对象,可以调用Boolean构造函数并传入true或false值。
5.6.2 Number类型
要创建Number对象,可以在调用Number构造函数时向其中传递相应的数值。
toFixed():按照指定的小数位(参数)返回数值的字符串表示,自动四舍五入。
toExponential(): 该方法返回以指数表示法(也称e表示法)表示的数值的字符串形式。
5.6.3 String类型
要创建String对象,可以在调用String构造函数时向其中传递相应的字符串。
String对象的方法也可以在所有基本的字符串值中访问到。其中,继承的valueOf()、toLocaleString()和toString()方法,都返回对象所表示的基本字符串值。
String类型的每个实例都有一个length属性,表示字符串中包含多个字符。
a. 字符方法
charAt():接收一个参数,基于0的字符位置,以单字符串的形式返回给定位置的那个字符。
charCodeAt():接收一个参数,基于0的字符位置,返回字符的字符编码。
b. 字符串操作方法
concat(): 用于将一或多个字符串拼接起来,但会拼接的得到的新字符串。
ECMAScript还提供了三个基于子字符串创建字符串的方法:slice()、substr()和substring()。这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的情况下)表示子字符串到哪里结束。具体来说,slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而substr()的第二个参数指定的则是返回的字符个数。如果没有给这些方法传递第二个参数,则将字符串的长度作为结束位置。与concat()方法一样。slice()、substr()和substring()也不会修改字符串本身的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。
c.字符串位置方法
有两个可以从字符串中查找字符串的方法:indexOf()和lastIndexOf()。这两个方法都是从一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该字符串,则返回-1)。
indexOf():从字符串的开头向后搜索子字符串。
lastIndexOf():从字符串的末尾向前搜索子字符串。
这两个方法都可以接收可选的第二个参数,表示从字符串中那个位置开始搜索。
在使用第二个参数的情况下,可以通过循环调用indexOf()或lastIndexOf()来找到所有匹配的子字符串。
d. trim()方法
这个方法会创建一个字符串的副本,删除前置及后缀的所有空格。
e.字符串大小写转换方法
toLowerCase():转换为大写
toLocaleLowerCase():转换为大写,针对特定地区的实现
toUpperCase():转换为小写
toLocaleUpperCase():转换为小写,针对特定地区的实现
f. 字符串的模式匹配方法
match(): 在字符串上调用这个方法,本质上与调用RegExp的exec()方法相同。
match()方法只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象。
search(): 这个方法的唯一参数与match()方法的参数相同:由字符串或RegExp对象指定的一个正则表达式。search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。
replace():这个方法接受两个参数:第一个参数可以是一个RegExp对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要制定全局(g)标志。
split(): 这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。split()方法可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。
localeCompare():这个方法比较两个字符串,并返回比较结果
如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1)。
如果字符串等于字符串参数,则返回0;
如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是1.)
formCharCode():这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。
5.7 单体内置对象
ECMA-262对内置对象的定义是: “由ECMAScript实现提供的、不依赖与宿主环境的对象,这些对象在ECMAScirpt程序执行之前就已经存在了。”意思就是说,开发人员不必显式地实例化内置对象,因为它们已经实例化了。ECMA-262顶一个了两个单体内置对象:Global和Math。
5.7.1 Global对象
Global(全局)对象可以说是ECMAScript中最特别的一个对象了。Global对象在某种意义上是作为一个终极的“兜底儿对象”来定义的。换句话说不属于任何其他对象的属性和方法,最终都是它的属性和方法。事实上,没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性。诸如isNaN()、isFinite()、parseInt()以及parseFloat(),实际上全都是Global对象的方法。除此之外Global对象还包含其他一些方法。
a.URI编码方法
Global对象的encodeURI()和encodeURIComponent()可以对URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的URI中不能包含某些字符,例如空格。而这两个URI编码方法就可以对URI进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接受和理解。
使用encodeURI()编码后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了%20。而encodeURIComponent()方法则会使用对应的编码替换所有非字母数字字符。
一般来说,我们使用encodeURIComponent()方法的时候要比使用encodeURI()更多,因为在实践中更常见的是对查询字符串参数而不是对基础URI进行编码。
与encodeURI()和encodeURIComponent()方法对应的两个方法分别是decodeURI()和decodeURIComponent()。
b.eval()方法
eval()方法就像是一个完整的ECMAScript解析器,它只接受一个参数,即要执行的ECMAScript字符串。当解析器发现代码中调用eval()方法时,它会将传入的参数当做实际的ECMAScript语句来解析,然后把执行结果插入到原位置。通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链。
3.Global对象的属性
特殊的值undefined、NaN、Infinity都是Global对象的属性。所有原生引用类型的构造函数,像Object和Function,也都是Global对象的属性。
ECMAScript5 明确禁止给undefined、NaN和Infinity赋值,这样做即使在非严格模式下也会导致错误。
4.window对象
在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。
5.7.2 Math对象
a. min()/max()
min()/max():: 确定一组数值中的最小值和最大值。这两个方法都可以接收任意多个数值参数。
要找到数组中的最大或最小值,可以像下面这样使用apply()方法。
这个技巧的关键是把Math对象作为apply()的第一个参数,从而正确地设置this值。然后,可以将任何数组作为第二个参数。
b. 舍入方法
Math.ceil():执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor():执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round():执行标准摄入,即它总是将数值四舍五入为最接近的整数。
Math.random()方法
Math.random():方法返回介于0和1之间的随机数不包括0和1。
5.8 小结
Object是一个基础类型,其他所有类型都从Object继承了基本的行为;
Array类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;
Date类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
RegExp类型是ECMAScript支持正则表达式的一个接口;
函数实际上是Function类型的实例,因此函数也是对象;而这一点正是JS最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。
因为有了基本包装类型,所以JS中的基本类型值可以被当作对象来访问。三种基本包装类型分别是:Boolean、Number和String。
每个包装类型都映射到同名的基本类型;
在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。
在所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。