编程语言
首页 > 编程语言> > JavaScript高级程序设计第三版 第5章 引用类型(二)5.6-5.8

JavaScript高级程序设计第三版 第5章 引用类型(二)5.6-5.8

作者:互联网

第5章 引用类型

5.6 基本包装类型

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

    var s1 = "some text";
    var s2 = s1.substring(2);//调用了 s1 的substring()方法,并将返回的结果保存在了 s2 中

这个例子中的变量 s1 包含一个字符串,字符串当然是基本类型值。我们知道,基本类型值不是对象,因而从逻辑上讲它们不应该有方法(尽管如我们所愿,它们确实有方法)。

可以将以上三个步骤想象成是执行了下列 ECMAScript 代码。

    var s1 = new String("some text");
    var s2 = s1.substring(2);
    s1 = null;

经过此番处理,基本的字符串值就变得跟对象一样了。而且,上面这三个步骤也分别适用于 Boolean和 Number 类型对应的布尔值和数字值。

引用类型与基本包装类型的主要区别: 对象的生存期。

使用 new 操作符创建的引用类型的实例 在执行流离开当前作用域之前都一直保存在内存中。
自动创建的基本包装类型的对象 则只存在于一行代码的执行瞬间,然后立即被销毁。

这意味着我们不能在运行时为基本类型值添加属性和方法。来看下面的例子:

    var s1 = "some text";
    s1.color = "red";//为字符串 s1 添加一个 color 属性
    alert(s1.color); //undefined 再次访问 s1 时,其 color 属性不见了

当第三行代码再次访问 s1 时,其 color 属性不见了。问题的原因就是第二行创建的 String 对象在执行第三行代码时已经被销毁了。第三行代码又创建自己的 String 对象,而该对象没有 color 属性。

当然,可以显式地调用 Boolean、 Number 和 String 来创建基本包装类型的对象。不过,应该在
绝对必要的情况下再这样做,因为这种做法很容易让人分不清自己是在处理基本类型还是引用类型的值。对基本包装类型的实例调用 typeof 会返回"object",而且所有基本包装类型的对象都会被转换为布尔值 true。

Object 构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。例如:

    var obj = new Object("some text");
    alert(obj instanceof String); //true

把字符串传给 Object 构造函数,就会创建 String 的实例;而传入数值参数会得到 Number 的实例,传入布尔值参数就会得到 Boolean 的实例。
要注意的是,使用 new 调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的。

例如:

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

在这个例子中,变量 number 中保存的是基本类型的值 25,而变量 obj 中保存的是 Number 的实例。
尽管我们不建议显式地创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的。而每个基本包装类型都提供了操作相应值的便捷方法。

5.6.1 Boolean类型

Boolean 类型是与布尔值对应的引用类型。要创建 Boolean 对象,可以像下面这样调用 Boolean构造函数并传入 true 或 false 值。

    var booleanObject = new Boolean(true);

Boolean 类型的实例重写了 valueOf()方法,返回基本类型值 true 或 false;重写了 toString()方法,返回字符串"true"和"false"。可是, Boolean 对象在 ECMAScript 中的用处不大,因为它经常会造成人们的误解。其中最常见的问题就是在布尔表达式中使用 Boolean 对象,例如:

    var falseObject = new Boolean(false);//使用 false 值创建了一个 Boolean 对象
    var result = falseObject && true;//将这个对象与基本类型值 true构成了逻辑与表达式
    alert(result); //true
    var falseValue = false;
    result = falseValue && true;//布尔表达式中的所有对象都会被转换为 true
    alert(result); //false

在布尔运算中, false && true 等于 false。可是,示例中的这行代码是对falseObject 而不是对它的值(false)进行求值。前面讨论过,布尔表达式中的所有对象都会被转换为 true,因此 falseObject 对象在布尔表达式中代表的是 true。结果, true && true 当然就等于 true 了。

基本类型 引用类型
typeof 操作符 返回"boolean" 返回"object"
instanceof操作符测试 由于 Boolean 对象是 Boolean 类型的实例,所以使用 instanceof操作符测试 Boolean 对象会返回 true 测试基本类型的布尔值则返回 false

例如:

    alert(typeof falseObject); //object
    alert(typeof falseValue); //boolean
    alert(falseObject instanceof Boolean); //true
    alert(falseValue instanceof Boolean); //false

