第十一章介紹了window對象及其客戶端javascript所扮演的核心角色:它是客戶端javascript程序的全局對象。本章介紹window對象的屬性和方法,這些屬性定義了不一樣的API,可是隻有一部分實際上和瀏覽器窗口相關。window對象是以窗口命名的。javascript
1節展現如何使用setTimeout()和setInterval()來註冊一個函數,並在指定的時間後調用它。html
2節講述如何使用location屬性來獲取當前顯式文檔的URL和載入新的文檔html5
3節介紹history屬性,並展現如何在歷史記錄中向前和向後移動java
4節展現如何使用navigator獲取瀏覽器的廠商和版本信息,如何使用screen屬性來查詢窗口的尺寸web
5節展現如何使用alert()、prompt()、confirm()來顯示簡單的文本對話框,以及如何使用showModalDialog()顯示HTML對話框正則表達式
6節講解如何使用onerror處理方法,這個方法在未補貨javascript異常發生時調用chrome
7節講述HTML元素的ID和name做爲window對象的屬性來使用小程序
8是一個很長的節,講解如何打開和關閉瀏覽器。以及如何編寫在多個窗口和嵌套窗體中的javascript 代碼數組
1.計時器瀏覽器
setTimeout()和setIterval()能夠用來註冊在指定的時間以後,單詞或重複調用的函數。由於它們都是客戶端javascript中的重要全局函數,因此定義爲window對象方法,但做爲通用函數,其實並不會對窗口作什麼事情。
window對象的setTimeout()方法用來實現一個函數在指定的毫秒後運行。setTimeout返回一個值,這個值能夠傳給clearTimeout()用於取消這個函數的執行。
SetInterval()和setTimeout()同樣,只不過這個函數會在指定的毫秒數的間隔裏重複調用:
setInterval(updataClock,60000);//,每隔60秒調用一次updataClock函數
和setTimeout()同樣,setInterval()函數也返回一個值,這個值能夠傳遞給clearInterval(),用於取消後續函數的調用。
下面的例子定義的函數會在指定的時間以後,開始重複調用某個函數,而後在過了一段時間後取消函數的調用。該例子演示了setTimeout、setInterval、clearInterval的用法
/**定時器應用函數 * 安排函數f()在將來的調用模式 * 在等待了若干時間後調用f() * 若是設置了interval並無設置end參數,則f()的調用不會中止 * 只有制定了f(),纔會從start=0時刻開始 * 注意,調用invoke()不會阻塞,會當即返回 * */ function invoke(f, start, interval, end) { if (!start) start = 0;//默認設置爲0 if(arguments.length <=2)//單次調用模式 setTimeout(f,start);//start秒後調用f else{ setTimeout(repeat,start);//若干秒後調用f() function repeat(){ var h = setInterval(f,interval);//循環調用f() //在end結束後調用,嵌套是end已經定義了 if(end) setTimeout(function(){clearInterval(h);},end); } } }
一個簡單的定時器函數
var Obj = function(msg) { this.msg = msg; this.shout = function() { alert(this.msg); } this.waitAndShout = function() { var owner = this; setTimeout(function() { owner.shout.call(owner); }, 2000); } } var aa = new Obj("abc"); aa.waitAndShout();
因爲歷史緣由,setTimeout()和setInterval()第一個參數能夠做爲字符串傳入。若是這麼作,那這個字符串會在指定的超時時間或間隔以後求值(至關於執行eval()).除了前兩個參數以外,HTML5規範還容許setTimeout()和setInterval()傳入額外的參數,而且在調用函數的時候把這些參數傳過去。
若是以0毫秒時間調用setTimeout,那麼指定的函數不會馬上執行。相反會把它放到隊裏中,等到前面處於等待狀態的事件處理程序徹底完成以後,再馬上調用它。
2.瀏覽器的定位和導航
window對象的location屬性引用的是Location對象,它表示該窗口中當前文檔的URL,並定義了方法使創口引用到Location對象。
window.location === document.location; //=>true 老是返回true
Document對象也有一個URL屬性,是文檔首次載人後保存該文檔的URL靜態字符串。若是定位到文檔中的片斷標識符(如#table-of-contens),Location對象會作響應更新,而document.url屬性卻不會改變。
i.解析url
window對象的location屬性引用是Location對象,表示當前顯示的的文檔的URL。Location對象的href屬性是一個字符串。Location對象的toString()方法返回href屬性的值,所以會在隱式調用toString()狀況下,使用location代替Location.href
var d = location.href; var c = location.toString(); console.log(d === c)
這個對象的其它屬性,protocol,host,hostname,port,pathname和search分別表示URL的各個部分。它們稱爲"URL分解",同時被Link對象(經過HTML文檔中的a和<area>元素建立)支持,參閱本書的第四部分,Location和Link項獲取詳細信息。
Location對象的hash和seerch比較有意思。hash表示URL中的「片斷標識符 #xx」部分,search返回問好以後的URL,這部分通常是某種類型的查詢字符串。
下面的例子展現了一個通用函數urlArgs()定義,能夠用這個函數將參數從URL的search屬性中提取出來。該例子用到了decodeURIComponent(),後者是在客戶端Javascript定義的全局函數(參加本書第三章部分中的Global獲取詳細內容)。
/** *這個函數來解析來自URL的查詢中串中的name=value參數 * 它將name=value對象存儲在一個對象的屬性中,並返回該對象,這樣使用它 * * var args = urlArgs();//從URL中解析參數 * var q = args.q ||"";//若是參數定義的話就使用它,不然使用默認值。 * var n = args.n?parseInt(args.n):10 **/ function urlArgs() { var args = {}; //空對象 var query = location.search.substring(1); //?後的值 var pairs = query.split("&"); for (var i = 0; i < pairs.length; i++) { //對於每一個片斷 var pos = pairs[i].indexOf('='); 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; }
ii.載入新的文檔
Location對象的assign()方法可使窗口載入並顯示你指定的url文檔。replace()方法也相似,但它在載入新的文檔以前會從瀏覽歷史把當前文檔刪除。若是腳本無條件的載入一個新的文檔,replace()方法是可能比assgin()方法更好的選擇。不然,後退 按鈕會使用瀏覽器帶回原始文檔。而相同的腳本則會再次載入新文檔。若是檢測到用戶瀏覽器不支持某些特性來顯示功能齊全的版本,能夠這樣作:
//若是瀏覽器不支持XMLHttpRequest對象 //則將其重定向到一個不須要Ajax的靜態頁面 if (XMLHttpRequest) location.replace("aa.html");
除了assign()和replace()方法,Location對象還定義了reload()方法,後者可讓瀏覽器從新載入當前文檔。
傳統的方法通常是這樣作
location = "http://a.com";
location = "page.html";
純粹的片斷標識符也是url的一種類型,能夠這樣定義
location = "http://a.com#cll";
location = "page.html#top";
Location對象的URL是可寫的,對它們從新賦值會改變URL的位置,致使瀏覽器載入新的文檔(若是是hash屬性,則定位到片斷標識符)
location.search = "?page=" + (pagename+1);//載入新的頁面
3.瀏覽歷史
window對象的history屬性是引用該窗口的History對象。History對象是用來把窗口的瀏覽歷史用文檔和文檔狀態列表的形式表示。History對象的length屬性表示瀏覽意思列表的數量元素,處於安全考慮,腳本不能訪問已經保存的URL.
history對象的back()和forward()方法與瀏覽器的「後退」和「前進」按鈕同樣。它們能夠往先後跳轉一格,第三個方法go(),接受一個參數,能夠像前(正參數)向後(幅參數)跳過任意個頁面。
history.go(-2); //向後兩個歷史記錄,至關於後退按鈕兩次
若是窗口包含多個子窗口(好比iframe見本文8.ii節),子窗口的歷史會按照穿插主窗口的歷史中。
現代的web應用能夠不經過載入新的文檔而動態的改變自身內容。這麼作但願用戶能用「後退」和「前進」按鈕在這些動態建立應用狀態之間跳轉。html5將這些技術標準(18章2節)。
在現實的工做中,那些須要之前的HTML5歷史管理項目中,開發者會使用一些現成 解決方法(由於以前歷史管理是個複雜的難題),不少框架都實現了這些功能。例如jQuery的history插件。也有一些單獨的類庫。RSH(Really Simple History)是其中一個比較流行的示例。(20章2節會有關於html5的歷史管理)
4.瀏覽器和屏幕信息
本節介紹window對象的navigator和screen屬性,它們分別引用的是Navigator和Screen對象,這些對象信息容許腳本根據環境定製的行爲。
瀏覽器有必定的嗅探價值。這樣的一種狀況是,當須要解決某個瀏覽器特定的bug時,Navugator對象有4個屬性提供關於運行中的瀏覽器的版本信息。並可使用這些屬性就行嗅探。
i.Nagvigator
appName
web瀏覽器的全稱,IE中,它顯示「Microsoft Internet Exploer」.在firefox中,該屬性就是「Netscape」,在其它瀏覽器中也是(爲了兼容如今的瀏覽器嗅探碼)。
appVersion
此屬性一般以數字開始,並跟隨瀏覽器開發商和版本信息等詳細字符串。字符串的前邊一般是4.0或者5.0,表示它是第4仍是第5代兼容的瀏覽器。appVersion沒有標準格式。全部沒有辦法判斷瀏覽器的類型
userAgent
瀏覽器在它的User-Agent HTTP頭部發送的字符串。這個屬性一般包含全部appVersion信息,而且經常包含其它細節。和appVersion同樣,它也沒有標準格式。因爲這個屬性包含絕大部分信息,所以,瀏覽器嗅探代碼一般使用它。
platform
在其上運行的瀏覽器的操做系統(多是硬件的字符串)。
下面的例子展現了使用正則表達式(來自jQuery)從navigator.userAgent抽取瀏覽器的版本和名稱方法代碼。
/* 使用naVigator.userAgent來進行瀏覽器嗅探 */ //爲客戶端嗅探定義browser.name和browser.version,這裏使用了jQuery1.41的代碼 //name和number都是字符串,對瀏覽器的輸出結果不同,檢測的結果以下 //'webkit':safari或chrome,版本號是WebKit的版本號 //'opera' Opear 版本號就是軟件的把嫩好 //"mozilla" Firefox或者基於gecko內核的瀏覽器,版本號是Gecko的版本 //msie IE+版本號 var browser = (function() { var s = navigator.userAgent.toLowerCase(); var match = /(webkit)[ \/]([\w.]+)/.exec(s) || /(opera)(?:.*version)?[ \/]([\w.]+)/.exec(s) || /(msie)([\w.]+)/.exec(s) || !/compatible/.test(s) && /(mozilla)( ? : .* ? rv : ([\w.] + )) ? /.exec(s)||[]; return{name:match[1]||"",version:match[2]||"0"}; }());
另一種
var info = {}; info.browser = function() { ua = navigator.userAgent.toLowerCase(); var rwebkit = /(webkit)[ \/]([\w.]+)/; var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/; var rmsie = /(msie) ([\w.]+)/; var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/; var match = rwebkit.exec(ua) || ropera.exec(ua) || rmsie.exec(ua) || ua.indexOf("compatible") < 0 && rmozilla.exec(ua) || []; return { name: match[1] || "", version: match[2] || "0" }; }(); console.log(info.browser)
處理瀏覽器廠商和版本信息的屬性以外,Navigator對象還包含一些雜項屬性和方法。如下是一些標準化的屬性以及普遍應用但未標準的屬性
OnLine
navigator.onLine是表示是否瀏覽器是否鏈接到網絡
geolocation
navigator.geolocation對象擁有肯定用戶地址位置信息的接口,參加20.1章節細節
javaEnabled
navigator.javaEnabled是一個非標準的方法,當瀏覽器能運行java小程序時返回true
cookieEnabled
navigator.cookieEnabled也是一個非標準方法,若是瀏覽器能夠永久保存cookie時,返回true,而cookie配置「視具體狀況而定」時,可能不返回正確的值。
ii.Screen對象。
window對象的screen屬性。它提供有關窗口的大小和可用顏色的數量和信息。屬性width和heigth指定是以小蘇爲單位的窗口大小,屬性availWidth和availHeiht指是實際可用的顯示大小。屬性colorDepth是值顯示的BPP值,典型的值有16,24,32
window.screen屬性和它引用的screen對象都是非標準但普遍實現的。可用用screen對象來肯定web是否運行在一個小的屏幕設備上,若是屏幕有限,是否要選用更小的字體和圖片等。
5.對話框
window對象提供了三個方法向用戶顯示簡單點對話框,alert(),confirm()要求用戶單擊肯定或取消,返回一個布爾值,prompt()一樣也顯示一條消息,等待用戶輸入字符串,並返回那個字符串。下面的代碼全用了這三種方法:
do { var name = prompt("你的名字"); var correct = confirm("你輸入了" + name + "\n" + "oK確認,chancel取消"); } while (!correct) alert("hello" + name);
儘管alert(),confirm()和prompt()都容易使用,可是良好的設計都須要有節制的使用它們。現在,惟一常見的就是使用它們調試,查看變量輸出的結果是什麼。
注意,這些對話框中顯示的文本是純文本,只能使用空格,換行符和各類標點符號來格式化這些對話框。
confirm()和prompt()都會產生阻塞,也就是說再關掉它們所顯示的對話框以前,它們不返回,也會中止載入,知道用戶響應位置。大多數瀏覽器裏,alert()也會產生阻塞,等待用戶關閉關閉對話框,但不老是這樣,完整的的細節請參考第四部分的Window.alert()/Window.confirm()、和window.prompt()方法。
除了window的alert()、confirm()和prompt()方法,還有更復雜的方法showModalDialog(),顯示一個包含HTML格式的模態對話框(模態對話框就是彈出來後只能點擊當前的對話框的內容,底下的頁面不能操做)。當窗口關閉後,window.returnValue屬性的值就是此方法的返回值。對話框的HTML內容每每必須包含用來設置returnValue的「確認」按鈕,若是須要則調用window.close(12.8.i)
下面的例子是一個適用於showModalDialog()的html文件,代碼頂部註釋包含了showModalDialog()的樣例。對話框裏顯示的大量文本都來自showModalDialog()第二個參數,而不是寫死在html中。
<!-- /*使用showModalDialog()方法來顯示出對話框*/ 這個html不是獨立的,這個文件由showModalDialog()調用 它但願window.dialogArguments是一個由字符串組成的數組,數組的一個元素放在對話框的頂部,剩下的每一個元素是每行的輸入框的標識 當單擊肯定時,返回一個數組,這個數組是每一個輸入框的值組成 使用這樣的代碼開肯定: var p = showModalDialog("multiprompt.html", ["請輸入3d座標","x","y","z"], "dialogwidth:400;dialogheight:300;resizable:yes"); --> <form> <fieldset id="fields"></fieldset> <!--對話框正文部分--> <div style="text-align: center;"> <button onclick="okay()">肯定</button> <!--設置返回值和關閉事件--> <button onclick="cancel()">取消</button> <!--關閉時不帶任何返回值--> </div> <script type="text/javascript"> //建立對話框主題部分,在fieldset中顯示出來 var args = dialogArguments; var text = "<legend>" + args[0] + "</legend>"; for (var i = 1; i < args.length; i++) text += "<label>" + args[i] + ":<input id = 'f" + i + "'></label><br>"; document.getElementById("fields").innerHTML = text; //直擊關閉這個對話框,不設置返回值 function cancel() { window.close(); } //讀取輸入框的值,而後設置一個返回值,以後關閉 function okay() { window.returnValue = []; //返回一個數組 for (var i = 1; i < args.length; i++) //設置輸入框的元素 window.returnValue[i - 1] = document.getElementById("f" + i).value; window.close(); //關閉對話框,使用showModealDialog()返回 } </script> <form>
6.錯誤處理
window對象對象的onerror屬性是一個事件處理程序,當未捕獲的異常傳播到調用棧上時就會調用它,並把錯誤消息輸出到瀏覽器的javascript控制檯上。若是給這個屬性賦值一個函數,那麼只要這個窗口中發生了javascript錯誤,就會調用該函數,即它成爲了窗口的錯誤處理程序。
因爲歷史緣由,事件處理函數調用經過三個字符串參數,而不是經過傳遞一個事件對象。(其它客戶端對象的onerror處理程序所須要的錯誤條件是不同的,可是它們都是正常的事件處理程序,這個函數只需傳入一個事件對象。)window.onerror的第一個參數是描述錯誤的一條消息。第二個參數是一個字符串,它存放引起錯誤的javascript代碼所在文檔的 url.第三個參數是引起錯誤的行數。
除了這三個參數外,onerror處理程序的返回值也很重要。若是onerror處理程序返回false,它通知瀏覽器事件程序已經處理了錯誤,不須要其餘操做。換句話說,瀏覽器不該該顯示它本身的錯誤消息。因爲歷史緣由,Firefox裏的錯誤程序必須返回true表示它已經處理了錯誤
onerror處理程序是很早期的javascript產物,那時候語言核心不包含try/catch異常處理語句。如今的代碼已經不多使用它。可是在開發階段,你可能須要定義一個錯誤處理程序,當錯誤發生時,顯式的通知本身。
window.onerror = function(msg, url, line) { alert("出錯了:\n" + msg + "\n 地址:" + url + "\n行號:" + line); return true; //屏蔽系統事件 }
7.做爲window對象屬性的文檔元素
若是在HTML文檔中使用id屬性來爲元素命名,而且若是window對象沒有此名字的屬性,window對象會賦予一個屬性,它的名字是id屬性的值,而他們指向表示文檔元素的HTMLElement對象。
客戶端javascript中,window對象是以全局對象的形式存在與做用域鏈上層,這就意味着在html文檔中使用的id屬性會成爲被腳本訪問的全局變量。若是一個文檔包含<button id="okay"></button>元素,能夠經過全局變量okay引用此元素。
可是:有一個很重要的警告!: 若是window對象已經具備此名字的屬性 ,這就不會發生。好比id是history,location或navigator的元素,就不會以全局變量的形式出現。由於這些id已經被佔用了。一樣,若是html文檔包含一個id爲「x」的元素,而且還在膽碼中聲明並賦值給全局變量x,那麼顯式的聲明的變量會隱藏隱式的元素變量。在腳本中的變量聲明出如今命名元素以前,那這個變量的存在就會阻止元素獲取它的window屬性。而若是腳本中的變量聲明出如今命名元素以後,那麼變量的顯式賦值就會覆蓋該屬性的隱式值。
13章2節中,你會經過document,getElementById()方法,用HTML的id屬性來查找文檔元素。見下面的例子:
var ui = ["input", "prompt", "heading"]; //數組中存放要查找的元素id ui.forEach(function(id) { //用每一個id查找對於的元素 ui[id] = document.getElementById(id); //將其存放在一個屬性中 });
運行完這段代碼以後,ui.input,ui.prompt和ui.heading會引用文檔元素。腳本能夠用全局變量input和heading來代替ui.input和ui.heading
但記得12.5節裏window對象有個方法的名字是prompt(),所用腳本中不能用全局變量prompt代替ui.prompt.
元素的id做爲全局變量的隱式應用是web瀏覽器演化過程當中遺留的怪癖。它主要是出於與已有web頁面向後兼容性的考慮。但這裏並不推薦這種作法---瀏覽器廠商能夠在任什麼時候候爲window對象定義新屬性,而這些新屬性都會破壞使用了此屬性名的隱式定義的代碼。反之,用document.getElementById()來顯式查找元素,若是給他一個更簡單的名字,這種用法會更加簡單:
var $ = function(id) { return document.getElementById(id); }; ui.prompt = $("prompt")
不少客戶端類庫都定義了$函數,相似上面同樣經過id來查找元素。(17章內爲jQuery的$函數爲通用的元素選擇方法,基於id,標籤名,class屬性或其它標準,返回一個或多個元素)
假設ID並無被window對象使用的話,那麼任何有id屬性的html元素都會變成全局變量的值。如下HTML元素若是有name屬性的話,也會這樣表現:
<a> <applet> <area> <embed> <form> <frame> <frameset> <img> <object>
id元素在文檔中必須是惟一的,兩個元素不能有相同的id。可是這對name屬性無效。若是上面的元素有多於一個相同的name屬性(或者一個元素有name屬性,而另一個元素有相同值的id屬性),具備該名稱的隱式全局變量會引用一個類數組對象,這個類數組對象的元素是全部命名的元素。
有name或id屬性的<iframe>元素是個特殊的例子。爲它們隱式建立的變量不會引用表示元素自身的Element對象,而是引用表示<iframe>元素建立的嵌套的window對象。本文8.ii會討論到它。
8.多窗口和窗體
一個web頁面窗口可能在桌面上包含多個標籤頁。每個標籤 頁都是獨立的「瀏覽上下文」(browsing context),每個上下文都有獨立的window對象,並且相互之間互不干擾。每一個標籤頁中運行的腳本一般並不知道其它標籤頁的存在,更不用說和其餘標籤也的window對象進行交互操做或者操做其文檔內容了。若是web瀏覽器不支持多標籤頁或者把標籤頁關掉了,可能某一刻桌面上有不少打開的瀏覽器窗口。而使用標籤頁,每一個窗口中的window對象都是獨立的,也就是說彼此就是徹底獨立的和其它桌面窗口沒有關係。
可是窗口不老是和其它窗口徹底沒有關係。一個窗口或標籤頁中的腳本能夠打開新的窗口或標籤頁,當一個腳本這樣作時,多個窗口或窗口與另外一個窗口文檔之間就能夠互操做。(11.6.ii講解的同源策略約束)。本節i小節會介紹窗口的打開和關閉的更多內容。
html文檔常用<iframe>來嵌套多個文檔。由它所建立的嵌套瀏覽上下文是用它本身的window對象所表示的。廢棄的<frameset>和<frame>元素一樣建立了嵌套瀏覽的上下文。每個<frame>都有獨立的window對象表示。對於客戶端javascript來講,窗口、標籤頁、iframe和框架都是獨立的瀏覽上下文。對於javascript來講,它們都是window對象。和相互獨立的標籤頁不一樣,嵌套的瀏覽上下文之間並非相互獨立的。在一個窗體中運行javascript程序老是能看見它的祖先和子孫窗體,儘管腳本查看這些窗體中的文檔受到同源策略限制。
由於window是客戶端javascript的全局對象,每一個窗口或窗體都包含堵路的javascript執行上下文。不過在一個窗口中的javascript代碼,若有同源策略的限制,則可使用另一個窗口中定義的對象、屬性和方法。與此相關的細節會在本節iii節詳細討論。因爲同源策略的限制致使窗口之間無縫直接交互時,html5提供了一個機遇消息傳輸的API,能夠用於間接通訊。20章3節會討論。
i.打開和關閉窗口
使用window對象的open()方法能夠打開一個新的瀏覽器窗口(或標籤頁,這一般和瀏覽器的配置項有關)。window.open()載入指定的url到新的活已存在的窗口中,並返回那個窗口的window對象。它有四個可選的參數。
open()第一個參數是要在新窗口打開文檔的url。若是省略(也能夠是空字符串),那麼會使用頁面的URLabout:blank
opne()第二個參數是新打開窗口的名。若是指定的是一個以及存在的窗口的名字(而且腳本容許跳轉到那個窗口),會直接使用已經存在的窗口。不然,會打開新的窗口,並將這個指定的名字賦值給它。若是省略此參數,會使用指定的名字「_blank」打開新的、爲命名的窗口。
須要注意的是,腳本是沒法經過簡單的猜想窗口的名字來控制操縱這個窗口中的web應用的,只有設置了「容許導航」(allowed to navigte)(html5規範術語)的頁面才能夠這樣。寬泛的講,當且僅當窗口包含的文檔來自相同的源或者是這個腳本打開了那個窗口(或者是遞歸地打開了窗口中打開的窗口),腳本才能夠經過名字來指定存在的窗口。還有,若是其中一個窗口是內嵌在另外一個窗口的裏的窗體,那麼它們的腳本直接就能夠相互導航。在這種狀況下,可使用保留的名字「_top」(頂級祖先窗口)和「_parent」(直接父級窗口)來獲取彼此瀏覽上下文。
窗口名字 窗口的名字是很是重要的,由於它容許open()方法引用已存在的窗口,並同時能夠做爲<a>和<form>元素上的html target屬性值,用戶表示引用的文檔(或表單提交結果)應該顯示在命名窗口中,這個target屬性值能夠設置爲"_blank"."_parent"或"_top",從而使引用的文檔顯示在新的空白窗口、父窗口/窗體 或頂層窗口中。 window對象若是有name屬性,就用它保存名字。該屬性是可寫的,而且腳本能夠隨意設置它,若是傳遞爲window.open()腳本一個除"_blank"以外的名字,經過該調用建立的窗口將以更名字做爲那麼屬性的初始值。若是<iframe>元素有name屬性,表示該iframe的window對象會用它做爲 name屬性的初始值。
open()的第三個可選參數是一個以逗號分隔的列表,包含大小和各類屬性,用以代表新窗口是如何打開的。若是省略它,新窗口會用一個默認的大小,並且帶有一整組標準的UI組件,即菜單欄/狀態欄、工具欄等。在標籤式瀏覽器中,會建立一個新的標籤
另一方面,若是指定這個參數,就能夠指定窗口的尺寸,以及它包含的一組屬性。(顯式指定窗口支持更像是建立新窗口,而不是新標籤)例如,容許打開改變大小的瀏覽器窗口,而且包含狀態欄、工具欄,地址欄能夠這樣寫
var w =window.open("smaillwin.html","smallwin","width=400,heigth=500,status=yes,resizeable=yes");
第三個參數是非標準的,html5規範也主張瀏覽器應該忽略它。參見 第四部分中的window.open()查看在此參數中能夠指定什麼內容。注意,當指定第三個參數時,全部沒有顯式指定的功能都會忽略。除以各類緣由,瀏覽器包含可能對可能指定功能的限制。例如:一般不容許指定一個過小或者位於屏幕以外才窗口,而且瀏覽器不容許建立一個沒有狀態欄的窗口。
open()的第四個參數只在第二個參數命名的是一個存在的窗口時纔有用。它是一個布爾值,聲明瞭由第一個參數是url是應用替換掉窗口瀏覽歷史的當前條目(true),仍是應該在窗口歷史條目建立一個新的條目false,後者爲默認設置。
open()的返回值是表明命名或新建立窗口的window對象。能夠在本身的javascript代碼中使用這個window對象來引用新建立的窗口,就像使用隱式的window對象window來引用運行代碼的窗口同樣
var w = window.open(); w.alert("to example.com"); w.location = "http://www.example.com"
在window.open()方法建立窗口中,opener屬性引用的是打開它腳本的window對象。在其它窗口總,opener爲null:
w.opner !== true; //true, 對於任何由w建立的任意窗口 w.open().opener === w; //true,對於任意窗口w
window.open()是廣告商採用在你「瀏覽窗口以前彈出」或「頁面以後彈出」窗口的一種方法。因爲這種方法的濫用,大部分瀏覽器增長了彈出窗口過濾系統,一般,open()方法只有當用戶單擊按鈕或者連接的時候纔會調用,javascript代碼嘗試在瀏覽器載入或關閉時開啓彈出一個窗口時,一般會失敗。將上面的代碼粘貼到瀏覽器javascript控制檯進行測試 ,可能會由於一樣的緣由而失敗。
關閉窗口
就像方法open()打開一個新窗口同樣,方法close()將關閉一個窗口。若是已經建立了window對象w,可使用以下的代碼將它關閉。
w.close()
運行在那個窗口中的中的關閉方法能夠用javascript將其關閉。以下
window.close();
注意,要顯式地使用標識符window。這樣能夠避免混淆window對象的close()方法和Document對象的close()方法,若是正在從事的事件程序調用close()。這很重要
大多瀏覽器只容許自動關閉由本身的javascript代碼建立的窗口。若是要關閉其餘窗口,能夠用一個對話框提示用戶,對要求關閉的窗口進行確認或取消。在表示窗體而不是頂級窗口或標籤頁上的window對象執行close()方法不會任何效果,它不能關閉一個窗體(反之能夠從它包含的文檔中刪除iframe)。
即便一個窗口關閉了,表明它的window對象仍然存在。已關閉的窗口會有個值爲爲true的closed屬性。它的Document會是null。它的方法一般不再會工做。
ii.窗體之間的關係
咱們已經知道,window對象的方法open()返回表明建立窗口的window對象,並且這個新窗口具備opener屬性,該屬性能夠打開它的原始窗口。這樣,兩個窗口就能夠相互引用,彼此均可以互相讀取對方的屬性或是調用對方的方法。窗體也是這樣的,窗口或窗體中運行的代碼均可以經過下面介紹的屬性引用到本身才窗口或窗體,以及嵌套的子窗體。
任何窗口或窗體中的javascript代碼均可以將本身的窗口和窗體引用位window或self.窗體能夠用parent屬性引用包含它的窗口或窗體的window對象。
parent.history.back();
若是一個窗口是頂層窗口或標籤,而不是窗體,那麼氣parent屬性引用的就是這個窗口自己。
parent == self; //只有頂級窗口才會返回true
若是一個窗體包含在另外一個窗體中,然後者又包含在頂級窗口中,那麼該窗體就可使用parent.parent來引用頂級窗口。top屬性是一個通用的快捷方式,不管一個窗體被嵌套了幾層,它的top屬性引用老是指向包含它的頂級窗口。若是一個window對象表明的是一個頂級窗口,那麼它的top屬性引用的就是窗口自己。對於那些頂級窗口的直接子窗口,top屬性就等價於parent屬性。
parent和top屬性容許腳本引用它的窗體的祖先。有不止一種方法能夠引用窗口或窗體的子孫窗體。窗體是iframe元素建立的。能夠用 獲取其餘元素的一個方法獲取一個表示iframe元素的對象。假定<iframe id="f1">,那麼表示該iframe元素的對象就是:
var iframeElement = document.getElementById("f1");
<iframe>元素有contentWindow屬性,引用該窗體的window對象,因此此窗體的window對象就是:
var childFrame = document.getElementById("f1").contentWindow;
能夠進行反向操做——從表示窗體的window對象來獲取該窗體的<iframe>元素,用window對象的frameElement屬性。表示頂級窗口的window對象的frameElement屬性爲null。窗體中的window對象的frameElement屬性不是null:
var elt = document.getElementById("f1"); var win = elt.contentWindow; win.frameElement === elt; //對於幀來講,永遠是true window.frameElement === null; //對於頂級窗口來講,永遠是true
儘管如此,一般不須要使用getElementById()和contentWindow屬性來獲取窗口中的子窗體的引用,每一個window對象都有一個frames屬性,它引用自身包含的窗口或窗體的子窗體。frames是繼續引用是類數組對象 ,並能夠經過數字或窗體名進行索引。引用窗口中的第一個子窗體,能夠用frames[0]。引用第二個子窗體的第三個子窗體,能夠用frames[1].frames[2],窗體裏運行的代碼能夠用parent.frames[1]引用兄弟窗體。注意frames[]數組裏的元素是window對象,不是<iframe>元素。
若是指定<iframe>元素的name或id屬性,那麼除了用數字進行索引以外,還能夠用名字來索引 .例如名字爲f1的幀應該用frames["f1"]或frames.f1。
本章第7小節中,<iframe>以及其餘元素的name和id均可以自動經過window對象的屬性來引用,而<iframe>元素和其它元素有所不一樣:對於窗體來講,經過window對象的屬性引用的<iframe>是指窗體中的window對象,而不是元素對象。也就是說,能夠經過窗體的名字f1來代替frames.f1。實際上,HTML5規範指出,frames屬性是一個自引用(self-referential)的屬性,就像window和self同樣。而這個window對象看起來像一個窗體組成的數組。也就是說,能夠window[0]來獲取第一個窗體的引用,能夠經過window.length或length查詢窗體的編號。可是這裏咱們使用frames代替window會更清晰些,儘管這種方法有些傳統。須要注意的是,當前的瀏覽器不會讓frame==window,在frame和window不相等的狀況下,能夠經過子窗口的索引或名字來得到其餘對象的引用。
可使用<iframe>的元素的name或id屬性做爲javascript代碼中的引用表示。但若是使用name屬性的話,所指定的name一樣會表明這個窗體的window對象的name屬性。以這種方式給出的名字能夠作一個連接的target屬性,並且它能夠用做window.open()的第二個參數。
iii.交互窗口中的javascript
每一個窗口和窗體都是它自身的javascript執行上下文,以及window做爲全局對象。可是若是一個窗口或窗體中的代碼能夠應用到其餘窗口或窗體(而且同源策略沒有阻止它),那麼一個窗口或窗體中的腳本就能夠和其它窗口或窗體的腳本進行交互。
設想一個web頁面中有兩個<iframe>元素 ,分別叫A和B,而且這些窗體所包含的文檔來自同一服務器,而且包含交互腳本,窗體A裏的腳本定義了一個變量i
var i = 3;
這個變量只是全局對象的一個屬性,也是window對象的一個屬性。窗體A中的代碼能夠用標識符i來引用變量,或者用window對象顯式的引用這個變量:
window.i
因爲窗體B中的腳本能夠引用窗體A的window對象,所以它能夠引用那個window對象的屬性:
parent.A.i=4;//改變窗體A中的變量i的值
咱們知道,定義函數的function能夠聲明一個變量,就像關鍵字var所作的那樣。若是B腳本什麼了一個(非嵌套)的函數f,這個函數在窗體B中是全局變量,而且在窗體B中能夠用f()調用f,可是窗體A中的代碼必須將f做爲窗體B的window對象的屬性f來調用
parent.B.f();//調用窗體B中定義的一個函數
若是窗體A中須要很頻繁的調用這個函數,則能夠將這個函數賦值給窗體A中的一個變量,這樣就能夠常用這個變量來引用窗體中的函數了:
var f = parent.B.f;
如今窗體A中的代碼就能夠像窗體B中的代碼同樣調用函數f()了。
採用這種方式在窗體或窗口間共享函數時,牢記詞法的做用域規則很是重要。函數在定義它的做用域中執行,而不是在它的做用域中執行。就上面的那個例子來講,若是函數f引用引用了全局變量,那麼將在窗體B中查找這些變量,即便函數是有窗體A調用的。
要記住構造函數也是函數,全部當用構造函數和相關的原型對象定義一個類(9章)時,那個類只能在單獨的窗口中定義。假設set.js中的窗口包含窗體A和窗體B,而且包含Set類
頂級窗體中定義的腳本能夠建立新的Set對象,相似這樣:
var s = new Set();
相反,每一個窗體中的代碼辨析顯式地用父級窗口中的屬性來引用Set()構造函數:
var s = new parent.Set();
另外,每一個窗體中的代碼必須顯式地用父級窗口的屬性來引用Set()構造函數
var set = top.Set(); var s =new Set();
和用戶定義的類不一樣,內置的類(好比String,Date和RegExp)都會在全部的窗口彙總自動預約義。可是要注意,每一個窗口都有構造函數的一個獨立副本和構造函數對於袁旭對象的一個獨立副本。例如,每一個窗口都有定義的String字符串的新方法,而且經過把它賦值給當前窗口中的String.prototype對象而使它成爲String類的一個方法,那麼該窗口中的全部字符串就均可以使用這個新方法。可是,別的窗口中定義的字符串不能使用這個新方法。
事實上每一個window對象都有本身的原型對象,這意味這instanceof操做符不能跨窗口工做。例如,當instanceof來標記窗體B的一個字符串和窗體A的string()構造函數時,結果會爲false。7章10介紹了決定跨窗口數組的類型時的相關困難。
WindowProxy對象
咱們已經講過不少次,Window對象是客戶端javascript的全局變量。可是從技術來看,並非這樣的。web瀏覽器每次向窗口或窗體中載入新的內容,它都會開始一個新的javascript對象執行上下文,包含一個新建立的全局對象。可是當多個窗口或窗體在使用時,有一個很重要的概念,儘管窗體或窗口載入 新的文檔,可是引用窗體或窗口的window對象還仍然是一個有效的引用。
全部客戶端javascript有兩個重要的對象。客戶端全局對象處於做用域鏈的頂級,而且是全局變量和函數所定義的地方。事實上全局對象會在窗口或窗體載入新內容時被替換,咱們成爲「window」的對象實際上不是全局對象,而是全局對象的一個代理。每次當查詢或設置window對象的屬性時,就會在窗口或窗體當前全局對象上查詢或設置相同的屬性。HTML5將這個規範稱代理對象爲WindowProxy
因爲它的代理行爲,除了有更長的生命週期外,代理對象表現得像真正的全局對象。若是能夠比較這兩個對象,那麼區分它們會很困難。但事實上,沒有辦法能夠用到正真的客戶端全局對象。全局對象處於做用域的頂端,可是window、self、parent以及窗體中的屬性所有返回代理對象。window.open()方法也返回代理對象。甚至頂級函數裏的this關鍵字都是代理對象,而不是真正的全局對象。
(本文完,您能夠關注上一章:第十一章:WEB瀏覽器中的javascript,將更新:第十三章:校本化文檔。歡迎關注)