JavaScript权威指南--window对象

时间:2021-09-04 18:42:44

知识要点

JavaScript权威指南--window对象

window对象及其客户端javascript所扮演的核心角色:它是客户端javascript程序的全局对象。本章介绍window对象的属性和方法,这些属性定义了不同的API,但是只有一部分实际上和浏览器窗口相关。window对象是以窗口命名的。

1.计时器

setTimeout()和setIterval()可以用来注册在指定的时间之后单次或重复调用的函数。因为它们都是客户端javascript中的重要全局函数,所以定义为window对象方法,但作为通用函数,其实并不会对窗口做什么事情。

window对象的setTimeout()方法用来实现一个函数在指定的毫秒后运行。setTimeout返回一个值,这个值可以传给clearTimeout()用于取消这个函数的执行。

/**定时器应用函数
* 安排函数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);//若干秒后调用repeat()
function repeat(){
var h = setInterval(f,interval);//循环调用f()
//在end结束后调用,嵌套是end已经定义了
if(end) setTimeout(function(){clearInterval(h);},end);
}
}
}

谈谈setTimeout()和setInterval()问题

由于历史原因,setTimeout()和setInterval()第一个参数可以作为字符串传入。如果这么做,那这个字符串会在指定的超时时间或间隔之后求值(相当于执行eval()).除了前两个参数之外,HTML5规范还允许setTimeout()和setInterval()传入额外的参数,并且在调用函数的时候把这些参数传递过去。然而,如果需要支持IE的话,就不要应用此特性了。

如果以0毫秒时间调用setTimeout,那么指定的函数不会立刻执行。相反会把它放到队里中,等到前面处于等待状态的事件处理程序完全完成之后,再立刻调用它。

补充:

function parent(){
function child(){
setTimeout(child2(),1000);
setTimeout(parent2(),1000);
alert("use child1")
}
function child2(){
alert("use child2")
}
child();
}
parent();//调用parent
function parent2(){
alert("I’m your mather")
}

输出:直接按顺序输出:2-1-l`m。给第一个参数添加双引号成为字符串即可。

function parent(){
function child(){
setTimeout("child2()",1000);
setTimeout("parent2()",1000);
console.log("use child1")
}
function child2(){
console.log("use child2")
}
child();
}
parent();//调用parent
function parent2(){
console.log("I’m your mather")
}

输出结果:

JavaScript权威指南--window对象

这说明setTimeout只能访问全局对象的属性和方法,而不能访问私有作用域内的属性和方法。其实setTimeout是个window对象的一个方法,f是作为window对象的一个方法调用的,其效果就像一个<script>标签里面的代码一样只能访问,对于函数里面的变量和方法是无法访问的。这就是为什么建议使用函数代替字符串的一个原因。另外,传递字符串也有可能导致性能损失。

2.浏览器的定位和导航

window对象的location属性引用的是Location对象,它表示该窗口中当前显示的文档的URL,并定义了方法使窗口载入新的文档。

Document对象的location属性也引用到Location对象:

window.location === document.location; //=>true 总是返回true

Document对象也有一个URL属性,是文档首次载人后保存该文档的URL静态字符串。如果定位到文档中的片段标识符(如#table-of-contens),Location对象会做相应的更新,而document.url属性却不会改变。

2.1.解析url

window对象的location属性引用是Location对象,表示该窗口当前显示的的文档的URL。Location对象的href属性是一个字符串,包含URL的完整文本。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,这部分通常是某种类型的查询字符串。一般来说这部分内容是用来参数化URL并在其中嵌入参数的。常用于运行在服务器上的脚本,但在启动JavaScript的页面中也可以使用。

下面的例子展示了一个通用函数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;
}

2.2.载入新的文档

Location对象的assign()方法可以使窗口载入并显示你指定的url中的文档。replace()方法也类似,但它在载入新的文档之前会从浏览历史把当前文档删除。如果脚本无条件的载入一个新的文档,replace()方法是可能比assgin()方法更好的选择。否则,后退按钮会使用浏览器带回原始文档。而相同的脚本则会再次载入新文档。如果检测到用户浏览器不支持某些特性来显示功能齐全的版本,可以用location.replace()来载入静态的HTML版本:

 //如果浏览器不支持XMLHttpRequest对象
//则将其重定向到一个不需要Ajax的静态页面
if (!XMLHttpRequest) location.replace("staticpage.html");

注意,在这个例子中传入replace()的是一个相对URL。相对URL是相对于当前页面所在的目录来解析的,就像将它们用于一个超链接中。

除了assign()和replace()方法,Location对象还定义了reload()方法,后者可以让浏览器重新载入当前文档。

使浏览器跳转到新页面的一种更传统的方法是直接赋值给location:

location = "https://segmentfault.com/";

也可用相对URL,它会对其进行解析:

location = "page.html";

纯粹的片段标识符也是url的一种类型,它不会让浏览器载入新文档,但只会使它滚动到文档的某个位置。#top标识符是一个特殊例子:如果文档没有元素额ID是"top",它会让浏览器跳转到文档开始处。

location = "#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见14.8.2节),子窗口的浏览历史会按时间顺序穿插在主窗口的历史中。这意味着在主窗口调用history.back()可能会导致其中一个子窗口往回跳到前一个显示文档,但主窗口保留当前状态不变。

现代的web应用可以不通过载入新的文档而动态的改变自身内容(15、18章)。这么做可能希望用户能用“后退”和“前进”按钮在这些动态创建应用状态之间跳转。html5将这些技术标准化(22章2节)。

HTML5之前的历史管理是个更复杂的难题。应用程序必须要在窗口浏览历史中创建一个新的条目来管理自身的历史记录。。。。。。

在实际的工作中,那些需要以前的HTML5历史管理的项目中,开发者会使用一些现成 解决方法,很多框架都实现了这些功能。例如jQuery的history插件。也有一些单独的管理历史记录的类库。RSH(Really Simple History)是其中一个比较流行的示例。(22章2节会有关于html5的历史管理)

4.浏览器和屏幕信息

本节介绍window对象的navigator和screen属性,它们分别引用的是Navigator和Screen对象,这些对象信息允许脚本根据环境定制的行为。

4.1.Navigator对象

window对象的navigator属性引用的是包含浏览器厂商和版本信息的Navigator对象。

这样命名是为了纪念Netscape之后Navigator浏览器。

过去会用其来确定脚本是在哪种浏览器运行,现在浏览器种类繁多,也有一种更好的功能测试方法(13.4.3节)。但是Navigation还是有价值的,在这种情况下有用:当需要解决存在于某个特定的浏览器的特定版本中的特殊的bug时。

可以使用这些属性进行浏览器嗅探:

  • appName:web浏览器的全称,IE中,它显示“Microsoft Internet Exploer”.在firefox中,该属性就是“Netscape”,在其它浏览器中也是(为了兼容现在的浏览器嗅探码)。
  • appVersion:此属性通常以数字开始,并跟随浏览器开发商和版本信息等详细字符串。字符串的前边通常是4.0或者5.0,表示它是第4还是第5代兼容的浏览器。appVersion没有标准格式。所有没有办法判断浏览器的类型
  • userAgent:浏览器在它的User-Agent HTTP头部发送的字符串。这个属性通常包含所有appVersion信息,并且常常包含其它细节。和appVersion一样,它也没有标准格式。由于这个属性包含绝大部分信息,因此,浏览器嗅探代码通常使用它。
  • platform:在其上运行的浏览器的操作系统(可能是硬件的字符串)。
navigator.appName
//不是Navigator.appName,属性是引用Navigator对象

Navigator属性的复杂性正说明了浏览器嗅探对于处理客户端兼容性问题是没有太大帮助的。appName(都设为Netscape)和appVersion(有起始数字)没太大意义,所以使用更复杂的userAgent。

下面的例子展示了使用正则表达式(来自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"};
}());

除了浏览器厂商和版本信息的属性之外,Navigator对象还包含一些杂项属性和方法。以下是一些标准化的属性以及广泛应用但未标准的属性:

  • OnLine:navigator.onLine是表示浏览器是否连接到网络。应用:判断离线的话就保存状态到本地(20章)
  • geolocation:navigator.geolocation对象拥有确定用户地址位置信息的接口,参加22.1章节细节
  • javaEnabled():navigator.javaEnabled是一个非标准的方法,当浏览器能运行java小程序时返回true
  • cookieEnabled():navigator.cookieEnabled也是一个非标准方法,如果浏览器可以永久保存cookie时,返回true,而cookie配置“视具体情况而定”时,可能会返回不正确的值。

4.2.Screen对象。

window对象的screen属性引用的是Screen对象。它提供有关窗口的大小和可用的颜色数量的信息。属性width和heigth指定的是以像素为单位的窗口大小,属性availWidth和availHeiht指是实际可用的显示大小,它们排除了像桌面任务栏这样的特性所占用的空间。属性colorDepth指定的是显示的BPP(bits-per-pixel)值,典型的值有16,24,32

window.screen属性和它引用的screen对象都是非标准但广泛实现的。可以用Screen对象来确定web应用是否运行在一个小的屏幕设备上,如果屏幕有限,可能要选用更小的字体和图片等。

5.对话框

window对象提供了3个方法向用户显示简单的对话框,alert()向用户显示一条信息并等待用户关闭对话框,confirm()要求用户单击确定或取消,返回一个布尔值,prompt()同样也显示一条消息,等待用户输入字符串,并返回那个字符串。下面的代码全用了这三种方法:

do {
var name = prompt("你的名字");
var correct = confirm("你输入了" + name + "\n" + "oK确认,chancel取消");
} while (!correct)
alert("hello " + name);

尽管alert(),confirm()和prompt()都容易使用,但是良好的设计还是需要有节制的使用它们。如今,唯一常见的就是使用它们调试,查看变量输出的结果是什么。

注意,这些对话框中显示的文本是纯文本,而不是HTML格式的文本,只能使用空格,换行符和各种标点符号来格式化这些对话框。

confirm()和prompt()都会产生阻塞,也就是说,在用户关掉它们所显示的对话框之前,它们不返回,代码会停止运行或载入,直到用户响应为止。在大多数浏览器里,alert()也会产生阻塞,并等待用户关闭对话框,但不总是这样,完整的的细节请参考第四部分的Window.alert()/Window.confirm()、和window.prompt()方法。

除了window的alert()、confirm()和prompt()方法,还有更复杂的方法showModalDialog(),显示一个包含HTML格式的模态对话框(显示出来就不可以点选位于其下面的对话框),可以给它传入参数,以及从对话框里返回值。第一个参数用以指定提供对话框HTML内容的URL,第二个参数是一个任意值(数组和对象均可),这个值在对话框里的脚本中可以通过window.dailogArguments属性的值访问。第三个参数是一个非标准的列表,包含以分号隔开的name=value对,如果提供了这个参数,可以配置对话框的尺寸和其他属性,用dialogwidth和dialogheight来设置对话框窗口的大小。用resizable=yes来允许用户改变窗口大小。

这个方法直到窗口关闭之前不会反悔。当窗口关闭后,window.returnValue属性的值就是此方法的返回值。对话框的HTML内容往往必须包含用来设置returnValue的“确认”按钮,如果需要则调用window.close(14.8.1节)。

下面的例子是一个适用于showModalDialog()的html文件,代码顶部注释包含调用showModalDialog()的样例。对话框里显示的大量文本都来自showModalDialog()第二个参数,而不是写死在html中。

。。。。。。

6.错误处理

window对象的onerror属性是一个事件处理程序,当未捕获的异常传播到调用栈上时就会调用它,并把错误消息输出到浏览器的javascript控制台上。如果给这个属性赋值一个函数,那么只要这个窗口中发生了javascript错误,就会调用该函数,即它成为了窗口的错误处理程序。

由于历史原因,window对象的onerror事件处理函数的调用通过三个字符串参数,而不是通过传递一个事件对象。(其它客户端对象的onerror处理程序所需要的错误条件是不一样的,但是它们都是正常的事件处理程序,向这个函数只需传入一个事件对象。)window.onerror的第一个参数是描述错误的一条消息。第二个参数是一个字符串,它存放引发错误的javascript代码所在文档的 url.第三个参数是引发错误的行数。

除了这三个参数外,onerror处理程序的返回值也很重要。如果onerror处理程序返回false,它通知浏览器事件处理程序已经处理了错误,不需要其他操作。换句话说,浏览器不应该显示它自己的错误消息。遗憾的是,由于历史原因,Firefox里的错误程序必须返回true表示它已经处理了错误

onerror处理程序是很早期的javascript产物,那时候语言核心不包含try/catch异常处理语句。现在的代码已经很少使用它。但是在开发阶段,你可能需要定义一个错误处理程序,当错误发生时,来显式的通知你。

//在一个对话框中弹出错误消息,但不超过3次
window.onerror = function(msg, url, line) {
if(onerror.num++ < onerror.max){
alert("出错了:\n" + msg + "\n 地址:" + url + "\n行号:" + line);
return true; //屏蔽系统事件
}
}
onerror.max = 3;
onerror.num = 0;

示例:

<html>
<head>
<script type="text/javascript">
onerror=handleErr
var txt="" function handleErr(msg,url,l)
{
txt="本页中存在错误。\n\n"
txt+="错误:" + msg + "\n"
txt+="URL: " + url + "\n"
txt+="行:" + l + "\n\n"
txt+="点击“确定”继续。\n\n"
alert(txt)
return true
} function message()
{
ablert("Welcome guest!")
}
</script>
</head> <body>
<input type="button" value="查看消息" onclick="message()" />
</body> </html>

7.作为window对象属性的文档元素

如果在HTML文档中使用id属性来为元素命名,并且如果window对象没有此名字的属性,window对象会赋予一个属性,它的名字是id属性的值,而他们的值指向表示文档元素的HTMLElement对象。

//文档中存在id="doc"的HTML元素
window.doc

在客户端javascript中,window对象是以全局对象的形式存在于作用域链的最上层,这就意味着在html文档中使用的id属性会成为被脚本访问的全局变量。如果一个文档包含<button id="okay"></button>元素,可以通过全局变量okay引用此元素。

但是:有一个很重要的警告!如果window对象已经具有此名字的属性,这就不会发生。比如id是history,location或navigator的元素,就不会以全局变量的形式出现,因为这些id已经被占用了。同样,如果html文档包含一个id为“x”的元素,并且还在代码中声明并赋值给全局变量x,那么显式声明的变量会隐藏隐式的元素变量。如果脚本中的变量声明出现在命名元素之前,那这个变量的存在就会阻止元素获取它的window属性。而如果脚本中的变量声明出现在命名元素之后,那么变量的显式赋值就会覆盖该属性的隐式值。

15章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
但记得14.5节里window对象有个方法的名字是prompt(),所用脚本中不能用全局变量prompt代替ui.prompt。

元素的id作为全局变量的隐式应用是web浏览器演化过程中遗留的怪癖。它主要是出于与已有web页面向后兼容性的考虑。但这里并不推荐这种做法---浏览器厂商可以在任何时候为window对象定义新属性,而这些新属性都会破坏使用了此属性名的隐式定义的代码。反之,用document.getElementById()来显式查找元素,如果给他一个更简单的名字,这种用法会更加简单:

var $ = function(id) {
return document.getElementById(id);
};
ui.prompt = $("prompt")

假设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对象。本文14.8.2节会讨论到它。

8.多窗口和窗体

一个web页面窗口可能在桌面上包含多个标签页。每一个标签 页都是独立的“浏览上下文”(browsing context),每一个上下文都有独立的window对象,而且相互之间互不干扰。

但是窗口不总是和其它窗口完全没有关系。一个窗口或标签页中的脚本可以打开新的窗口或标签页,当一个脚本这样做时,这样多个窗口或窗口与另一个窗口文档之间就可以互操作。(13.6.2节讲解的同源策略约束)。本节1小节会介绍窗口的打开和关闭的更多内容。

html文档经常使用<iframe>来嵌套多个文档。由它所创建的嵌套浏览上下文是用它自己的window对象所表示的。废弃的<frameset>和<frame>元素同样创建了一个嵌套的浏览上下文。每一个<frame>都由一个独立的window对象表示。对于客户端javascript来说,窗口、标签页、iframe和框架都是独立的浏览上下文。对于javascript来说,它们都是window对象。和相互独立的标签页不同,嵌套的浏览上下文之间并不是相互独立的。在一个窗体中运行javascript程序总是能看见它的祖先和子孙窗体,尽管脚本查看这些窗体中的文档受到同源策略限制。14.8.2节。

因为window是客户端javascript的全局对象,每个窗口或窗体都包含独立的javascript执行上下文。不过在一个窗口中的javascript代码,如有同源策略的限制,则可以使用另外一个窗口中定义的对象、属性和方法。与此相关的细节会在14.8.3节详细讨论。由于同源策略的限制导致窗口之间无法直接交互时,html5提供了一个基于事件的消息传输API,可以用于间接通信。22章3节会讨论。

8.1.打开和关闭窗口

使用window对象的open()方法可以打开一个新的浏览器窗口(或标签页,这通常和浏览器的配置项有关)。window.open()载入指定的url到新的或已存在的窗口中,并返回代表那个窗口的window对象。它有四个可选的参数。

open()第一个参数是要在新窗口中显示的文档的url。如果省略(也可以是空字符串),那么会使用页面的URLabout:blank。

opne()第二个参数是新打开的窗口的名字。如果指定的是一个以及存在的窗口的名字(并且脚本允许跳转到那个窗口),会直接使用已经存在的窗口。否则,会打开新的窗口,并将这个指定的名字赋值给它。如果省略此参数,会使用指定的名字“_blank”打开新的、未命名的窗口。

需要注意的是,脚本是无法通过简单的猜测窗口的名字来控制操纵这个窗口中的web应用的,只有设置了“允许导航”(allowed to navigte)(html5规范术语)的页面才可以这样。宽泛的讲,当且仅当窗口包含的文档来自相同的源或者是这个脚本打开了那个窗口(或者是递归地打开了窗口中打开的窗口),脚本才可以通过名字来指定存在的窗口。还有,如果其中一个窗口是内嵌在另一个窗口的里的窗体,那么它们的脚本直接就可以相互导航。在这种情况下,可以使用保留的名字“_top”(*祖先窗口)和“_parent”(直接父级窗口)来获取彼此浏览上下文。

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。它的方法通常再也不会工作。

8.2.窗体之间的关系

我们已经知道,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

。。。。。。

8.3.交互窗口中的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的值

。。。。。。