理解基本类型的布尔值与 Boolean 对象之间的区别非常重要——当然,我们的建议是永远不要使用 Boolean 对象。

5.6.2 Number类型

Number 是与数字值对应的引用类型。要创建 Number 对象,可以在调用 Number 构造函数时向其中传递相应的数值。下面是一个例子。

    var numberObject = new Number(10);

与 Boolean 类型一样, Number 类型也重写了 valueOf()、 toLocaleString()和 toString()方法。重写后的 valueOf()方法返回对象表示的基本类型的数值,另外两个方法则返回字符串形式的数值。我们在第 3 章还介绍过,可以为 toString()方法传递一个表示基数的参数,告诉它返回几进制数值的字符串形式,如下面的例子所示。

    var num = 10;
    alert(num.toString()); //"10"
    alert(num.toString(2)); //"1010"
    alert(num.toString(8)); //"12"
    alert(num.toString(10)); //"10"
    alert(num.toString(16)); //"a"

除了继承的方法之外, Number 类型还提供了一些用于将数值格式化为字符串的方法。

    var num = 10;
    alert(num.toFixed(2)); //"10.00"

这里给 toFixed()方法传入了数值 2,意思是显示几位小数。于是,这个方法返回了"10.00",即以 0 填补了必要的小数位。如果数值本身包含的小数位比指定的还多,那么接近指定的最大小数位的值就会舍入,如下面的例子所示。

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

能够自动舍入的特性,使得 toFixed()方法很适合处理货币值。但需要注意的是,不同浏览器给这个方法设定的舍入规则可能会有所不同。在给 toFixed()传入 0 的情况下, IE8 及之前版本不能正确舍入范围在{(-0.94,-0.5],[0.5,0.94)}之间的值。对于这个范围内的值, IE 会返回 0,而不是-1 或 1;其他浏览器都能返回正确的值。 IE9 修复了这个问题。
toFixed()方法可以表示带有 0 到 20 个小数位的数值。但这只是标准实现的范围,有些浏览器也可能支持更多位数。

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

以上代码输出了"1.0e+1";不过,这么小的数值一般不必使用 e 表示法。

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

实际上,toPrecision()会根据要处理的数值决定到底是调用 toFixed()还是调用 toExponential()。而这三个方法都可以通过向上或向下舍入,做到以最准确的形式来表示带有正确小数位的值。
toPrecision()方法可以表现 1 到 21 位小数。某些浏览器支持的范围更大,但这是典型实现的范围。与 Boolean 对象类似, Number 对象也以后台方式为数值提供了重要的功能。但与此同时,我们仍然不建议直接实例化 Number 类型,而原因与显式创建 Boolean 对象一样。具体来讲,就是在使用typeof 和 instanceof 操作符测试基本类型数值与引用类型数值时,得到的结果完全不同,如下面的例子所示。

    var numberObject = new Number(10);
    var numberValue = 10;
    alert(typeof numberObject); //"object"
    alert(typeof numberValue); //"number"
    alert(numberObject instanceof Number); //true
    alert(numberValue instanceof Number); //false

在使用 typeof 操作符测试基本类型数值时,始终会返回"number",而在测试 Number 对象时,则会返回"object"。类似地, Number 对象是 Number 类型的实例,而基本类型的数值则不是。

5.6.3 String类型

String 类型是字符串的对象包装类型,可以像下面这样使用 String 构造函数来创建。

    var stringObject = new String("hello world");

String 对象的方法也可以在所有基本的字符串值中访问到。其中,继承的 valueOf()、toLocaleString()和toString()方法,都返回对象所表示的基本字符串值。
String 类型的每个实例都有一个 length 属性,表示字符串中包含多个字符。来看下面的例子。

    var stringValue = "hello world";
    alert(stringValue.length); //"11"

这个例子输出了字符串"hello world"中的字符数量,即"11"。应该注意的是,即使字符串中包含双字节字符(不是占一个字节的 ASCII 字符),每个字符也仍然算一个字符。
String 类型提供了很多方法,用于辅助完成对 ECMAScript 中字符串的解析和操作。

1. 字符方法

