第5章引用类型

时间:2021-11-25 16:14:28

5.1 Object类型

创建Object实例的方式有两种。第一种是使用new操作符后跟Object构造函数,另一种方式是使用对象字面量表示法。

 

在通过对象字面量定义对象时,实际上不会调用Object构造函数

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

 

方括号表示法的优点是可以通过变量来访问属性。

5.2 Array类型

ECMAScript数组的每一项可以保存任何类型的数据,并它的大小是可以动态调整的

使用Array构造函数

给构造函数传的值是数值,则会按照该数值创建包含给定项数的数组;

如果传递的是其他类型的参数,则会创建包含那个值得只有一项的数组;

使用数组字面量表示法

数组的length属性不是只读的,通过设置这个属性可以从数组的末尾移除项或向数组中添加新项。如果将其length属性设置为大于数组项数的值,则新增的每一项都会取得undefined值。

5.2.1检测数组

instanceof :value instanceof Array;它的问题在于它假定只有一个全局执行环境

ES5新增了一个Array.isArray()方法

constructor属性:arr.constructor;

5.2.2转换数组

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

valueOf():返回的还是数组;

join():只接受一个参数,即用作分隔符的字符串,如果不给join()方法传入任何值,或者给它传入undefined,则使用逗号作为分隔符;

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

5.2.3栈方法

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

pop():这个方法从数组末尾移除最后一项,减少数组的length值,然后返回溢出的项;

5.2.4队列方法

shift():这个操作能够移除数组中的第一项并返回该项;

unshift():它能在数组前端添加任意个项并返回新数组的长度;

5.2.5重排序方法

reverse():这个方法会反转数组项的顺序;

sort():这个方法会调用每个数组项的toString()转型方法,然后比较得到的字符串对应的ASCII值,以确定如何排序,即使每一项都是数值;

sort()方法还可以接收一个比较函数作为参数。这个比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回0,如果第一个参数应该位于第二个之后则返回一个整数;

reverse()和sort()方法的返回值是经过排序后的数组

5.2.6操作方法

concat():这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,然后返回新构建的数组。

在没有给concat()方法传递参数的情况下,它只是复制当前数组并返回副本。

如果传递给concat()方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。

如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾

这个方法不会影响原数组

slice():这个方法可以接收一或两个参数,即要返回项的起始和结束位置。

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

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

这个方法不会影响原数组

splice():这个方法算是最强大的数组方法,主要用途是向数组的中部插入项。这个方法会影响原数组,它始终都会返回一个数组,该数组中包含从原始数组中删除的项

删除:可以删除任意数量的项,只需指定2个参数:要删除的第一项的位置和要删除的项数;

插入:可以向指定位置插入任意数量的项,只需提供3个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项;

替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项不必与删除的项相等;

5.2.7位置方法

ES5为数组实例添加了两个位置方法:indexOf()和lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选)表示查找起点位置的索引。其中indexOf()方法从数组的开头(位置0)开始查找,lastIndexOf()方法则从数组的末尾开始向前查找。

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

5.2.8迭代方法

ES5为数组定义了5个迭代方法。每个方法都接受两个参数:要在每一项上运行的函数和(可选)运行该函数的作用域对象--影响this的值。传入这些方法中的函数会接收三个参数:数组项的值(item)、该项在数组中的位置(index)、和数组本身对象(array),以下方法都不会修改数组中的包含的值。

 

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

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

forEach():对数组中的每一项运行给定的函数。这个方法没有返回值,本质上和for循环一样;

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

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

5.2.9缩小方法

ES5新增了两个归并数组的方法:reduce()和reduceRight()。这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。其中,reduce()方法从数组的第一项开始,逐个遍历到最后。而reduceRight()则从数组的最后一项开始,向前遍历到第一项。

这两个方法都接收两个参数:一个在每一项上调用的函数和(可选)作为归并基础的初始值。

传入给reduce()和reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象。

5.3 Date类型

要创建一个日期对象,使用new操作符和Date构造函数即可;

Date.parse()方法接受一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数,如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse();

Date类型也重写了toLocaleString()、toString()和valueOf()方法:

toLocaleString()会按照与浏览器设置的地区相适应的格式返回日期和时间;

toString()方法则通常返回带有时区信息的日期和时间;

valueof()方法根本不返回字符串,而是返回日期的毫秒表示;

5.4 RegExp类型

ECMAScript通过RegExp类型来支持正则表达式。每个正则表达式都可带有一个或多个标志,用以表明正则表达式的行为:

