首頁 > web前端 > js教程 > 主體

深入理解《Javascript高級程式設計》

零下一度
發布: 2017-07-18 16:04:39
原創
1580 人瀏覽過

    Javascript高階程式設計這本書內容很多也很厚,希望其他沒有時間的人可以透過看這系列摘錄,就可以大體學到書裡面的核心內容。

  綠色背景的內容是我認為比較值得注意的原創內容。

  黃色背景的內容是我認為非常重要的原創內容。

  我的理解會用藍色的字體標示出來。

  這章的內容較多,而且比較重要,分兩篇來記錄,這個是下篇。

  5.5.4 函數內部屬性

  在函數內部,有兩個特殊的物件: arguments 和 this。其中, arguments 在第 3 章曾經介紹過,它是一個類別數組對象,包含傳入函數中的所有參數。雖然 arguments 的主要用途是保存函數參數,但這個物件還有一個名叫 callee 的屬性該屬性是一個指針,指向擁有這個 arguments 物件的函數。請看下面這個非常經典的階乘函數

function factorial(num){if (num <=1) {return 1;

} else {return num * factorial(num-1)

}

}
登入後複製

  定義階乘函數一般都要用到遞歸演算法;如上面的程式碼所示,在函數有名字,而且名字以後也不會變的情況下,這樣定義就沒有問題。但問題是這個函數的執行與函數名稱 factorial 緊密耦合在了一起。為了消除這種緊密耦合的現象,可以像下面這樣使用 arguments.callee。

function factorial(num){if (num <=1) {return 1;

} else {return num * arguments.callee(num-1)

}

}
登入後複製
View Code

在這個重寫後的factorial()函數的函數體內,沒有再引用函數名factorial。這樣,無論引用

函數時使用的是什麼名字,都可以保證正常完成遞歸呼叫。例如:

var trueFactorial = factorial;

factorial = function(){return 0;

};

alert(trueFactorial(5)); //120alert(factorial(5)); //0
登入後複製
View Code

在此,变量 trueFactorial 获得了 factorial 的值,实际上是在另一个位置上保存了一个函数的指针。然后,我们又将一个简单地返回 0 的函数赋值给 factorial 变量。如果像原来的 factorial()那样不使用 arguments.callee,调用 trueFactorial()就会返回 0。可是,在解除了函数体内的代码与函数名的耦合状态之后, trueFactorial()仍然能够正常地计算阶乘;至于 factorial(),它现在只是一个返回 0 的函数。

函数内部的另一个特殊对象是 this,其行为与 Java 和 C#中的 this 大致类似。换句话说, this引用的是函数据以执行的环境对象——或者也可以说是 this 值(当在网页的全局作用域中调用函数时,this 对象引用的就是 window)。来看下面的例子。

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}

sayColor(); //"red"o.sayColor = sayColor;

o.sayColor(); //"blue"
登入後複製
View Code

  上面这个函数 sayColor()是在全局作用域中定义的,它引用了 this 对象。由于在调用函数之前,this 的值并不确定,因此 this 可能会在代码执行过程中引用不同的对象。当在全局作用域中调用sayColor()时, this 引用的是全局对象 window;换句话说,对 this.color 求值会转换成对window.color 求值,于是结果就返回了"red"。而当把这个函数赋给对象 o 并调用 o.sayColor()时,this 引用的是对象 o,因此对 this.color 求值会转换成对 o.color 求值,结果就返回了"blue"。

  请读者一定要牢记,函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的 sayColor()函数与 o.sayColor()指向的仍然是同一个函数。

  ECMAScript 5 也规范化了另一个函数对象的属性:caller。除了 Opera 的早期版本不支持,其他浏览器都支持这个 ECMAScript 3 并没有定义的属性。这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为 null。例如:

function outer(){

inner();

}function inner(){

alert(inner.caller);

}

outer();
登入後複製
View Code

以上代码会导致警告框中显示 outer()函数的源代码。因为 outer()调用了 inter(),所以inner.caller 就指向 outer()。为了实现更松散的耦合,也可以通过 arguments.callee.caller来访问相同的信息。