两个用于访问字符串中特定字符的方法是: charAt()和 charCodeAt()。这两个方法都接收一个参数,即基于 0 的字符位置。其中, charAt()方法以单字符字符串的形式返回给定位置的那个字符(ECMAScript 中没有字符类型)。例如:

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

获得字符编码使用 charCodeAt()。

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

ECMAScript 5 还定义了另一个访问个别字符的方法。在支持此方法的浏览器中,可以使用方括号加数字索引来访问字符串中的特定字符,如下面的例子所示。

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

使用方括号表示法访问个别字符的语法得到了 IE8 及 Firefox、 Safari、 Chrome 和 Opera 所有版本的
支持。如果是在 IE7 及更早版本中使用这种语法,会返回 undefined 值(尽管根本不是特殊的undefined 值)。

2. 字符串操作方法

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

实际上, concat()方法可以接受任意多个参数,也就是说可以通过它拼接任意多个字符串。再看一个例子:

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

虽然 concat()是专门用来拼接字符串的方法,但实践中使用更多的还是加号操作符(+)。而且,使用加号操作符在大多数情况下都比使用 concat()方法要简便易行(特别是在拼接多个字符串的情况下)。

    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"  substring()方法则返回了全部字符串,因为它将-3 转换成了 0。
    alert(stringValue.substr(-3)); //"rld"
    alert(stringValue.slice(3, -4)); //"lo w" slice()方法会把第二个参数转换为 7
    alert(stringValue.substring(3, -4)); //"hel" substring()方法会把第二个参数转换为 0 相当于调用了 substring(0,3)
    alert(stringValue.substr(3, -4)); //""(空字符串) substr()也会将第二个参数转换为 0,这也就意味着返回包含零个字符的字符串,也就是一个空字符串

在给 slice()和 substr()传递一个负值参数时,它们的行为相同。这是因为-3 会被转换为 8(字符串长度加参数 11+(-3)=8),实际上相当于调用了 slice(8)substr(8)。
IE 的 JavaScript 实现在处理向 substr()方法传递负值的情况时存在问题,它会返回原始的字符串。 IE9 修复了这个问题。

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

在将第二个参数 6 传递给这两个方法之后,得到了与前面例子相反的结果。这一次,由于indexOf()是从位置 6(字母"w")开始向后搜索,结果在位置 7 找到了"o", 因此它返回 7。而 lastIndexOf()是从位置 6 开始向前搜索。结果找到了"hello"中的"o",因此它返回 4。
在使用第二个参数的情况下,可以通过循环调用 indexOf()或 lastIndexOf()来找到所有匹配的子字符串,如下
面的例子所示:

    var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
    var positions = new Array();
    var pos = stringValue.indexOf("e");
    while(pos > -1){
    positions.push(pos);
    pos = stringValue.indexOf("e", pos + 1);//不断增加 indexOf()方法开始查找的位置,遍历了一个长字符串
    }
    alert(positions); //"3,24,32,35,52"

每次搜索返回的位置依次被保存在数组 positions 中,以便将来使用。

4. trim()方法

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

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

由于 trim()返回的是字符串的副本,所以原始字符串中的前置及后缀空格会保持不变。支持这个方法的浏览器有 IE9+、 Firefox 3.5+、 Safari 5+、 Opera 10.5+和 Chrome。此外, Firefox 3.5+、 Safari 5+和 Chrome 8+还支持非标准的 trimLeft()和 trimRight()方法,分别用于删除字符串开头和末尾的空格。

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

接下来我们要介绍的是一组与大小写转换有关的方法。 ECMAScript 中涉及字符串大小写转换的方法有 4 个: toLowerCase()、 toLocaleLowerCase()、 toUpperCase()和 toLocaleUpperCase()。
其中, toLowerCase()和 toUpperCase()是两个经典的方法,借鉴自 java.lang.String 中的同名方法。而 toLocaleLowerCase()和 toLocaleUpperCase()方法则是针对特定地区的实现。对有些地区来说,针对地区的方法与其通用方法得到的结果相同,但少数语言(如土耳其语)会为 Unicode 大小写转换应用特殊的规则,这时候就必须使用针对地区的方法来保证实现正确的转换。以下是几个例子。

    var stringValue = "hello world";
    alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD"
    alert(stringValue.toUpperCase()); //"HELLO WORLD"
    alert(stringValue.toLocaleLowerCase()); //"hello world"
    alert(stringValue.toLowerCase()); //"hello world"