g:表示全局模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;

i:表示不区分大小写模式,即在确定匹配项时忽略模式与字符串的大小写;

m:表示多行模式,即在到达一行文本末尾时还会继续查找下一行中是否存在于模式匹配的项

模式中所有的元字符都必须转义:( [ ^ $ | ) ? * + . ] } )

可以使用RegExp构造函数,它接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串;

RegExp对象的主要方法是exec(),该方法专门为捕获组而设计的

exec()接收一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项信息的情况下返回null;

返回的数组虽然是Array实例,但也包含两个额外的属性:index和input。其中,index表示匹配项在字符串中的位置,而input表示应用正则表达式的字符串;

在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项);

即使在模式中设置了全局标志g,它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配项。

正则表达式的第二个方法是test(),它接收一个字符串参数。在模式与该参数匹配的情况下返回true;否则返回false。它经常被用于if语句中

5.5 Function类型

函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

 

函数定义

函数通常是使用函数声明语法定义的:

 

function sum(num1,num2){

    return num1 + num2;

}

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

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

 

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

从技术角度讲,这是一个函数表达式。但是,不推荐使用这种方式来定义函数,因为这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。

 

注:使用不带圆括号的函数名是访问函数指针,而非调用函数

因为ECMAScript中的函数名本身就是变量,所以函数也可以作为值来使用。

函数内部属性

在函数内部,有两个特殊的对象:arguments和this。其中arguments是一个类数组对象,包含着传入函数中的所有参数。this引用的是函数据以执行的环境对象--或者也可以说是this值(当在网页的全局作用域中调用函数时,this对象引用的就是window)

 

callee

 

虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数

 

function rec(num){

    if(num<=1){

        return 1;

    }else{

        return num * arguments.callee(num-1)

    }

}

当函数在严格模式下运行时,访问arguments.callee会导致错误

caller

 

这个属性中保存着调用当前函数的函数的引用,如果实在全局作用域中调用当前函数,它的值为null。

 

在严格模式下访问arguments.caller属性也会导致错误,而在非严格模式下这个属性始终是undefined

严格模式下不能为函数的caller属性赋值,否则会导致错误

函数的属性和方法

ECMAScript中的函数是对象,因此函数也有属性和方法

 

属性

 

每个函数都包含两个属性:length和prototype

 

length属性表示函数希望接收的命名参数的个数;

prototype是保存它们所有实例方法的真正所在。prototype属性是不可枚举的,因此使用for-in无法实现;

方法

 

每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

 

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

call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同,传递给函数的参数必须逐个列举出来;

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

call()和apply()真正强大的地方是能够扩充函数赖以运行的作用域,最大的好处就是对象不需要与方法有任何耦合关系。

5.6基本包装类型

每当读取一个基本类型值得时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。

 

引用类型和基本包装类型的主要区别就是对象的生存期。

使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中;

自动创建的基本包装类型的对象,只存在于一行代码的执行瞬间,然后立即被销毁,这意味着我们不能在运行的时候为基本类型值添加属性和方法;

可以显式的调用Boolean、Number和String来创建基本包装类型的对象

这种做法很容易分不清处理基本类型还是引用类型。对基本包装类型的实例调用typeof会返回"object",而且所有基本包装类型的对象都会被转换为布尔值true;

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

Boolean类型

Boolean类型的实例重写了valueOf()方法,返回基本类型值true或false;重写了toString()方法,返回字符串"true"和"false";

使用instanceof()操作符测试Boolean对象会返回true;

布尔表达式中的所有对象都会被转换为true;

建议永远都不要使用Boolean对象

Number类型

valueOf():返回对象表示的基本类型的数值;

toString():返回字符串形式的数值,可以为其传递一个表示基数的参数,告诉它返回几进制数值的字符串形式;

toFixed():会按照指定的小数位返回数值的字符串表示,这个方法很适合处理货币值;

toExponential():该方法返回以指数表示法(也称e表示法)表示的数值的字符串形式;

toPrecision():这个方法会根据要处理的数值决定到底是调用toFixed()还是toExponential(),这三个方法都可以通过向上向下舍入,做到以最准确的形式来表示带有正确小数位的值。这个方法接收一个参数,即表示数值的所有数字的位数(不包括指数部分)

String类型

String类型的每一个实例都有一个length属性,表示字符串中包含多少个字符。即使字符串中包含双字节字符(不是占一个字节的ASCII字符),每个字符也仍然算一个字符。

 