function outer(){

inner();

}function inner(){

alert(arguments.callee.caller);

}

outer();
登入後複製
View Code

IE、 Firefox、 Chrome 和 Safari 的所有版本以及 Opera 9.6 都支持 caller 属性。

当函数在严格模式下运行时,访问 arguments.callee 会导致错误。 ECMAScript 5 还定义了arguments.caller 属性,但在严格模式下访问它也会导致错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清 arguments.caller 和函数的 caller 属性。以上变化都是为了加强这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其他代码了。严格模式还有一个限制:不能为函数的 caller 属性赋值,否则会导致错误。

 

  5.5.5 函数属性和方法

  前面曾经提到过, ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性: length 和 prototype。其中, length 属性表示函数希望接收的命名参数的个数,如下面的例子所示。

function sayName(name){

alert(name);

}function sum(num1, num2){return num1 + num2;

}function sayHi(){

alert("hi");

}

alert(sayName.length); //1alert(sum.length); //2alert(sayHi.length); //0
登入後複製
View Code

  在 ECMAScript 核心所定义的全部属性中,最耐人寻味的就要数 prototype 属性了。对于ECMAScript 中的引用类型而言, prototype 是保存它们所有实例方法的真正所在。换句话说,诸如toString()和 valueOf()等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时, prototype 属性的作用是极为重要的(第 6 章将详细介绍)。在 ECMAScript 5 中, prototype 属性是不可枚举的,因此使用 for-in 无法发现。

  每个函数都包含两个非继承而来的方法: apply()和 call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。首先, apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例也可以是arguments 对象。例如:

function sum(num1, num2){return num1 + num2;

}function callSum1(num1, num2){return sum.apply(this, arguments); // 传入 arguments 对象}function callSum2(num1, num2){return sum.apply(this, [num1, num2]); // 传入数组}

alert(callSum1(10,10)); //20alert(callSum2(10,10)); //20
登入後複製
View Code

  在上面这个例子中, callSum1()在执行 sum()函数时传入了 this 作为 this 值(因为是在全局作用域中调用的,所以传入的就是 window 对象)和 arguments 对象。而 callSum2 同样也调用了sum()函数,但它传入的则是 this 和一个参数数组。这两个函数都会正常执行并返回正确的结果。

  call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call()方法而言,第一个参数是 this 值没有变化,变化的是其余参数都直接传递给函数。换句话说,在使用call()方法时,传递给函数的参数必须逐个列举出来,如下面的例子所示。

function sum(num1, num2){return num1 + num2;

}function callSum(num1, num2){return sum.call(this, num1, num2);

}

alert(callSum(10,10)); //20
登入後複製
View Code

  在使用 call()方法的情况下, callSum()必须明确地传入每一个参数。结果与使用 apply()没有什么不同。至于是使用 apply()还是 call(),完全取决于你采取哪种给函数传递参数的方式最方便。如果你打算直接传入 arguments 对象,或者包含函数中先接收到的也是一个数组,那么使用 apply()肯定更方便;否则,选择 call()可能更合适。(在不给函数传递参数的情况下,使用哪个方法都无所谓。)

事实上,传递参数并非 apply()和 call()真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。下面来看一个例子。

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}

sayColor(); //redsayColor.call(this); //redsayColor.call(window); //redsayColor.call(o); //blue
登入後複製
View Code

  这个例子是在前面说明 this 对象的示例基础上修改而成的。这一次, sayColor()也是作为全局函数定义的,而且当在全局作用域中调用它时,它确实会显示"red"——因为对 this.color 的求值会转换成对 window.color 的求值。而 sayColor.call(this)和 sayColor.call(window),则是两种显式地在全局作用域中调用函数的方式,结果当然都会显示"red"。但是,当运行 sayColor.call(o)时,函数的执行环境就不一样了,因为此时函数体内的 this 对象指向了 o,于是结果显示的是"blue"。

  使用 call()(或 apply())来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。在前面例子的第一个版本中,我们是先将 sayColor()函数放到了对象 o 中,然后再通过 o 来调用它的;而在这里重写的例子中,就不需要先前那个多余的步骤了。