一般来说,在不知道自己的代码将在哪种语言环境中运行的情况下,还是使用针对地区的方法更稳妥一些。

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

    var text = "cat, bat, sat, fat";
    var pattern = /.at/;
    //与 pattern.exec(text)相同
    var matches = text.match(pattern);//本例中的 match()方法返回了一个数组
    alert(matches.index); //0
    alert(matches[0]); //"cat"  数组的第一项是与整个模式匹配的字符串
    alert(pattern.lastIndex); //0

如果是调用 RegExp 对象的 exec()方法并传递本例中的字符串作为参数,那么也会得到与此相同的数组:数组的第一项是与整个模式匹配的字符串,之后的每一项(如果有)保存着与正则表达式中的捕获组匹配的字符串。

    var text = "cat, bat, sat, fat";
    var pos = text.search(/at/);
    alert(pos); //1
    var text = "cat, bat, sat, fat";
    var result = text.replace("at", "ond");//首先传入 replace()方法的是字符串"at"和替换用的字符串"ond"。
    alert(result); //"cond, bat, sat, fat" 替换的结果是把"cat"变成了"cond",但字符串中的其他字符并没有受到影响。
    result = text.replace(/at/g, "ond");//通过将第一个参数修改为带有全局标志的正则表达式,就将全部"at"都替换成了"ond"。
    alert(result); //"cond, bond, sond, fond"

如果第二个参数是字符串,那么还可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中。下表列出了 ECMAScript 提供的这些特殊的字符序列。

