ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript猾编,那么 BOM(瀏覽器對象模型)則無疑才是真正的核心逝薪。BOM 提供了很多對象杠览,用于訪問瀏覽器的功能,這些功能與任何網(wǎng)頁內容無關当宴。多年來畜吊,缺少事實上的規(guī)范導致 BOM 有很多問題,因為瀏覽器提供商會按照各自的想法隨意去擴展它户矢。W3C 為了把瀏覽器中 JavaScript 最基本的部分標準化玲献,已經(jīng)將 BOM 的主要方面納入了 HTML5 的規(guī)范中。
window
對象
BOM 的核心對象是 window
梯浪,它表示瀏覽器的一個實例捌年。在瀏覽器中,window
對象有雙重角色挂洛,它既是通過 JavaScript 訪問瀏覽器窗口的一個接口礼预,又是 ECMAScript 規(guī)定的 Global
對象。這意味著在網(wǎng)頁中定義的任何一個對象虏劲、變量和函數(shù)托酸,都以 window
作為其 Global
對象,因此有權訪問 isNaN()
柒巫、isFinite()
励堡、parseInt()
、parseFloat()
等方法堡掏。
全局作用域
由于 window
對象同時扮演著 ECMAScript 中 Global
對象的角色应结,因此所有在全局作用域中聲明的變量、函數(shù)都會變成 window
對象的屬性和方法布疼。來看下面的例子摊趾。
var age = 29;
function sayAge(){
console.log(this.age);
}
console.log(window.age); // 29
sayAge(); // 29
window.sayAge(); // 29
拋開全局變量會成為 window
對象的屬性不談币狠,定義全局變量與在 window
對象上直接定義屬性還是有一點差別:全局變量不能通過 delete
運算符刪除游两,而直接在 window
對象上的定義的屬性可以。例如:
var age = 29;
window.color = "red";
// 在 IE < 9 時拋出錯誤漩绵,在其他所有瀏覽器中都返回 false
delete window.age;
// 在 IE < 9 時拋出錯誤贱案,在其他所有瀏覽器中都返回 true
delete window.color; // return true
console.log(window.age); // 29
console.log(window.color); // undefined
使用 var
語句添加的 window
屬性有一個名為 Configurable
的特性,這個特性的值被默認設置為 false
,因此這樣定義的屬性不可以通過 delete
運算符刪除宝踪。IE8 及更早版本在遇到使用 delete
刪除 window
屬性的語句時侨糟,不管該屬性最初是如何創(chuàng)建的,都會拋出錯誤瘩燥,以示警告秕重。IE9 及更高版本不會拋出錯誤。
另外厉膀,還要記住一件事:嘗試訪問未聲明的變量會拋出錯誤溶耘,但是通過查詢 window
對象,可以知道某個可能未聲明的變量是否存在服鹅。例如:
// 這里會拋出錯誤凳兵,因為 oldValue 未定義
var newValue = oldValue;
// 這里不會拋出錯誤,因為這是一次屬性查詢
// newValue 的值是 undefined
var newValue = window.oldValue;
窗口關系及框架
如果頁面中包含框架企软,則每個框架都擁有自己的 window
對象庐扫,并且保存在 frames
集合中。在 frames
集合中仗哨,可以通過數(shù)值索引(從0開始形庭,從左至右,從上到下)或者框架名稱來訪問相應的 window
對象厌漂。每個 window
對象都有一個 name
屬性碘勉,其中包含框架的名稱。下面是一個包含框架的頁面:
<html>
<head>
<title>Frameset Example</title>
</head>
<frameset rows="160,*">
<frame src="frame.htm" name="topFrame">
<frameset cols="50%,50%">
<frame src="anotherframe.htm" name="leftFrame">
<frame src="yetanotherframe.htm" name="rightFrame">
</frameset>
</frameset>
</html>
對這個例子而言桩卵,可以通過 window.frames[0]
或者 window.frames["topFrame"]
來引用上方的框架验靡。不過最好使用 top
而非 window
來引用這些框架(例如 top.frames[0]
),因為 top
對象始終指向最高(最外)層的框架雏节,也就是瀏覽器窗口胜嗓。使用它可以確保在一個框架中正確地訪問另一個框架。因為對于在一個框架中編寫的任何代碼來說钩乍,其中的 window
對象指向的都是那個框架的特定實例辞州,而非最高層的框架。
與 top
相對的另一個 window
對象是 parent
寥粹。顧名思義变过,parent
(父)對象始終指向當前框架的直接上層框架。在某些情況下涝涤,parent
有可能等于 top
媚狰;但在沒有框架的情況下,parent
一定等于 top
(此時它們都等于 window
)阔拳。
與框架有關的最后一個對象是 self
崭孤,它始終指向 window
;實際上,self
和 window
對象可以互換使用辨宠。引入 self
對象的目的只是為了與 top
和 parent
對象對應起來遗锣,因此它不格外包含其他值。
所有這些對象都是 window
對象的屬性嗤形,可以通過 window.parent
精偿、window.top
等形式來訪問。同時赋兵,這也意味著可以將不同層次的 window
對象連綴起來还最,例如 window.parent.parent.frames[0]
。
在使用框架的情況下毡惜,瀏覽器中會存在多個 Global
對象拓轻。在每個框架中定義的全局變量會自動成為框架中 window
對象的屬性。由于每個 window
對象都包含原生類型的構造函數(shù)经伙,因此每個框架都有一套自己的構造函數(shù)扶叉,這些構造函數(shù)一一對應,但并不相等帕膜。例如枣氧,top.Object
并不等于 top.frames[0].Object
。這個問題會影響到對跨框架傳遞的對象使用 instanceof
運算符垮刹。
導航和打開窗口
使用 window.open()
方法既可以導航到一個特定的 URL达吞,也可以打開一個新的瀏覽器窗口。這個方法可以接收4個參數(shù):要加載的URL荒典、窗口目標酪劫、一個特性字符串以及一個表示新頁面是否取代瀏覽器歷史記錄中當前加載頁面的布爾值。通常只須傳遞第一個參數(shù)寺董,最后一個參數(shù)只在不打開新窗口的情況下使用覆糟。
如果為 window.open()
傳遞了第二個參數(shù),而且該參數(shù)是已有窗口或框架的名稱遮咖,那么就會在具有該名稱的窗口或框架中加載第一個參數(shù)指定的 URL滩字。看下面的例子御吞。
// 等同于 <a target="newWindow"></a>
window.open("http://shijiajie.com/", "newWindow");
彈出窗口
如果給 window.open()
傳遞的第二個參數(shù)并不是一個已經(jīng)存在的窗口或框架麦箍,那么該方法就會根據(jù)在第三個參數(shù)位置上傳入的字符串創(chuàng)建一個新窗口或新標簽頁。如果沒有傳入第三個參數(shù)陶珠,那么就會打開一個帶有全部默認設置(工具欄挟裂、地址欄和狀態(tài)欄等)的新瀏覽器窗口(或者打開一個新標簽頁)。在不打開新窗口的情況下背率,會忽略第三個參數(shù)话瞧。
第三個參數(shù)是一個逗號分隔的設置字符串嫩与,表示在新窗口中都顯示哪些特性寝姿。下表列出了可以出現(xiàn)在這個字符串中的設置選項交排。
設置 | 值 | 說明 |
---|---|---|
fullscreen | yes或no | 表示瀏覽器窗口是否最大化。僅限IE |
height | 數(shù)值 | 表示新窗口的高度饵筑。不能小于100 |
left | 數(shù)值 | 表示新窗口的左坐標埃篓。不能是負值 |
location | yes或no | 表示是否在瀏覽器窗口中顯示地址欄。不同瀏覽器的默認值不同根资。如果設置為no架专,地址欄可能會隱藏,也可能會被禁用(取決于瀏覽器) |
menubar | yes或no | 表示是否在瀏覽器窗口中顯示菜單欄玄帕。默認值為no |
resizable | yes或no | 表示是否可以通過拖動瀏覽器窗口的邊框改變其大小部脚。默認值為no |
scrollbars | yes或no | 表示如果內容在視口中顯示不下,是否允許滾動裤纹。默認值為no |
status | yes或no | 表示是否在瀏覽器窗口中顯示狀態(tài)欄委刘。默認值為no |
toolbar | yes或no | 表示是否在瀏覽器窗口中顯示工具欄。默認值為no |
top | 數(shù)值 | 表示新窗口的上坐標鹰椒。不能是負值 |
width | 數(shù)值 | 表示新窗口的寬度锡移。不能小于100 |
這行代碼會打開一個新的可以調整大小的窗口,窗口初始大小為400×400像素漆际,并且距屏幕上沿和左邊各10像素淆珊。
window.open("http://shijiajie.com/","newWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
window.open()
方法會返回一個指向新窗口的引用。引用的對象與其他 window
對象大致相似奸汇,但我們可以對其進行更多控制施符。例如,有些瀏覽器在默認情況下可能不允許我們針對主瀏覽器窗口調整大小或移動位置擂找,但卻允許我們針對通過window.open()創(chuàng)建的窗口調整大小或移動位置操刀。通過這個返回的對象,可以像操作其他窗口一樣操作新打開的窗口婴洼,如下所示骨坑。
var win = window.open("http://shijiajie.com/","newWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
// 調整大小
win.resizeTo(500,500);
// 移動位置
win.moveTo(100,100);
// 關閉窗口
win.close();
但是,close()
方法僅適用于通過 window.open()
打開的彈出窗口柬采。對于瀏覽器的主窗口欢唾,如果沒有得到用戶的允許是不能關閉它的。
新創(chuàng)建的 window
對象有一個 opener
屬性粉捻,其中保存著打開它的原始窗口對象礁遣。這個屬性只在彈出窗口中的最外層 window
對象(top)中有定義,而且指向調用 window.open()
的窗口或框架肩刃。例如:
var win = window.open("http://shijiajie.com/","newWindow",
"height=400,width=400,top=10,left=10,resizable=yes");
console.log(win.opener === window); // true
雖然彈出窗口中有一個指針指向打開它的原始窗口祟霍,但原始窗口中并沒有這樣的指針指向彈出窗口杏头。窗口并不跟蹤記錄它們打開的彈出窗口,因此我們只能在必要的時候自己來手動實現(xiàn)跟蹤沸呐。
彈出窗口屏蔽程序
曾經(jīng)有一段時間醇王,廣告商在網(wǎng)上使用彈出窗口達到了肆無忌憚的程度。他們經(jīng)常把彈出窗口打扮成系統(tǒng)對話框的模樣崭添,引誘用戶去點擊其中的廣告寓娩。由于看起來像是系統(tǒng)對話框,一般用戶很難分辨是真是假呼渣。為了解決這個問題棘伴,大多數(shù)瀏覽器內置有彈出窗口屏蔽程序,將絕大多數(shù)用戶不想看到彈出窗口屏蔽掉屁置。
于是焊夸,在彈出窗口被屏蔽時,就應該考慮兩種可能性蓝角。如果是瀏覽器內置的屏蔽程序阻止的彈出窗口阱穗,那么 window.open()
很可能會返回 null
,如果是瀏覽器擴展或其他程序阻止的彈出窗口帅容,那么 window.open()
通常會拋出一個錯誤颇象。因此,要想準確地檢測出彈出窗口是否被屏蔽并徘,必須在檢測返回值的同時遣钳,將對 window.open()
的調用封裝在一個 try-catch
塊中,如下所示麦乞。
var blocked = false;
try {
var win = window.open("http://shijiajie.com", "_blank");
if (win == null){
blocked = true;
}
} catch (ex){
blocked = true;
}
if (blocked){
console.log("The popup was blocked!");
}
間歇調用和超時調用
JavaScript 是單線程語言蕴茴,但它允許通過設置超時值和間歇時間值來調度代碼在特定的時刻執(zhí)行。前者是在指定的時間過后執(zhí)行代碼姐直,而后者則是每隔指定的時間就執(zhí)行一次代碼倦淀。
超時調用需要使用 window
對象的 setTimeout()
方法,它接受兩個參數(shù):要執(zhí)行的代碼和以毫秒表示的時間(即在執(zhí)行代碼前需要等待多少毫秒)声畏。其中撞叽,第一個參數(shù)可以是一個包含 JavaScript 代碼的字符串(就和在 eval()
函數(shù)中使用的字符串一樣),也可以是一個函數(shù)插龄。例如愿棋,下面對 setTimeout()
的兩次調用都會在一秒鐘后顯示一個警告框。
// 不建議傳遞字符串
setTimeout("console.log('Hello world!') ", 1000);
// 推薦的調用方式
setTimeout(function() {
console.log("Hello world!");
}, 1000);
雖然這兩種調用方式都沒有問題均牢,但由于傳遞字符串可能導致性能損失糠雨,因此不建議以字符串作為第一個參數(shù)。
第二個參數(shù)是一個表示等待多長時間的毫秒數(shù)徘跪,但經(jīng)過該時間后指定的代碼不一定會執(zhí)行甘邀。JavaScript 是一個單線程序的解釋器琅攘,因此一定時間內只能執(zhí)行一段代碼。為了控制要執(zhí)行的代碼松邪,就有一個 JavaScript 任務隊列坞琴。這些任務會按照將它們添加到隊列的順序執(zhí)行。setTimeout()
的第二個參數(shù)告訴 JavaScript
再過多長時間把當前任務添加到隊列中测摔。如果隊列是空的置济,那么添加的代碼會立即執(zhí)行解恰;如果隊列不是空的锋八,那么它就要等前面的代碼執(zhí)行完了以后再執(zhí)行。
調用 setTimeout()
之后护盈,該方法會返回一個數(shù)值 ID
挟纱,表示超時調用。這個超時調用 ID
是計劃執(zhí)行代碼的唯一標識符腐宋,可以通過它來取消超時調用。要取消尚未執(zhí)行的超時調用計劃,可以調用 clearTimeout()
方法并將相應的超時調用 ID
作為參數(shù)傳遞給它剥啤,如下所示训桶。
// 設置超時調用
var timeoutId = setTimeout(function() {
console.log("Hello world!");
}, 1000);
// 注意:把它取消
clearTimeout(timeoutId);
只要是在指定的時間尚未過去之前調用 clearTimeout()
,就可以完全取消超時調用卫枝。前面的代碼在設置超時調用之后馬上又調用了 clearTimeout()
煎饼,結果就跟什么也沒有發(fā)生一樣。
間歇調用與超時調用類似校赤,只不過它會按照指定的時間間隔重復執(zhí)行代碼吆玖,直至間歇調用被取消或者頁面被卸載。設置間歇調用的方法是 setInterval()
马篮,它接受的參數(shù)與 setTimeout()
相同:要執(zhí)行的代碼(字符串或函數(shù))和每次執(zhí)行之前需要等待的毫秒數(shù)沾乘。下面來看一個例子。
// 不建議傳遞字符串
setInterval ("console.log('Hello world!') ", 10000);
// 推薦的調用方式
setInterval (function() {
console.log("Hello world!");
}, 10000);
調用 setInterval()
方法同樣也會返回一個間歇調用 ID
浑测,該 ID
可用于在將來某個時刻取消間歇調用翅阵。要取消尚未執(zhí)行的間歇調用,可以使用 clearInterval()
方法并傳入相應的間歇調用 ID
迁央。取消間歇調用的重要性要遠遠高于取消超時調用掷匠,因為在不加干涉的情況下,間歇調用將會一直執(zhí)行到頁面卸載漱贱。以下是一個常見的使用間歇調用的例子槐雾。
var num = 0;
var max = 10;
var intervalId = null;
function incrementNumber() {
num++;
// 如果執(zhí)行次數(shù)達到了max設定的值,則取消后續(xù)尚未執(zhí)行的調用
if (num == max) {
clearInterval(intervalId);
console.log("Done");
}
}
intervalId = setInterval(incrementNumber, 500);
在這個例子中幅狮,變量num每半秒鐘遞增一次募强,當遞增到最大值時就會取消先前設定的間歇調用株灸。這個模式也可以使用超時調用來實現(xiàn),如下所示擎值。
var num = 0;
var max = 10;
function incrementNumber() {
num++;
// 如果執(zhí)行次數(shù)未達到max設定的值慌烧,則設置另一次超時調用
if (num < max) {
setTimeout(incrementNumber, 500);
} else {
console.log("Done");
}
}
setTimeout(incrementNumber, 500);
可見,在使用超時調用時鸠儿,沒有必要跟蹤超時調用 ID
屹蚊,因為每次執(zhí)行代碼之后,如果不再設置另一次超時調用进每,調用就會自行停止汹粤。一般認為,使用超時調用來模擬間歇調用的是一種最佳模式田晚。在開發(fā)環(huán)境下嘱兼,很少使用真正的間歇調用,原因是后一個間歇調用可能會在前一個間歇調用結束之前啟動贤徒。而像前面示例中那樣使用超時調用芹壕,則完全可以避免這一點。所以接奈,最好不要使用間歇調用踢涌。
系統(tǒng)對話框
瀏覽器通過 alert()
、confirm()
和 prompt()
方法可以調用系統(tǒng)對話框向用戶顯示消息序宦。系統(tǒng)對話框與在瀏覽器中顯示的網(wǎng)頁沒有關系睁壁,也不包含 HTML。它們的外觀由操作系統(tǒng)及(或)瀏覽器設置決定挨厚,而不是由 CSS 決定堡僻。此外,通過這幾個方法打開的對話框都是同步和模態(tài)的疫剃。也就是說钉疫,顯示這些對話框的時候代碼會停止執(zhí)行,而關掉這些對話框后代碼又會恢復執(zhí)行巢价。
第一種對話框是調用 alert()
方法生成的牲阁。它向用戶顯示一個系統(tǒng)對話框,其中包含指定的文本和一個 OK(“確定”)按鈕壤躲。通常使用 alert()
生成的“警告”對話框向用戶顯示一些他們無法控制的消息城菊,例如錯誤消息。而用戶只能在看完消息后關閉對話框碉克。
第二種對話框是調用 confirm()
方法生成的凌唬。從向用戶顯示消息的方面來看,這種“確認”對話框很像是一個“警告”對話框漏麦。但二者的主要區(qū)別在于“確認”對話框除了顯示OK按鈕外客税,還會顯示一個 Cancel(“取消”)按鈕况褪,兩個按鈕可以讓用戶決定是否執(zhí)行給定的操作。
為了確定用戶是單擊了OK還是Cancel更耻,可以檢查 confirm()
方法返回的布爾值:true
表示單擊了OK测垛,false
表示單擊了Cancel或單擊了右上角的 X 按鈕。確認對話框的典型用法如下秧均。
if (confirm("Are you sure?")) {
alert("I'm so glad you're sure! ");
} else {
alert("I'm sorry to hear you're not sure.");
}
最后一種對話框是通過調用 prompt()
方法生成的食侮,這是一個“提示”框,用于提示用戶輸入一些文本目胡。提示框中除了顯示 OK 和 Cancel 按鈕之外锯七,還會顯示一個文本輸入域,以供用戶在其中輸入內容讶隐。prompt()
方法接受兩個參數(shù):要顯示給用戶的文本提示和文本輸入域的默認值(可以是一個空字符串)起胰。
如果用戶單擊了 OK 按鈕久又,則 promp()
返回文本輸入域的值巫延;如果用戶單擊了 Cancel 或沒有單擊 OK 而是通過其他方式關閉了對話框,則該方法返回 null
地消。下面是一個例子炉峰。
var result = prompt("What is your name? ", "");
if (result !== null) {
alert("Welcome, " + result);
}
綜上所述,這些系統(tǒng)對話框很適合向用戶顯示消息并請用戶作出決定脉执。由于不涉及 HTML疼阔、CSS 或 JavaScript,因此它們是增強 Web 應用程序的一種便捷方式半夷。
location
對象
location
對象提供了與當前窗口中加載的文檔有關的信息婆廊,還提供了一些導航功能。事實上巫橄,location
對象是很特別的一個對象淘邻,因為它既是 window
對象的屬性,也是 document
對象的屬性湘换;換句話說宾舅,window.location
和 document.location
引用的是同一個對象。location
對象的用處不只表現(xiàn)在它保存著當前文檔的信息彩倚,還表現(xiàn)在它將 URL 解析為獨立的片段筹我,讓開發(fā)人員可以通過不同的屬性訪問這些片段。下表列出了 location
對象的所有屬性帆离。
屬性名 | 例子 | 說明 |
---|---|---|
hash | "#contents" | 返回 URL 中的 hash(#號后跟零或多個字符)蔬蕊,如果 URL 中不包含散列,則返回空字符串 |
host | "shijiajie.com:80" | 返回服務器名稱和端口號(如果有) |
hostname | "shijiajie.com" | 返回不帶端口號的服務器名稱 |
href | "http:/shijiajie.com" | 返回當前加載頁面的完整URL哥谷。而 location 對象的 toString() 方法也返回這個值 |
pathname | "/WileyCDA/" | 返回URL中的目錄和(或)文件名 |
port | "8080" | 返回 URL 中指定的端口號岸夯。如果 URL 中不包含端口號概而,則這個屬性返回空字符串 |
protocol | "http:" | 返回頁面使用的協(xié)議。通常是 http: 或 https: |
search | "?q=javascript" | 返回URL的查詢字符串囱修。這個字符串以問號開頭 |
查詢字符串參數(shù)
雖然通過上面的屬性可以訪問到 location
對象的大多數(shù)信息赎瑰,但其中訪問URL包含的查詢字符串的屬性并不方便。盡管 location.search
返回從問號到 URL 末尾的所有內容破镰,但卻沒有辦法逐個訪問其中的每個查詢字符串參數(shù)餐曼。為此,可以像下面這樣創(chuàng)建一個函數(shù)鲜漩,用以解析查詢字符串源譬,然后返回包含所有參數(shù)的一個對象:
/*
* 這個函數(shù)用來解析來自URL的查詢串中的name=value參數(shù)對
* 它將name=value對存儲在一個對象的屬性中,并返回該對象
* 這樣來使用它
*
* var args = urlArgs(); // 從URL中解析參數(shù)
* var q = args.q || ""; // 如果參數(shù)定義了的話就使用參數(shù)孕似;否則使用一個默認值
* var n = args.n ? parseInt(args.n) : 10;
*/
function urlArgs() {
var args = {}; // 定義一個空對象
var query = location.search.substring(1); // 查找到查詢串踩娘,并去掉'? '
var pairs = query.split("&"); // 根據(jù)"&"符號將查詢字符串分隔開
for (var i = 0; i < pairs.length; i++) { // 對于每個片段
var pos = pairs[i].indexOf('='); // 查找"name=value"
if (pos == -1) continue; // 如果沒有找到的話,就跳過
var name = pairs[i].substring(0, pos); // 提取name
var value = pairs[i].substring(pos + 1); // 提取value
value = decodeURIComponent(value); // 對value進行解碼
args[name] = value; // 存儲為屬性
}
return args; // 返回解析后的參數(shù)
}
位置操作
使用 location
對象可以通過很多方式來改變?yōu)g覽器的位置喉祭。首先养渴,也是最常用的方式,就是使用 assign()
方法并為其傳遞一個 URL泛烙,如下所示理卑。
location.assign("http://shijiajie.com");
這樣,就可以立即打開新URL并在瀏覽器的歷史記錄中生成一條記錄蔽氨。如果是將 location.href
或 window.location
設置為一個URL值藐唠,也會以該值調用 assign()
方法。例如鹉究,下列兩行代碼與顯式調用 assign()
方法的效果完全一樣宇立。
window.location = "http://shijiajie.com";
location.;
在這些改變?yōu)g覽器位置的方法中,最常用的是設置 location.href
屬性自赔。
另外妈嘹,修改 location
對象的其他屬性也可以改變當前加載的頁面。下面的例子展示了通過將 hash
匿级、search
蟋滴、hostname
、pathname
和 port
屬性設置為新值來改變 URL痘绎。
// 假設初始 URL 為 http://shijiajie.com/about/
location.
// 將 URL 修改為 "http://shijiajie.com/about/#ds-thread"
location.hash = "#ds-thread";
// 將 URL 修改為 "http://shijiajie.com/about/?args=123"
location.search = "?args=123";
// 將 URL 修改為 "https://segmentfault.com/"
location.hostname = "segmentfault.com";
// 將 URL 修改為 "http://segmentfault.com/u/stone0090/"
location.pathname = "u/stone0090";
// 將 URL 修改為 "https://segmentfault.com:8080/"
location.port = 8080;
當通過上述任何一種方式修改URL之后津函,瀏覽器的歷史記錄中就會生成一條新記錄,因此用戶通過單擊“后退”按鈕都會導航到前一個頁面孤页。要禁用這種行為尔苦,可以使用 replace()
方法。這個方法只接受一個參數(shù),即要導航到的 URL允坚;結果雖然會導致瀏覽器位置改變魂那,但不會在歷史記錄中生成新記錄。在調用 replace()
方法之后稠项,用戶不能回到前一個頁面涯雅,來看下面的例子:
<!DOCTYPE html>
<html>
<head>
<title>You won't be able to get back here</title>
</head>
<body>
<p>Enjoy this page for a second, because you won't be coming back here.</p>
<script type="text/javascript">
setTimeout(function () {
location.replace("http://shijiajie.com/");
}, 1000);
</script>
</body>
</html>
如果將這個頁面加載到瀏覽器中,瀏覽器就會在1秒鐘后重新定向到 shijiajie.com
展运。然后活逆,“后退”按鈕將處于禁用狀態(tài),如果不重新輸入完整的 URL拗胜,則無法返回示例頁面蔗候。
與位置有關的最后一個方法是 reload()
,作用是重新加載當前顯示的頁面埂软。如果調用 reload()
時不傳遞任何參數(shù)锈遥,頁面就會以最有效的方式重新加載。也就是說勘畔,如果頁面自上次請求以來并沒有改變過所灸,頁面就會從瀏覽器緩存中重新加載。如果要強制從服務器重新加載咖杂,則需要像下面這樣為該方法傳遞參數(shù) true
庆寺。
location.reload(); // 重新加載(有可能從緩存中加載)
location.reload(true); // 重新加載(從服務器重新加載)
位于 reload()
調用之后的代碼可能會也可能不會執(zhí)行,這要取決于網(wǎng)絡延遲或系統(tǒng)資源等因素诉字。為此,最好將 reload()
放在代碼的最后一行知纷。
history
對象
history
對象保存著用戶上網(wǎng)的歷史記錄壤圃,從窗口被打開的那一刻算起。因為 history
是 window
對象的屬性琅轧,因此每個瀏覽器窗口伍绳、每個標簽頁乃至每個框架,都有自己的 history
對象與特定的 window
對象關聯(lián)乍桂。出于安全方面的考慮冲杀,開發(fā)人員無法得知用戶瀏覽過的 URL。不過睹酌,借由用戶訪問過的頁面列表权谁,同樣可以在不知道實際 URL 的情況下實現(xiàn)后退和前進。
使用 go()
方法可以在用戶的歷史記錄中任意跳轉憋沿,可以向后也可以向前旺芽。這個方法接受一個參數(shù),表示向后或向前跳轉的頁面數(shù)的一個整數(shù)值。負數(shù)表示向后跳轉(類似于單擊瀏覽器的“后退”按鈕)采章,正數(shù)表示向前跳轉(類似于單擊瀏覽器的“前進”按鈕)运嗜。來看下面的例子。
// 后退一頁
history.go(-1);
// 前進一頁
history.go(1);
// 前進兩頁
history.go(2);
也可以給 go()
方法傳遞一個字符串參數(shù)悯舟,此時瀏覽器會跳轉到歷史記錄中包含該字符串的第一個位置——可能后退担租,也可能前進,具體要看哪個位置最近抵怎。如果歷史記錄中不包含該字符串翩活,那么這個方法什么也不做,例如:
// 跳轉到最近的 shijiajie.com 頁面
history.go("shijiajie.com");
另外便贵,還可以使用兩個簡寫方法 back()
和 forward()
來代替 go()
菠镇。顧名思義,這兩個方法可以模仿瀏覽器的“后退”和“前進”按鈕承璃。
// 后退一頁
history.back();
// 前進一頁
history.forward();
除了上述幾個方法外利耍,history
對象還有一個 length
屬性,保存著歷史記錄的數(shù)量盔粹。這個數(shù)量包括所有歷史記錄隘梨,即所有向后和向前的記錄。對于加載到窗口舷嗡、標簽頁或框架中的第一個頁面而言轴猎,history.length
等于0。通過像下面這樣測試該屬性的值进萄,可以確定用戶是否一開始就打開了你的頁面捻脖。
if (history.length == 0){
//這應該是用戶打開窗口后的第一個頁面
}
雖然 history
并不常用,但在創(chuàng)建自定義的“后退”和“前進”按鈕中鼠,以及檢測當前頁面是不是用戶歷史記錄中的第一個頁面時可婶,還是必須使用它。
小結
BOM(瀏覽器對象模型)以 window
對象為依托援雇,表示瀏覽器窗口以及頁面可見區(qū)域矛渴。同時,window
對象還是 ECMAScript 中的 Global
對象惫搏,因而所有全局變量和函數(shù)都是它的屬性具温,且所有原生的構造函數(shù)及其他函數(shù)也都存在于它的命名空間下。本章討論了下列 BOM 的組成部分筐赔。
- 在使用框架時铣猩,每個框架都有自己的
window
對象以及所有原生構造函數(shù)及其他函數(shù)的副本。每個框架都保存在frames
集合中川陆,可以通過位置或通過名稱來訪問剂习。 - 有一些窗口指針蛮位,可以用來引用其他框架,包括父框架鳞绕。
-
top
對象始終指向最外圍的框架失仁,也就是整個瀏覽器窗口。 -
parent
對象表示包含當前框架的框架们何,而self
對象則回指window
萄焦。 - 使用
location
對象可以通過編程方式來訪問瀏覽器的導航系統(tǒng)。設置相應的屬性冤竹,可以逐段或整體性地修改瀏覽器的 URL拂封。 - 調用
replace()
方法可以導航到一個新 URL,同時該 URL 會替換瀏覽器歷史記錄中當前顯示的頁面鹦蠕。 -
navigator
對象提供了與瀏覽器有關的信息冒签。到底提供哪些信息,很大程度上取決于用戶的瀏覽器钟病;不過萧恕,也有一些公共的屬性(如userAgent
)存在于所有瀏覽器中。
BOM中還有兩個對象:screen
和 history
肠阱,但它們的功能有限票唆。screen
對象中保存著與客戶端顯示器有關的信息,這些信息一般只用于站點分析屹徘。history
對象為訪問瀏覽器的歷史記錄開了一個小縫隙走趋,開發(fā)人員可以據(jù)此判斷歷史記錄的數(shù)量,也可以在歷史記錄中向后或向前導航到任意頁面噪伊。
關卡
// 挑戰(zhàn)一
setTimeout(function () {
console.log("1");
}, 0)
console.log("2"); // ???
// 挑戰(zhàn)二
for (var i = 0;i<5;i++) {
setTimeout(function () {
console.log(i); // ???
}, 0)
};
// 挑戰(zhàn)三
var a = 1;
var obj = {
a : 2,
b : function(){
setTimeout(function () {
console.log(this.a);
}, 0)
}
}
obj.b(); // ???
// 挑戰(zhàn)四
var a = 1;
var obj = {
a : 2,
b : function(){
setTimeout(function () {
console.log(this.a);
}.call(this), 0);
}
}
obj.b(); // ???
更多
關注微信公眾號「劼哥舍」回復「答案」簿煌,獲取關卡詳解。
關注 https://github.com/stone0090/javascript-lessons酥宴,獲取最新動態(tài)啦吧。