ECMAScript 5 还定义了一个方法: bind()。这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind()函数的值。例如:

window.color = "red";var o = { color: "blue" };function sayColor(){

alert(this.color);

}var objectSayColor = sayColor.bind(o);

objectSayColor(); //blue
登入後複製

在這裡, sayColor()呼叫 bind()並傳入物件 o,創建了 objectSayColor()函數。 object

SayColor()函數的 this 值等於 o,因此即使是在全域作用域中呼叫這個函數,也會看到"blue"。這種技巧的優點請參考第 22 章。

支援 bind()方法的瀏覽器有 IE9+、 Firefox 4+、 Safari 5.1+、 Opera 12+和 Chrome。

每個函數繼承的 toLocaleString()和 toString()方法總是傳回函數的程式碼。傳回程式碼的格式則因瀏覽器而異-有的傳回的程式碼與原始碼中的函數程式碼一樣,而有的則傳回函數程式碼的內部表示,即由解析器刪除了註解並對某些程式碼作了改動後的程式碼。由於這些差異,我們無法根據這兩個方法返回的結果來實現任何重要功能;不過,這些資訊在調試程式碼時倒是很有用。另外一個繼承的valueOf()方法同樣也只回傳函數程式碼。

5.6 基本包裝型別

  為了方便操作基本型別值, ECMAScript 也提供了3 個特殊的參考型別: Boolean、 Number 和String。這些類型與本章介紹的其他引用類型相似,但同時也具有與各自的基本類型相應的特殊行為。實際上,每當讀取一個基本類型值的時候,後台就會建立一個對應的基本包裝類型的對象,讓我們能夠呼叫一些方法來操作這些資料。來看下面的例子。

var s1 = "some text";

var s2 = s1.substring(2);

#  這個例子中的變數s1 包含一個字串,字串當然是基本型別值。而下一行呼叫了 s1 的substring()方法,並將傳回的結果保存在了 s2 中。我們知道,基本類型值不是對象,因而從邏輯上講它們不應該有方法(儘管如我們所願,它們確實有方法)。其實,為了讓我們實現這種直覺的操作,後台已經自動完成了一系列的處理。當第二行程式碼存取 s1 時,存取過程處於一種讀取模式,也就是要從記憶體中讀取這個字串的值。而在讀取模式中存取字串時,後台會自動完成下列處理。

(1) 建立String 類型的一個實例;

#(2) 在實例上呼叫指定的方法;

(3) 銷毀這個實例。

可以將上述三個步驟想像成是執行了下列 ECMAScript 程式碼。

var s1 = new String("some text");

var s2 = s1.substring(2);

s1 = null;

  經過此番處理,基本的字串值就變得跟物件一樣了。而且,上面這三個步驟也分別適用於 Boolean和 Number 類型對應的布林值和數字值。引用類型與基本包裝類型的主要差異就是物件的生存期。使用 new 運算子建立的參考類型的實例,在執行流程離開目前作用域之前都一直保存在記憶體中。而自動建立的基本包裝類型的對象,則只存在於一行程式碼的執行瞬間,然後立即被銷毀。這意味著我們不能在運行時為基本類型值新增屬性和方法。

來看下面的範例:

var s1 = "some text";

s1.color = "red";

#

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"
登入後複製
View Code

在这个例子中,变量 number 中保存的是基本类型的值 25,而变量 obj 中保存的是 Number 的实例。要了解有关转型函数的更多信息,请参考第 3 章。

尽管我们不建议显式地创建基本包装类型的对象,但它们操作基本类型值的能力还是相当重要的。而每个基本包装类型都提供了操作相应值的便捷方法。

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);var result = falseObject && true;

alert(result); //truevar falseValue = false;

result = falseValue && true;

alert(result); //false
登入後複製
View Code

前面讨论过,布尔表达式中的所有对象都会被转换为 true,因此 falseObject 对象在布尔表达式中代表的是 true。结果, true && true 当然就等于 true 了。

