JavaScript高级程序设计第五章引用类型——单体内置对象

ECMA-262对内置对象的定义是:“由ECMAScript实现提供的,不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。”意思就是说,开发人员不必显式地实例化内置对象,因为他们已经实例化了。前面我们已经介绍了大多数内置对象,例如Object,Array和String。ECMA-262还定义了两个单体内置对象:Global和Math。

5.7.1Global对象

Global(全局)对象可以说是ECMAScript中最特别的一个对象了,因为不管你从什么角度看,这个对象都是不存在的。ECMAScript中的Global对象在某种意义上是作为一个终极的“兜底儿对象”来定义的。换句话说,不属于任何其他对象的属性和方法,最终都是它的属性和方法。实际上,没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性。前面介绍的那些函数,诸如:isNaN(),isFinite(),parseInt(),parseFloat(),实际上全都是Global对象的方法。除此之外,Global对象还包括其他一些方法。

1.URI编码方法

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()则会对它发现的任何非标准字符进行编码。来看例子:

var uri = "http://www.wrox.com/illegal value.html#start";
alert(encodeURI(uri));//http://www.wrox.com/illegal%20value.html#start
alert(encodeURIComponent(uri));//http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start

使用encodeURI()编码之后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了%20.而encodeURIComponent()方法则会使用对应的编码替换所有非字母数字字符。这也正是可以对整个URI使用encodeURI(),而只能对付加在现有URI后面的字符串使用encodeURIComponent()的原因所在。

一般来说,我们使用encodeURIComponent()方法的时候要比使用encodeURI()更多,因为在实践中更常见的是对查询字符串参数而不是对基础字符串进行编码。

与encodeURI()和encodeURIComponent()方法对应的两个方法分别是decodeURI()和decodeURIComponent()。其中,decodeURI()只能对使用encodeURI()替换的字符进行解码。例如,它将%20替换成一个空格,但不会对%23做任何处理,因为%23表示井字号(#),而井字号不是使用encodeURI()替换的。同样的,decodeURIComponent()能够解码使用encodeURIComponent()编码的所有字符,即它们可以解码任何特殊字符的编码。来看例子:

var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start";
alert(decodeURI(uri));//http%3A%2F%2Fwww.wrox.com%2Fillegal value.html%23start
alert(decodeURIComponent(uri));//http://www.wrox.com/illegal value.html#start

这里,变量uri包含着一个由encodeURIComponent()编码的字符串。在第一次调用decodeURI()输出的结果中,只有%20被换成了空格。而在第二次调用decodeURIComponent()输出的结果中,所有特殊字符的编码都被替换成了原来的字符,得到了一个未经转义的字符串(但这个字符串并不是一个有效的URI)。

2.eval()方法

现在,我们介绍最后一个——大概也是整个ECMAScript语言中最强大的一个方法:eval()eval()就像一个完整的ECMAScript解析器,它只接受一个参数,即要执行的ECMAScript字符串,来看例子:

eval("alert('hi')");

这行代码的作用等价于下面这行代码:

alert("hi");

当解析器发现代码中调用eval()方法时,它会将传入的参数当作实际的ECMAScript语句来解析,然后把执行结果插入到原位置。通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链。这意味着通过eval()执行的代码可以引用在包含环境中定义的变量,举个例子:

var msg = "hello world";
eval("alert(msg)");//"hello world"

可见,变量msg是在eval()调用的环境之外定义的,但其中调用的alert()仍然能够显示“hello world”,这是因为上面第二行代码最终被替换成一行真正的代码。同样的,我们也可以在eval()调用中定义一个函数,然后再在该调用的外部代码中引用这个函数:

eval("function sayHi(){ alert('hi'); }");
sayHi();//"hi"

显然,函数sayHi()是在eval()内部定义的。但由于对eval()的调用最终会被替代成定义函数的实际代码,因此可以在下一行调用sayHi()。对于变量也一样:

eval("var msg = 'hello world';");
alert(msg);//"hello world"

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

严格模式下,在外部访问不到eval()中创建的任何变量或函数,因此前面两个例子都会导致错误。同样,在严格模式下,为eval赋值也会导致错误:

"use strict";
eval = "hi";//causes error
使用eval()时必须极为谨慎,特别是在用它执行用户输入数据得情况下,否则,可能会有恶意用户输入威胁你的站点或应用程序安全的代码(即所谓的代码注入)。

3.Global对象的属性

Global对象还包含一些属性,其中一部分属性已经在之前介绍了,例如,特殊的值undefined,NaN以及Infinity都是Global对象的属性。此外,所有原生引用类型的构造函数,像Object和Function,也都是Global对象的属性。下面列出了Global对象的所有属性。

属性                                                说明

undefined                                特殊值undefined

NaN                                         特殊值NaN

Infinity                                     特殊值Infinity

Object                                      构造函数Object

Array                                        构造函数Array

Function                                   构造函数Function

Boolean                                    构造函数Boolean

String                                        构造函数String

Number                                    构造函数Number

Date                                          构造函数Date

RegExp                                      构造函数RegExp

Error                                          构造函数Error

EvalError                                    构造函数EvalError

RangeError                                构造函数RangeError

ReferenceError                          构造函数ReferenceError

SyntaxError                               构造函数SyntaxError

TypeError                                  构造函数TypeError

URIError                                    构造函数URIError

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

4.window对象

ECMAScript虽然没有指出如何直接访问Global对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。来看下面例子:

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

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

JavaScript中的window对象除了扮演ECMAScript规定的Global对象的角色外,还承担了很多别的任务。第8章在讨论浏览器对象模型时将详细介绍window对象。

另一种取得Global对象的方法是使用以下代码:

var global = function(){
   return this;
}();

以上代码创建一个立即调用的函数表达式,返回this的值。如前所述,在没有给函数明确指定this值的情况下(无论是通过将函数添加为对象的方法,还是通过调用call()或apply()),this值等于Global对象。而像这样通过简单地返回this来取得Global对象,在任何环境下都是可行的。第7章将深入讨论函数表达式。

5.7.2Math对象

 ECMAScript还为保存数学公式和信息提供了一个公共位置,即Math对象。与我们在JavaScript直接编写的计算功能相比,Math对象提供的计算功能执行起来要快的多。Math对象中还提供了辅助完成这些计算的属性和方法。

1.Math对象的属性

Math对象包含的属性大都是数学计算中可能用到的一些特殊值。看下面:

属性                                            说明

Math.E                            自然对数的底数,即常量e的值

Math.LN10                     10的自然对数

Math.LN2                        2的自然对数

Math.LOG2E                    以2为底e的对数

Math.LOG10E                  以10为底e的对数

Math.PI                            π的值

Math.SQRT1_2                 1/2的平方根(即2的平方根的倒数)

Math.SQRT2                     2的平方根

2.min()和max()方法

min()和max()方法用于确定一组数值中的最大值和最小值,这两个方法都可以接收任意多个数值参数,如下面例子所示:

var max = Math.max(3, 54, 32, 16);
alert(max);//54

var min = Math.min(3, 54, 32, 16);
alert(min);//3

对于3,54,32,和16,Math.max()返回54,而Math.min()返回3。这两方法经常用于避免多余循环和在if语句中确定一组数的最大值。

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

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

这个技巧的关键是把Math对象作为apply()的第一个参数,从而正确的设置this值。然而,可以将任何数组作为第二个参数。

3.舍入方法

将小数值舍入为整数的几个方法:Math.ceil(),Math.floor(),Math.round()。这三个方法分别遵循下列舍入规则:

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.floor(25.9));//25
alert(Math.floor(25.5));//25
alert(Math.floor(25.1));//25

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