字符方法

 

两个用于访问字符串中特定字符的方法是:charAt()和charCodeAt()。这两个方法都接收一个参数,即基于0的字符位置

 

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

charCodeAt():这个方法以字符编码的形式返回给定位置的那个字符;

ES5中还定义了,可以使用方括号加数字索引([1])来访问字符串中特定位置;

字符串操作方法

 

concat():用于将一个或多个字符串拼接起来,返回拼接得到的新字符串,它不会影响原字符串;

ES还提供了3个基于子字符串创建新字符串的方法:slice()、substr()和substring()。

这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数,第一个参数指定字符串的开始位置;

slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置;

substr()的第二个参数指定的是返回的字符个数;

这三个方法都不会影响原字符串

在给这些方法传递负值的情况下,slice()方法会将传入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串的长度,而将第二个参数转换为0,substring()方法会把所有负值参数都转换为0;

字符串位置方法

 

有两个可以从字符串中查找子字符串的方法:indexOf()和lastIndexOf()。这两个方法都是从一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)

 

indexOf()方法从字符串的开头向后搜索子字符串,而lastIndexOf()方法是从字符串的末尾向前搜索子字符串;

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

trim()

 

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

由于trim()返回的是字符串的副本,所以不影响原始字符串

 

字符串大小写转换方法

 

ECMAScript设计大小写转换的方法有四个toLowerCase、toLocaleLowerCase()、toUpperCase()和toLacleUpperCase()。其中toLowerCase和toUpperCase()是两个经典方法,而toLocaleLowerCase()和toLacleUpperCase()方法则是针对特定地区的实现。

字符串的模式匹配方法

 

match():在字符串上调用这个方法本质上与调用RegExp的exec()的方法相同。它只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象;

search():这个方法的唯一参数与match()方法的参数相同。这个方法返回字符串中第一个匹配项的索引,如果没有找到匹配项则返回-1,而且search()方法始终是从字符串开通向后查找模式;

replace():这个方法接收两个参数,第一个参数可以是一个RegExp对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数可以是一个字符串或者一个函数。

如果第一个参数是字符串,那么只会替换第一个子字符串,想要替换所有的子字符串唯一的方法就是提供一个正则表达式,而且要指定全局(g)标志;

这个方法的第二个参数也可以使一个函数。在只有一个匹配项的情况下,会向这个函数传递3个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串;

这个方法不会影响原字符串;

split():这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中,分隔符可以是字符串,也可以是一个RegExp对象。split()方法可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。

localeCompare()

 

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

 

如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多情况下是-1);

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

如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多情况下是1);

formCharCode()

 

String构造函数本身还有一个静态方法:fromCharCode()。这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。

5.7单体内置对象

由ECMAScript实现提供的,不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了

 

Global对象

所有在全局作用域中定义的属性和函数,都是Global对象的属性。

 

URI编码

 

Global对象的encodeURI()和encodeURIComponent()方法可以对URI进行编码,以便发送给浏览器

 

encodeURI()主要用于整个URI,而encodeURIComponent()主要用于对URI中的某一段进行编码;

它们的主要区别在于,encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码;

decodeURI()只能对使用encodeURI()替换的字符进行解码,同样的decodeURIComponent()能够解码使用encodeURIComponent()编码的所有字符,即它可以解码任何特殊字符的编码;

eval()方法

 

这个方法就像一个完整的ECMAScript解析器。

 

它只接收一个参数,即要执行的ECMAScript字符串;

通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链;

在eval()中创建的任何变量都不会被提升

严格模式下,在外部访问不到eval()中创建的任何变量或函数

Global对象的属性

特殊的值undefined、NaN以及Infinity都是Global对象的属性;

所有原生引用类型的构造函数,也都是Global对象的属性;

ES5明确禁止给undefined、NaN和Infinity赋值,这样做即使在非严格模式下也会导致错误;

window对象

 

Web浏览器将这个全局对象作为window对象的一部分加以实现。在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。

 

在没有给函数明确指定this值的情况下,this值等于Global对象

Math对象

ECMAScript还为保存数学公式和信息提供了一个公共位置,即Math对象

 

min()和max()

 

这两个方法用于确定一组数值中的最小值和最大值。这两个方法都可以接受人一多个数值参数;

 

要找到数组中的最大最小值,可以使用:Math.max.apply(Math,arr)

舍入方法

 

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

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

Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数;

random()方法

 

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

 

可以利用这个方法从某个整数范围内随机选择一个值

值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)