基本类型与引用类型的布尔值还有两个区别。首先, typeof 操作符对基本类型返回"boolean",而对引用类型返回"object"。其次,由于 Boolean 对象是 Boolean 类型的实例,所以使用 instanceof操作符测试 Boolean 对象会返回 true,而测试基本类型的布尔值则返回 false。例如:

alert(typeof falseObject); //objectalert(typeof falseValue); //booleanalert(falseObject instanceof Boolean); //truealert(falseValue instanceof Boolean); //false
登入後複製
View Code

理解基本类型的布尔值与 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"NumberTypeExample01.htm
登入後複製
View Code

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

其中, toFixed()方法会按照指定的小数位返回数值的字符串表示,例如:

var num = 10;

alert(num.toFixed(2)); //"10.00"

NumberTypeExample01.htm

这里给 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 修复了这个问题。

5.6.3 String类型

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

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

String 对象的方法也可以在所有基本的字符串值中访问到。其中,继承的 valueOf()、toLocale

String()和 toString()方法,都返回对象所表示的基本字符串值。

String 类型的每个实例都有一个 length 属性,表示字符串中包含多个字符。来看下面的例子。

var stringValue = "hello world";

alert(stringValue.length); //"11"

这个例子输出了字符串"hello world"中的字符数量,即"11"。应该注意的是,即使字符串中包含双字节字符(不是占一个字节的 ASCII 字符),每个字符也仍然算一个字符。

String 类型提供了很多方法,用于辅助完成对 ECMAScript 中字符串的解析和操作。

1. 字符方法

两个用于访问字符串中特定字符的方法是: charAt()和 charCodeAt()

2. 字符串操作方法

下面介绍与操作字符串有关的几个方法。第一个就是 concat(),用于将一或多个字符串拼接起来,返回拼接得到的新字符串。先来看一个例子。

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

alert(result); //"hello world"alert(stringValue); //"hello"
登入後複製
View Code

ECMAScript还提供了三个基于子字符串创建新字符串的方法:slice()、substr()和substring()。这三个方法都会返回被操作字符串的一个子字符串,而且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的情况下)表示子字符串到哪里结束。具体来说, slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置。而 substr()的第二个参数指定的则是返回的字符个数。如果没有给这些方法传递第二个参数,则将字符串的长度作为结束位置。与concat()方法一样, slice()、 substr()和 substring()也不会修改字符串本身的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。请看下面的例子。

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"
登入後複製
View Code

3. 字符串位置方法

有两个可以从字符串中查找子字符串的方法: indexOf()和 lastIndexOf()。这两个方法都是从

一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)。这两个方法的区别在于: indexOf()方法从字符串的开头向后搜索子字符串,而 lastIndexOf()方法是从字符串的末尾向前搜索子字符串。还是来看一个例子吧。

var stringValue = "hello world";

alert(stringValue.indexOf("o")); //4

alert(stringValue.lastIndexOf("o")); //7

4. trim()方法

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

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

alert(stringValue); //" hello world "alert(trimmedStringValue); //"hello world"
登入後複製
View Code

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

接下来我们要介绍的是一组与大小写转换有关的方法。 ECMAScript 中涉及字符串大小写转换的方法有 4 个: toLowerCase()、 toLocaleLowerCase()、 toUpperCase()和 toLocaleUpperCase()

7. localeCompare()方法

与操作字符串有关的最后一个方法是 localeCompare(),这个方法比较两个字符串,并返回下列值中的一个:

q 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定);

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

q 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是 1,具体的值同样要视实现而定)。

下面是几个例子。

var stringValue = "yellow";

alert(stringValue.localeCompare("brick")); //1alert(stringValue.localeCompare("yellow")); //0alert(stringValue.localeCompare("zoo")); //-1
登入後複製
View Code

5.7 單體內建物件

  ECMA-262 內建物件的定義是:「由ECMAScript 實作提供的、不依賴宿主環境的對象,這些對象在ECMAScript 程式執行之前就已經存在了。前面我們已經介紹了大多數內建對象,例如Object、 Array 和 String。

