1、虽然ECMAScript数组与其他语言中的数组都是数据的有序列表,但与其他语言不同的是,ECMAScript数组的每一项可以保存任何类型的数据。也就是说,可以用数组的第一个位置来保存字符串,用第二位置来保存数值,用第三个位置来保存对象,以此类推。而且,ECMAScript数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新增数据。
2、ECMAScript5新增了Array.isArray()方法。这个方法的目的是最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的。支持Array.isArray()方法的浏览器有IE9+、Firefox4+、Safari5+、Opear10.5+和Chrome。
3、所有对象都具有toLocaleString()、toString()和valueOf()方法。其中,调用数组的toString()方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。而调用valueOf()返回的还是数组。
另外,toLocaleString()方法经常也会返回与toString()和valueOf()方法相同的值,但也不总是如此。当调用数组的toLocaleString()方法时,它也会创建一个数组值的以逗号分隔的字符串。而与前两个方法唯一的不同之处在于,这一次为了取得每一项的值,调用的是每一项的toLocaleString()方法,而不是toString()方法。
4、数组继承的toLocaleString()、toString()和valueOf()方法,在默认情况下都会以逗号分隔的字符串的形式返回数组项。而如果使用join()方法,则可以使用不同的分隔符来构建这个字符串。join()方法只接收一个参数,即用作分隔符的字符串,然后返回包含所有数组项的字符串。如果不给join()方法传入任何值,或者给它传入undefined,则使用逗号作为分隔符。
如果数组中的某一项的值是null或者undefined,那么该值在join()、toLocaleString()、toString()和valueOf()方法返回的结果中以空字符串表示。
5、ECMAScript数组也提供了一种让数组的行为类似于其他数据结构的方法。具体来说,数组可以表现得就像栈一样,后者是一种可以限制插入和删除项的数据结构。栈是一种LIFO(Last-IN-First-Out,后进先出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入和移除,只发生在一个位置——栈的顶部。ECMAScript为数组专门提供了push()和pop()方法,以便实现类似栈的行为。
push()方法可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后的数组长度。而pop()方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
6、栈数据结构的访问规则是LIFO(后进先出),而队列数据结构的访问规则是FIFO(First-In-First-Out,先进先出)。队列在列表的末端添加项,从列表的前端移除项。由于push()是向数组末端添加项的方法,因此要模拟队列只需一个从数组前端取得项的方法。实现这一操作的方法就是shift(),它能够移除数组中的第一个项并返回该项,同时将数组长度减1。结合使用shift()和push()方法,可以像使用队列一样使用数组。
ECMAScript还为数组提供了一个unshift()方法。顾名思义,unshift()与shift()的用途相反:它能在数组前端添加任意个项并返回新数组的长度。因此,同时使用unshift()和pop()方法,可以从相反的方向来模拟队列,即在数组的前端添加项,从数组的末端移除项。
7、如果slice()方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置。例如,在一个包含5项的数组上调用slice(-2,-1)与调用slice(3,4)得到的结果相同。如果结束位置小于起始位置,则返回空数组。
8、splice()的主要用途是向数组的中部插入项,但使用这种方法的方式则有如下3种。
删除:可以删除任意数量的项,只需指定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()方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组)。
9、ECMAScript5为数组实例添加了两个位置方法:indexOf()和lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中,indexOf()方法从数组的开头(位置0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。
这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回-1。在比较第一个参数与数组中的每一项时,会使用全等操作符;也就是说,要求查找的项必须严格相等。
使用indexOf()和lastIndexOf()方法查找特定项在数组中的位置非常简单,支持它们的浏览器包括IE9+、Firfox2+、Safari3+、Opera9.5+和Chrome。
10、ECMAScript5为数组定义了5个迭代方法。每个方法都接收两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象——影响this的值。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。
every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
以上方法都不会修改数组中的包含的值。
在这些方法中,最相似的是every()和some(),它们都用于查询数组中的项是否满足某个条件。对every()来说,传入的函数必须对每一项都返回true,这个方法才返回true;否则,它就返回false。而some()方法则是只要传入的函数对数组中的某一项返回true,就会返回true。
支持这些迭代方法的浏览器有IE9+、Firefox2+、Safari3+、Opera9.5+和Chrome。
11、ECMAScript5还新增了两个缩小数组的方法:reduce()和reduceRight()。这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。其中,reduce()方法从数组的第一项开始,逐个遍历到最后。而reduceRight()则从数组的最后一项开始,向前遍历到第一项。
这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)作为缩小基础的初始值。传给reduce()和reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。
使用reduce()方法可以执行求数组中所有值之和的操作,比如:
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev,cur,index,array){
return prev+cur;
});
alert(sum); //15
使用reduce()还是reduceRight(),主要取决于要从哪头开始遍历数组。除此之外,它们完全相同。
支持这两个缩小函数的浏览器有IE9+、Firefox3+、Safari4+、Opera10.5和Chrome。
12、创建一个日期对象,使用new操作符和Date构造函数即可。在调用Date构造函数而不传递参数的情况下,新创建的对象自动获得当前日期和时间。如果想根据特定的日期和实际创建日期对象,必须传入表示该日期的毫秒数(即从UTC时间1970年1月1日午夜起至该日期止经过的毫秒数)。为了简化这一计算过程,ECMAScript提供了两个方法:Date.parse()和Date.UTC()。
其中,Date.parse()方法接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数。ECMA-262没有定义Date.parse()应该支持哪种日期格式,因此这个方法的行为因实现而异,而且通常是因地区而异。
如果传入Date.parse()方法的字符串不能表示日期,那么它会返回NaN。实际上,如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse()。
Date.UTC()方法同样也返回表示日期的毫秒数,但它与Date.parse()在构建值时使用不同的信息。Date.UTC()的参数分别是年份、基于0的月份(一月是0,二月是1,以此类推)、月中的哪一天(1到31)、小时数(0到23)、分钟、秒以及毫秒数。在这些参数中,只有前两个参数(年和月)是必需的。如果没有提供月中的天数,则假设天数为1;如果省略其他参数,则统统假设为0。
如同模仿Date.parse()一样,Date构造函数也会模仿Date.UTC(),但有一点明显不同:日期和时间都基于本地时区而非GMT来创建。不过,Date构造函数接收的参数仍然与Date.UTC()相同。因此,如果第一个参数是数值,Date构造函数就会假设该值是日期中的年份,而第二个参数是月份,以此类推。
ECMAScript5添加了Date.now()方法,返回表示调用这个方法时的日期和时间的毫秒数。这个方法简化了使用Date对象分析代码的工作。支持Date.now()方法的浏览器包括IE9+、Firefox3+、Safari3+、Opera10.5和Chrome。在不支持它的浏览器中,使用+操作符把Date对象转换成字符串,也可以达到同样的目的。
var date1 = Date.now();
var date2 = +new Date();
13、Date类型的toLocaleString()方法会按照与浏览器设置的地区相适应的格式返回日期和时间。这大概意味着时间格式中会包含AM或PM,但不会包含时区信息(当然,具体的格式会因浏览器而异)。而toString()方法则通常返回带有时区信息的日期和时间,其中时间一般以军用时间(即小时的范围是0到23)表示。
至于Date类型的valueOf()方法,则根本不返回字符串,而是返回日期的毫秒表示。因此,可以方便使用比较操作符(小于或大于)来比较日期值。
14、Date类型还有一些专门用于将日期格式化为字符串的方法:
toDateString()——以特定于实现的格式显示星期几、月、日和年
toTimeString()——以特定于实现的格式显示时、分、秒和时区
toLocaleDateString——以特定于地区的格式显示星期几、月、日和年;
toLocaleTimeString()——以特定于地区的格式显示时、分、秒
toUTCString()——以特定于实现的格式完整的UTC日期
与toLocaleString()和toString()方法一样,以上这些字符串格式方法的输出也是因浏览器而异的,因此没有哪一个方法能够用来在用户界面中显示一致的日期信息。
15、ECMAScript通过RegExp类型来支持正则表达式。
var expression = / pattern / flags ;
其中的模式(pattern)部分可以是任何简单或复杂的正则表达式,可以包含字符串、限定符、分组、向前查找以及反向引用。每个正则表达式都可带有一或多个标志(flags),用以标明正则表达式的行为。正则表达式的匹配模式支持下列3个标志:
g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;
i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。
除了以字面量形式来定义正则表达式,还可以使用RegExp构造函数,它接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串。
要注意的是,传递给RegExp构造函数的两个参数都是字符串(不能把正则表达式字面量传递给RegExp构造函数)。由于RegExp构造函数的模式参数是字符串,所以在某些情况下要对字符进行双重转义。所有元字符都必须双重转义,那些已经转义过的字符也是如此,例如\n(字符\在字符串中通常被转义为\\,而在正则表达式字符串中就会变成\\\)。
使用正则表达式字面量和使用RegExp构造函数创建的正则表达式不一样。在ECMAScript3中,正则表达式字面量始终会共享同一个RegExp实例,而使用构造函数创建的每一个新RegExp实例都是一个新实例。
ECMAScript5明确规定,使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次都创建新的RegExp实例。IE9+、Firefox4和Chrome都据此作出了修改。
16、RegExp的每个实例都具有下列属性:
global:布尔值,表示是否设置了g标志。
ignoreCase:布尔值,表示是否设置了i标志。
lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起。
multiline:布尔值,表示是否设置了m标志。
source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
17、RegExp对象的主要方法是exec(),该方法是专门为捕获组而设计的。exec()接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。返回的数组虽然是Array的实例,但包含两个额外的属性:index和input。其中,index表示匹配项在字符串中的位置,而index表示应用正则表达式的字符串。在数组中,第一项是整个模式匹配的字符串,其他项是与模式中捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。
对于exec()方法而言,即使在模式中设置了全局变量(g),它每次也只会返回一个匹配项。在不设置全局标志的情况下,在同一个字符串上多次调用exec()将始终返回第一个匹配项的信息。而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配项。此外,还应该注意模式的lastIndex属性的变化情况。在全局匹配模式下,lastIndex的值在每次调用exec()后都会增加,而在非全局模式下则始终保持不变。
正则表达式的第二个方法是test(),它接受一个字符串参数。在模式与该参数匹配的情况下返回true;否则,返回false。在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,使用这个方法非常方便。
RegExp实例继承的toLocaleString()和toString()方法都会返回正则表达式的字面量,与创建正则表达式的方式无关。
正则表达式的valueOf()方法返回正则表达式本身。
18、函数是对象,函数名是指针。
将函数名想象为指针,也有助于理解为什么ECMAScript中没有函数重载的概念。
19、解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
20、在函数内部,有两个特殊的对象:arguments和this。其中arguments是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
函数内部的另一个特殊对象是this,其行为与Java和C#中的this大致类似。换句话说,this引用的是函数据以执行的环境对象——或者也可以说是this值(当在网页的全局作用域中调用函数时,this对象引用的就是window)。
ECMAScript5也规范化了另一个函数对象的属性:caller。除了Opera的早期版本不支持,其他浏览器都支持这个ECMAScript3并没有定义的属性。这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。为了实现更松散的耦合,也可以通过arguments.callee.caller来访问相同的信息。
21、ECMAScript中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接收的命名参数的个数。
对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。换句话说,诸如toString()和valueOf()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时,prototype属性的作用是极为重要的。在ECMAScript5中,prototype属性是不可枚举的,因此使用for-in无法发现。
每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先,apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array的实例,也可以是arguments对象。
call()方法与apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于call()方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用call()方法时,传递给函数的参数必须逐个列举出来。
使用apply()还是call(),完全取决于你采取哪种给函数传递参数的方式最方便。如果你打算直接传入arguments对象,或者包含函数中先接收到的也是一个数组,那么使用apply()肯定更方便;否则,选择call()可能更合适。
事实上,传递参数并非apply()和call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。使用call()(或apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。
ECMAScript5还定义了一个方法:bind()。这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。支持bind()方法的浏览器有IE9+、Firefox4+、Safari5.1+、Opera12+和Chrome。
每个函数继承的toLocaleString()和toString()方法始终都返回函数的代码,返回代码的格式则因浏览器而异。另外一个继承的valueOf()方法同样也只返回函数代码。
22、为了便于操作基本类型值,ECMAScript还提供了3个特殊的引用类型:Boolean、Number和String。实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。
引用类型与基本包装类型的主要区别就是对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法。
当然,可以显式地调用Boolean、Number和String来创建基本包装类型的对象。不过,应该在绝对必要的情况下再这样做,因为这种做法很容易让人分不清自己是在处理基本类型还是引用类型的值。对基本包装类型的实例调用typeof会返回"object",而且所有基本包装类型的对象都会被转换为布尔值true。
Object构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。把字符串传给Object构造函数,就会创建String实例;而传入数值参数会得到Number的实例,传入布尔值参数就会得到Boolean的实例。
要注意的是,使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。
尽管我们不建议显式地创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的。而每个基本包装类型都提供了操作相应的值的便捷方法。
23、Boolean类型是与布尔值对应的引用类型。要创建Boolean对象,可以调用Boolean构造函数并传入true或false值。
Boolean类型的实例重写了valueOf()方法,返回基本类型值true或false;重写了toString()方法,返回字符串"true"和"false"。可是,Boolean对象在ECMAScript中的用处不大,因为它经常会造成人们的误解。
24、Number是与数字值对应的引用类型。要创建Number对象,可以在调用Number构造函数时向其中传递相应的数值。
与Boolean类型一样,Number类型也重写了valueOf()、toLocaleString()和toString()方法。重写后的valueOf()方法返回对象表示的基本类型的数值,另外两个方法则返回字符串形式的数值。可以为toString()方法传递一个表示基数的参数,告诉它返回几进制数值的字符串形式。
除了继承的方法之外,Number类型还提供了一些用于将数值格式化为字符串的方法。
其中,toFixed()方法会按照指定的小数位返回数组的字符串表示。如果数值本身包含的小数位比指定的还多,那么接近指定的最大小数位的值就会舍入。能够自动舍入的特性,使得toFixed()方法很适合处理货币值。但需要注意的是,不同浏览器给这个方法设定的舍入规则可能会有所不同。
另外可用于格式化数值的方法是toExponential(),该方法返回以指数表示法(也称e表示法)表示的数值的字符串形式。与toFixed()一样,toExponential()也接收一个参数,而且该参数同样也是指定输出结果中的小数位数。
如果你想得到表示某个数值的最合适的格式,就应该使用toPrecision()方法。对于一个数值来说,toPrecision()方法可能会返回固定大小(fixed)格式,也可能返回指数(exponential)格式;具体规则是看哪种格式最合适。这个方法接收一个参数,即表示数值的所有数字的位数(不包括指数部分)。
实际上,toPrecision()会根据要处理的数值决定到底是调用toFixed()还是调用toExponential()。而这三个方法都可以通过向上或向下舍入,做到以最准确的形式来表示带有正确小数位的值。
与Boolean对象类似,Number对象也以后台方式为数值提供了重要的功能。但与此同时,我们仍然不建议直接实例化Number类型,而原因与显式创建Boolean对象一样。具体来讲,就是在使用typeof和instanceof操作符测试基本类型数值与引用类型数值时,得到的结果完全不同。在使用typeof操作符测试基本类型数值时,始终会返回"number",而在测试Number对象时,则会返回"Object"。类似地,Number对象是Number类型的实例,而基本类型的数值则不是。
25、String类型是字符串的对象包装类型,可以像下面这样使用String构造函数来创建。String对象的方法也可以在所有基本的字符串值中访问到。其中,继承的valueOf()、toLocaleString()和toString()方法,都返回对象所表示的基本字符串值。
String类型的每个实例都有一个length属性,表示字符串中的字符数量。应该注意的是,即使字符串中包含双字节字符(不是占一个字节的ASCII字符),每个字符也仍然算一个字符。
两个用于访问字符串中特定字符的方法是:charAt()和charCodeAt()。这两个方法都接收一个参数,即基于0的字符位置。其中,charAt()方法以单字符字符串的形式返回给定位置的那个字符(ECMAScript中没有字符类型)。
如果你想得到的不是字符而是字符编码,那么就要使用charCodeAt()了。
ECMAScript5还定义了另一个访问个别字符的方法。在支持浏览器中,可以使用方括号加数字索引来访问字符串中的特定字符。
var stringValue = "hello world";
alert(stringValue[1]); //"e"
使用方括号表示法访问个别字符的语法得到了IE8及Firefox、Safari、Chrome和Opera所有版本的支持。如果是在IE7及更早版本中使用这种语法,会返回undefined值(尽管根本不是特殊的undefined值)。
下面介绍与操作字符串有关的几个方法。第一个就是concat(),用于将一或多个字符串拼接起来,返回拼接得到的新字符串,原字符串的值保持不变。concat()方法可以接受任意多个参数,也就是说可以通过它拼接任意多个字符串。
虽然concat()是专门用来拼接字符串的方法,但实践中使用更多的还是加号操作符。而且,使用加号操作符在大多数情况下都比使用concat()方法要简便易行(特别是在拼接多个字符串的情况下)。
ECMAScript还提供了三个基于子字符串创建新字符串的方法:slice()、substr()和substring()。这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的情况下)表示子字符串到哪里结束。具体来说,slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而substr()的第二个参数指定的则是返回的字符个数。如果没有给这些方法传递第二个参数,则将字符串的长度作为结束位置。与concat()方法一样,slice()、substr()和substring()也不会修改字符串本身的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。
在传递给这些方法的参数是负值的情况下,slice()方法会将传入的负值与字符串的长度相加,substr()方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0。最后,substring()方法会把所有负值参数都转换为0。
有两个可以从字符串中查找子字符串的方法:indexOf()和lastIndexOf()。这两个方法都是从一个字符串中搜索给定的子字符串,然后返回子字符串的位置(如果没有找到该子字符串,则返回-1)。这两个方法的区别在于:indexOf()方法从字符串的开头向后搜索子字符串,而lastIndexOf()方法是从字符串的末尾向前搜索子字符串。这两个方法都可以接收可选的第二个参数,表示从字符串中的哪个位置开始搜索。
在使用第二个参数的情况下,可以通过循环调用indexOf()或lastIndexOf()来找到所有匹配的子字符串。
var stringValue = "Lorem ipsum";
var positions = new Array();
var pos = stringValue.indexOf("e");
while(pos>-1){
positions.push(pos);
pos = stringValue.indexOf("e", pos+1);
}
alert(positions);
ECMAScript5为所有字符串定义了trim()方法,这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。由于trim()返回的是字符串的副本,所以原始字符串中的前置和后缀空格会保持不变。此外,Firefox3.5+、Safari5+和Chrome8+还支持非标准的trimLeft()和trimRight()方法,分别用于删除字符串开头和末尾的空格。
ECMAScript中涉及字符串大小写转换的方法有4个:toLowerCase()、toLocaleLowerCase()、toUpperCase()和toLocaleUpperCase()。其中,toLowerCase()和toUpperCase()是两个经典的方法,借鉴自java.lang.String中的同名方法。而toLocaleLowerCase()和toLocaleUpperCase()方法则是针对特定地区的实现。
String类型定义了几个用于在字符串中匹配模式的方法。第一个方法就是match(),在字符串上调用这个方法,本质上与调用RegExp的exec()方法相同。match()方法只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象。
另一个用于查找模式的方法是search()。这个方法的唯一参数与match()方法的参数相同:由字符串或RegExp对象指定的一个正则表达式。search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。而且,search()方法始终是从字符串开头向后查找模式。
为了简化替换子字符串的操作,ECMAScript提供了replace()方法,这个方法接受两个参数:第一个参数可以是一个RegExp对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局标志。
replace()方法的第二个参数也可以是一个函数。在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递3个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。这个函数应该返回一个字符串,表示应该被替换的匹配项使用函数作为replace()方法的第二个参数可以实现更加精细的替换操作。
最后一个与模式匹配有关的方法是split(),这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符可以是字符串,也可以是一个RegExp对象(这个方法不会将字符串看成正则表达式)。split()方法可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。
对split()中正则表达式的支持因浏览器而异。尽管对于简单的模式没有什么区别,但对于未发现匹配项以及带有捕获组的模式,匹配的行为就不大相同了。
与操作字符串有关的最后一个方法是localeCompare(),这个方法比较两个字符串,并返回下列值中的一个:
如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定);
如果字符串等于字符串参数,则返回0;
如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况是1,具体的值同样视实现而定)。
localeCompare()方法比较与众不同的地方,就是实现所支持的地区(国家和语言)决定了这个方法的行为。
另外,String构造函数本身还有一个静态方法:fromCharCode()。这个方法的任务是接受一或多个字符编码,然后将它们转换成一个字符串。从本质上来看,这个方法与实例方法charCodeAt()执行的是相反的操作。
26、ECMA-262对内置对象的定义是:“由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。”意思就是说,开发人员不必显式地实例化内置对象,因为它们已经实例化了。前面我们已经介绍了大多数内置对象,例如Object、Array和String。ECMA-262还定义了两个单体内置对象:Global和Math。
27、Global对象可以说是ECMAScript中最特别的一个对象了,因为不管你从什么角度上看,这个对象都是不存在的。不属于任何其他对象的属性和方法,最终都是它的属性和方法。事实上,没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性。诸如isNaN()、isFinite()、parseInt()以及parseFloat(),实际上全都是Global对象的方法。
Global对象的encodeURI()和encodeURIComponent()方法可以对URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的URI中不能包含某些字符,例如空格。而这两个URI编码方法就可以对URI进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接受和理解。
其中,encodeURI()主要用于这个URI(例如,http://www.wrox.com/illegal value.html),而encodeURIComponent()主要用于对URI中的某一段(例如前面URI中的illegal value.html)进行编码。它们的主要区别在于,encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。
使用encodeURI()编码后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了%20。而encodeURIComponent()方法则会使用对应的编码替换所有非字母数字字符。这也正是可以对整个URI使用encodeURI(),而只能对附加在现有URI后面的字符串使用encodeURIComponent()的原因所在。
一般来说,我们使用encodeURIComponent()方法的时候要比使用encodeURI()更多,因为在实践中更常见的是对查询字符串参数而不是对基础URI进行编码。
与encodeURI()和encodeURIComponent()方法对应的两个方法分别是decodeURI()和decodeURIComponent()。其中,decodeURI()只能对使用encodeURI()替换的字符进行解码。例如,它可将%20替换成一个空格,但不会对%23作任何处理,因为%23表示井字号(#),而井字号不是使用encodeURI()替换的。同样的,decodeURIComponent()能够解码使用encodeURIComponent()编码的所有字符,即它可以解码任何特殊字符的编码。
现在,我们介绍最后一个——大概也是整个ECMAScript语言中最强大的一个方法:eval()。eval()方法就像是一个完整的ECMAScript解析器,它只接受一个参数,即要执行的ECMAScript(或JavaScript)字符串。
当解析器发现代码中调用eval()方法时,它会被传入的参数当作实际的ECMAScript语句来解析,然后把执行结果插入到原位置。通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链。这意味着通过eval()执行的代码可以引用在包含环境中定义的变量。
在eval()中创建的任何变量或函数都不会被提升,因为在解析代码的时候,他们被包含在一个字符串中;它们只在eval()执行的时候创建。
严格模式下,在外部访问不到eval()中创建的任何变量或函数,为eval赋值也会导致错误。
能够解释代码字符串的能力非常强大,但也非常危险。因此在使用eval()时必须极为谨慎,特别是在用它执行用户输入数据的情况下。否则,可能会有恶意用户输入威胁你的站点或应用程序安全的代码(即所谓的代码注入)。
28、ECMAScript虽然没有指出如何直接访问Global对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。
在没有给函数明确指定this值的情况下(无论是通过将函数添加为对象的方法,还是通过调用call()或apply()),this值等于Global对象。通过简单的返回this来取得Global对象,在任何执行环境下都是可行的。
29、ECMAScript还为保存数学公式和信息提供了一个公共位置,即Math对象。与我们在JavaScript直接编写的计算功能相比,Math对象提供的计算功能执行起来要快得多。Math对象中还提供了辅助完成这些计算的属性和方法。
其中,min()和max()方法用于确定一组数值中的最小值和最大值。这两个方法都可以接收任意多个数值参数。这两个方法经常用于避免多余的循环和在if语句中确定一组数的最大值。要找到数组中的最大或最小值,可以像下面这样使用apply()方法。
var values = [1,2,3,4,5,6,7,8];
var max = Math.max.apply(Math,values);
这个技巧的关键是把Math对象作为apply()的第一个参数,从而正确的设置this值。然后,可以将任何数组作为第二个参数。
30、将小数值舍入为整数的几个方法:
Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数。
31、Math.random()方法返回介于0和1之间一个随机数,不包括0和1。套用下面的公式,就可以利用Math.random()从某个整数范围内随机选择一个值。
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
函数selectFrom()接受两个参数:应该返回的最大值和最小值。利用这个函数,可以方便的从数组中随机取出一项。
var colors = ["red","green","blue",yellow","black"];
var color = colors[selectFrom(0,colors.length-1)]; //可能是数组中包含的任何一个字符串