对于所有介于25和26(不包括26)之间的数值,Math.ceil()始终返回26,因为它执行的是向上舍入。Math.round()方法只在数值大于等于25.5时返回26;否则就返回25.最后Math.floor()对所有介于25和26(不包括26)之间的数值都会返回25.

4.radom()方法

Math.radom()方法返回大于等于0小于1的一个随机数。对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件。套用下面的公式,就可以利用Math.random()从某个整数范围内随机选择一个值。

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

公式中用到的了Math.floor()方法,这是因为Math.random()总返回一个小数。而用这个小数值乘以一个整数,然后再加上一个整数,最终结果仍然还是一个小数。举例说明,如果你想选择一个1到10之间的数值,就可以像下面这样编写:

var num = Math.floor(Math.random() * 10 + 1);

总共有10个可能的值(1到10),而第一个可能的值是1.而如果想要选择一个介于2到10之间的值,就应该将上面代码改成这样:

var num = Math.floor(Math.random() * 9 +2);

从2数到10要数9个数,因此可能值的总数就是9,而第一个可能值就是2。多数情况下其实都可以通过一个函数来计算可能值的总数和第一个可能的值,例如:

function selectFrom(lowerValue,upperValue){
   var choices = upperValue - lowerValue+1;
   return Math.floor(Math.random() * choices + lowerValue);
   
}
var num = selectFrom(2, 10);
alert(num);//介于2和10之间(包括2和10)的一个数值

函数selectFrom()接受两个参数:应该返回的最小值和最大值。而用最大值减最小值再加1得到了可能值的总数,然后它又把这些值套用到前面的公式中。这样,通过调用selectFrom(2, 10);就可以得到一个介于2和10之间(包括2和10)的数值了。利用整函数,可以方便地从数组中随机取出一项,例如:

var colors = ["red","green","blue","yellow","black","purple","brown"];
var color = colors[selectFrom(0, colors.length-1)];
alert(color);//可能是数组中包含的任何一个字符串

在这个例子中,传递给selectFrom()的第二个参数是数组的长度减1,也就是数组中最后一项的位置。

5.其他方法

P136
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值