字符序列 替换文本
$$ $
$& 匹配整个模式的子字符串。与RegExp.lastMatch的值相同
$’ 匹配的子字符串之前的子字符串。与RegExp.leftContext的值相同
$` 匹配的子字符串之后的子字符串。与RegExp.rightContext的值相同
$n 匹配第n个捕获组的子字符串,其中n等于0~9。例如, $1是匹配第一个捕获组的子字符串, $2是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串
$nn 匹配第nn个捕获组的子字符串,其中nn等于01~99。例如, $01是匹配第一个捕获组的子字符串, $02是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串

通过这些特殊的字符序列,可以使用最近一次匹配结果中的内容,如下面的例子所示。

    var text = "cat, bat, sat, fat";
    result = text.replace(/(.at)/g, "word ($1)");
    alert(result); //word (cat), word (bat), word (sat), word (fat)

每个以"at"结尾的单词都被替换了,替换结果是"word"后跟一对圆括号,而圆括号中是被字符序列$1 所替换的单词。
replace()方法的第二个参数也可以是一个函数。在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递 3 个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。在正则表达式中定义了多个捕获组的情况下,传递给函数的参数依次是模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项……,但最后两个参数仍然分别是模式的匹配项在字符串中的位置和原始字符串。这个函数应该返回一个字符串,表示应该被替换的匹配项使用函数作为 replace()方法的第二个参数可以实现更加精细的替换操作,请看下面这个例子。

    function htmlEscape(text){
    return text.replace(/[<>"&]/g, function(match, pos, originalText){
    switch(match){
    case "<":
    return "&lt;";
    case ">":
    return "&gt;";
    case "&":
    return "&amp;";
    case "\"":
    return "&quot;";
    }
    });
    }
    alert(htmlEscape("<p class=\"greeting\">Hello world!</p>"));
    //&lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;/p&gt;

这里,我们为插入 HTML 代码定义了函数 htmlEscape(),这个函数能够转义 4 个字符:小于号、大于号、和号以及双引号。

    var colorText = "red,blue,green,yellow";// colorText 是逗号分隔的颜色名字符串
    var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"]基于该字符串调用 split(",")会得到一个包含其中颜色名的数组,用于分割字符串的分隔符是逗号。
    var colors2 = colorText.split(",", 2); //["red", "blue"] 为了将数组截短,让它只包含两项,可以为 split()方法传递第二个参数 2。
    var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""] 通过使用正则表达式,还可以取得包含逗号字符的数组。

需要注意的是,在最后一次调用 split()返回的数组中,第一项和最后一项是两个空字符串。之所以会这样,是因为通过正则表达式指定的分隔符出现在了字符串的开头(即子字符串"red")和末尾(即子字符串"yellow")。

  1. IE8 及之前版本会忽略捕获组。 ECMA-262 规定应该把捕获组拼接到结果数组中。 IE9 能正确地
    在结果中包含捕获组。
  2. Firefox 3.6 及之前版本在捕获组未找到匹配项时,会在结果数组中包含空字符串; ECMA-262 规
    定没有匹配项的捕获组在结果数组中应该用 undefined 表示。在正则表达式中使用捕获组时还有其他微妙的差别。在使用这种正则表达式时,一定要在各种浏览器下多做一些测试。

要了解关于 split()方法以及捕获组的跨浏览器问题的更多讨论,请参考 StevenLevithan 的文章“JavaScript split bugs: Fixed!”(http://blog.stevenlevithan.com/archives/cross-browser-split)。

7. localeCompare()方法

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

条件 返回
如果字符串在字母表中应该排在字符串参数之前 返回一个负数(大多数情况下是-1,具体的值要视实现而定)
如果字符串等于字符串参数 返回 0
如果字符串在字母表中应该排在字符串参数之后 返回一个正数(大多数情况下是 1,具体的值同样要视实现而定)

下面是几个例子。

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

再强调一次,因为 localeCompare()返回的数值取决于实现,所以最好是像下面例子所示的这样使用这个方法。

    function determineOrder(value) {
    var result = stringValue.localeCompare(value);
    if (result < 0){
    alert("The string 'yellow' comes before the string '" + value + "'.");
    } else if (result > 0) {
    alert("The string 'yellow' comes after the string '" + value + "'.");
    } else {
    alert("The string 'yellow' is equal to the string '" + value + "'.");
    }
    }
    determineOrder("brick");
    determineOrder("yellow");
    determineOrder("zoo");

使用这种结构,就可以确保自己的代码在任何实现中都可以正确地运行了。

localeCompare()方法比较与众不同的地方,就是实现所支持的地区(国家和语言)决定了这个方法的行为。比如,美国以英语作为 ECMAScript 实现的标准语言,因此 localeCompare()就是区分大小写的,于是大写字母在字母表中排在小写字母前头就成为了一项决定性的比较规则。不过,在其他地区恐怕就不是这种情况了。

8. fromCharCode()方法

另外, String 构造函数本身还有一个静态方法: fromCharCode()。这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。从本质上来看,这个方法与实例方法 charCodeAt()执行的是相反的操作。来看一个例子:

    alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"

在这里,我们给 fromCharCode()传递的是字符串"hello"中每个字母的字符编码。

9. HTML 方法

早期的 Web 浏览器提供商觉察到了使用 JavaScript 动态格式化 HTML 的需求。于是,这些提供商就扩展了标准,实现了一些专门用于简化常见 HTML 格式化任务的方法。下表列出了这些 HTML 方法。
不过,需要请读者注意的是,应该尽量不使用这些方法,因为它们创建的标记通常无法表达语义。

方 法 输出结果
anchor(name) < a name= “name”>string
big() < big>string< /big>
bold() < b>string</ b>
fixed() < tt>string</ tt>
fontcolor(color) < font color=“color”>string</ font>
fontsize(size) < font size=“size”>string</ font>
italics() < i>string</ i>
link(url) < a href=“url”>string</ a>
small() < small>string</ small>
strike() < strike>string</ strike>
sub() < sub>string</ sub>
sup() < sup>string</ sup>

5.7 单体内置对象

5.7.1 Global对象

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

1. URI 编码方法

encodeURI() encodeURIComponent()方法
作用 用特殊的 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。 用特殊的 UTF-8 编码替换所有无效的字符,从而让浏览器能够接受和理解。
主要用于 整个 URI(例如, http://www.wrox.com/illegal value.htm) 对 URI 中的某一段(例如前面 URI 中的 illegal value.htm)进行编码。
主要区别 encodeURI()不会对本身属于 URI 的特殊字符进行编码,例如冒号、正斜杠、问号和井字号 encodeURIComponent()则会对它发现的任何非标准字符进行编码。

Global 对象的 encodeURI()和 encodeURIComponent()方法可以对 URI(Uniform Resource Identifiers,通用资源标识符)进行编码,以便发送给浏览器。有效的 URI 中不能包含某些字符,例如空格。
来看下面的例子。

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

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

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

decodeURI() decodeURIComponent()
作用 只能对使用 encodeURI()替换的字符进行解码。例如,它可将%20 替换成一个空格,但不会对%23 作任何处理,因为%23 表示井字号(#),而井字号不是使用encodeURI()替换的。 decodeURIComponent()能够解码使用 encodeURIComponent()编码的所有字符,即它可以解码任何特殊字符的编码。

来看下面的例子:

    var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start";//变量 uri 包含着一个由 encodeURIComponent()编码的字符串
    //http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start
    alert(decodeURI(uri));
    //http://www.wrox.com/illegal value.htm#start
    //在第一次调用 decodeURI()输出的结果中,只有%20 被替换成了空格。
    alert(decodeURIComponent(uri));//而在第二次调用 decodeURIComponent()输出的结果中,所有特殊字符的编码都被替换成了原来的字符,得到了一个未经转义的字符串(但这个字符串并不是一个有效的 URI)。

URI 方法 encodeURI()、 encodeURIComponent()、 decodeURI()和 decodeURIComponent()用于替代已经被 ECMA-262第 3版废弃的 escape()和 unescape()方法。 URI 方法能够编码所有 Unicode 字符,而原来的方法只能正确地编码 ASCII 字符。
因此在开发实践中,特别是在产品级的代码中,一定要使用 URI 方法,不要使用 escape()和 unescape()方法。

2. eval()方法

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

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

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

    alert("hi");

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

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

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

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

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

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

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

    "use strict";
    eval = "hi"; //causes error

3. Global 对象的属性

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

属 性 说 明 属 性 说 明
undefined 特殊值undefined Date 构造函数Date
NaN 特殊值NaN RegExp 构造函数RegExp
Infinity 特殊值Infinity Error 构造函数Error
Object 构造函数Object EvalError 构造函数EvalError
Array 构造函数Array RangeError 构造函数RangeError
Function 构造函数Function ReferenceError 构造函数ReferenceError
Boolean 构造函数Boolean SyntaxError 构造函数SyntaxError
String 构造函数String TypeError 构造函数TypeError
Number 构造函数Number URIError 构造函数URIError

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

4. window 对象

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

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

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

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

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

5.7.2 Math对象

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

这两个方法经常用于避免多余的循环和在 if 语句中确定一组数的最大值。

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

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

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

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 的一个随机数。对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件。套用下面的公式,就可以利用 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;//用最大值减最小值再加 1 得到了可能值的总数
    return Math.floor(Math.random() * choices + lowerValue);//又把这些数值套用到了前面的公式中
    }
    var num = selectFrom(2, 10);//通过调用 selectFrom(2,10)就可以得到一个介于 2 和 10 之间(包括 2 和 10)的数值了
    alert(num); // 介于 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. 其他方法

Math 对象中还包含其他一些与完成各种简单或复杂计算有关的方法,但详细讨论其中每一个方法的细节及适用情形超出了本书的范围。下面我们就给出一个表格,其中列出了这些没有介绍到的 Math对象的方法。

方 法 说 明 方 法 说 明
Math.abs(num) 返回num 的绝对值 Math.asin(x) 返回x 的反正弦值
Math.exp(num) 返回Math.E 的num 次幂 Math.atan(x) 返回x 的反正切值
Math.log(num) 返回num 的自然对数 Math.atan2(y,x) 返回y/x 的反正切值
Math.pow(num,power) 返回num 的power 次幂 Math.cos(x) 返回x 的余弦值
Math.sqrt(num) 返回num 的平方根 Math.sin(x) 返回x 的正弦值
Math.acos(x) 返回x 的反余弦值 Math.tan(x) 返回x 的正切值

虽然 ECMA-262 规定了这些方法,但不同实现可能会对这些方法采用不同的算法。毕竟,计算某个值的正弦、余弦和正切的方式多种多样。也正因为如此,这些方法在不同的实现中可能会有不同的精度。

5.8 小结

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

因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当作对象来访问。三种基本包装类型分别是: Boolean、 Number 和 String。以下是它们共同的特征:

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

标签:5.6,5.8,JavaScript,alert,var,字符串,stringValue,方法,Math
来源: https://blog.csdn.net/qq_43340342/article/details/99350989