ECMA-262 也定義了兩個單體內建物件: Global 和 Math。

5.7.1 Global物件

#  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 編碼替換所有無效的字符,從而讓瀏覽器能夠接受和理解。

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()仍能顯示"hello world"。這是因為上面第二行程式碼最終被替換成了一行真正的程式碼。同樣地,我們也可以在eval()呼叫中定義一個函數,然後在該呼叫的外部程式碼中引用這個函數:

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

sayHi();

顯然,函數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 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";function sayColor(){

alert(window.color);

}

window.sayColor(); //"red"
登入後複製
View Code

JavaScript中的 window 物件除了扮演 ECMAScript規定的 Global 物件的角色外,

還承擔了許多別的任務。第 8 章在討論瀏覽器物件模型時將詳細介紹 window 物件。

5.7.2 Math物件

ECMAScript 也為保存數學公式和資訊提供了一個公共位置,即 Math 物件。與我們在 JavaScript 直接編寫的計算功能相比, Math 物件提供的計算功能執行起來要快得多。 Math 物件中也提供了輔助完成這些計算的屬性和方法。

1. Math 物件的屬性

Math 物件包含的屬性大都是數學計算中可能會用到的一些特殊值。下表列出了這些屬性。

雖然討論這些值的意義和用途超出了本書範圍,但你確實可以隨時使用它們。

2. min()和max()方法

#Math 物件也包含許多方法,用於輔助完成簡單和複雜的數學計算。

其中, 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. 捨去方法

下面來介紹將小數值捨入為整數的幾個方法: Math.ceil()、 Math.floor( )和Math.round()。

這三個方法分別遵循下列舍入規則:

#Math.ceil()執行向上舍入,即它總是將數值向上捨入為最接近的整數;

Math.floor()執行向下捨入,即它總是將數值向下捨入為最接近的整數;

Math.round()執行標準舍入,即它總是將數值四捨五入為最接近的整數(這也是我們在數學課上學到的捨入規則)。

4. random()方法

#Math.random()方法傳回大於等於 0 小於 1 的一個隨機數。對於某些網站來說,這個方法非常實用,因為可以利用它來隨機顯示一些名人名言和新聞事件。套用下面的公式,就可以利用 Math.random()從某個整數範圍內隨機選取一個值。

值= Math.floor(Math.random() * 可能值的總數+ 第一個可能的值)

##5.其他方法

#5.8 小結

物件在JavaScript 中稱為引用類型的值,而且有一些內建的參考類型可以用來建立特定的對象,現簡要總結如下:

引用類型與傳統物件導向程式設計中的類別相似,但實作不同;

Object 是一個基礎類型,其他所有類型都從Object 繼承了基本的行為;

#Array 類型是一組值的有序列表,同時也提供了操作和轉換這些值的功能;

Date 類型提供了有關日期和時間的信息,包括當前日期和時間以及相關的計算功能;

RegExp 類型是ECMAScript 支援正規表示式的一個接口,提供了最基本的和一些高級的正規表示式功能。

函數其實是 Function 類型的實例,因此函數也是物件;而這一點正是 JavaScript 最有特色的地方。由於函數是對象,所以函數也擁有方法,可以用來增強其行為。

因為有了基本包裝類型,所以 JavaScript 中的基本型別值可以當作物件來存取。三種基本包裝類型分別是: Boolean、 Number 和 String。以下是它們共同的特徵:

每個包裝類型都映射到同名的基本類型;

在讀取模式下存取基本類型值時,就會創建對應的基本包裝類型的一個對象,從而方便了數據操作;

#操作基本類型值的語句一經執行完畢,就會立即銷毀新創建的包裝對象。

在所有程式碼執行之前,作用域中就已經存在兩個內建物件:Global 和 Math。在大多數 ECMAScript實作中都無法直接存取 Global 物件;不過, Web 瀏覽器實作了承擔該角色的 window 物件。全域變數和函數都是 Global 物件的屬性。 Math 物件提供了許多屬性和方法,用於輔助完成複雜的數學計算任務。

 

以上是深入理解《Javascript高級程式設計》的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
js
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板