ECMAScript 是 JavaScript 的核心,但若是要在 Web 中使用 JavaScript,那么 BOM(浏览器对象模型)则无疑才是真正的核心。BOM 提供了不少对象,用于访问浏览器的功能,这些功能与任何网页内容无关。多年来,缺乏事实上的规范致使 BOM 有不少问题,由于浏览器提供商会按照各自的想法随意去扩展它。W3C 为了把浏览器中 JavaScript 最基本的部分标准化,已经将 BOM 的主要方面归入了 HTML5 的规范中。javascript
window
对象BOM 的核心对象是 window
,它表示浏览器的一个实例。在浏览器中,window
对象有双重角色,它既是经过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global
对象。这意味着在网页中定义的任何一个对象、变量和函数,都以 window
做为其 Global
对象,所以有权访问 isNaN()
、isFinite()
、parseInt()
、parseFloat()
等方法。html
因为 window
对象同时扮演着 ECMAScript 中 Global
对象的角色,所以全部在全局做用域中声明的变量、函数都会变成 window
对象的属性和方法。来看下面的例子。java
var age = 29; function sayAge(){ console.log(this.age); } console.log(window.age); // 29 sayAge(); // 29 window.sayAge(); // 29
抛开全局变量会成为 window
对象的属性不谈,定义全局变量与在 window
对象上直接定义属性仍是有一点差异:全局变量不能经过 delete
运算符删除,而直接在 window
对象上的定义的属性能够。例如:git
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
属性的语句时,无论该属性最初是如何建立的,都会抛出错误,以示警告。IE9 及更高版本不会抛出错误。github
另外,还要记住一件事:尝试访问未声明的变量会抛出错误,可是经过查询 window
对象,能够知道某个可能未声明的变量是否存在。例如:编程
// 这里会抛出错误,由于 oldValue 未定义 var newValue = oldValue; // 这里不会抛出错误,由于这是一次属性查询 // newValue 的值是 undefined var newValue = window.oldValue;
若是页面中包含框架,则每一个框架都拥有本身的 window
对象,而且保存在 frames
集合中。在 frames
集合中,能够经过数值索引(从0开始,从左至右,从上到下)或者框架名称来访问相应的 window
对象。每一个 window
对象都有一个 name
属性,其中包含框架的名称。下面是一个包含框架的页面:segmentfault
<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
对象都包含原生类型的构造函数,所以每一个框架都有一套本身的构造函数,这些构造函数一一对应,但并不相等。例如,top.Object
并不等于 top.frames[0].Object
。这个问题会影响到对跨框架传递的对象使用 instanceof
运算符。
使用 window.open()
方法既能够导航到一个特定的 URL,也能够打开一个新的浏览器窗口。这个方法能够接收4个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。一般只须传递第一个参数,最后一个参数只在不打开新窗口的状况下使用。
若是为 window.open()
传递了第二个参数,并且该参数是已有窗口或框架的名称,那么就会在具备该名称的窗口或框架中加载第一个参数指定的 URL。看下面的例子。
// 等同于 <a href="http://shijiajie.com" target="newWindow"></a> window.open("http://shijiajie.com/", "newWindow");
若是给 window.open()
传递的第二个参数并非一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串建立一个新窗口或新标签页。若是没有传入第三个参数,那么就会打开一个带有所有默认设置(工具栏、地址栏和状态栏等)的新浏览器窗口(或者打开一个新标签页)。在不打开新窗口的状况下,会忽略第三个参数。
第三个参数是一个逗号分隔的设置字符串,表示在新窗口中都显示哪些特性。下表列出了能够出如今这个字符串中的设置选项。
设置 | 值 | 说明 |
---|---|---|
fullscreen | yes或no | 表示浏览器窗口是否最大化。仅限IE |
height | 数值 | 表示新窗口的高度。不能小于100 |
left | 数值 | 表示新窗口的左坐标。不能是负值 |
location | yes或no | 表示是否在浏览器窗口中显示地址栏。不一样浏览器的默认值不一样。若是设置为no,地址栏可能会隐藏,也可能会被禁用(取决于浏览器) |
menubar | yes或no | 表示是否在浏览器窗口中显示菜单栏。默认值为no |
resizable | yes或no | 表示是否能够经过拖动浏览器窗口的边框改变其大小。默认值为no |
scrollbars | yes或no | 表示若是内容在视口中显示不下,是否容许滚动。默认值为no |
status | yes或no | 表示是否在浏览器窗口中显示状态栏。默认值为no |
toolbar | yes或no | 表示是否在浏览器窗口中显示工具栏。默认值为no |
top | 数值 | 表示新窗口的上坐标。不能是负值 |
width | 数值 | 表示新窗口的宽度。不能小于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()建立的窗口调整大小或移动位置。经过这个返回的对象,能够像操做其余窗口同样操做新打开的窗口,以下所示。
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()
打开的弹出窗口。对于浏览器的主窗口,若是没有获得用户的容许是不能关闭它的。
新建立的 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
虽然弹出窗口中有一个指针指向打开它的原始窗口,但原始窗口中并无这样的指针指向弹出窗口。窗口并不跟踪记录它们打开的弹出窗口,所以咱们只能在必要的时候本身来手动实现跟踪。
曾经有一段时间,广告商在网上使用弹出窗口达到了肆无忌惮的程度。他们常常把弹出窗口打扮成系统对话框的模样,引诱用户去点击其中的广告。因为看起来像是系统对话框,通常用户很难分辨是真是假。为了解决这个问题,大多数浏览器内置有弹出窗口屏蔽程序,将绝大多数用户不想看到弹出窗口屏蔽掉。
因而,在弹出窗口被屏蔽时,就应该考虑两种可能性。若是是浏览器内置的屏蔽程序阻止的弹出窗口,那么 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 是单线程语言,但它容许经过设置超时值和间歇时间值来调度代码在特定的时刻执行。前者是在指定的时间事后执行代码,然后者则是每隔指定的时间就执行一次代码。
超时调用须要使用 window
对象的 setTimeout()
方法,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前须要等待多少毫秒)。其中,第一个参数能够是一个包含 JavaScript 代码的字符串(就和在 eval()
函数中使用的字符串同样),也能够是一个函数。例如,下面对 setTimeout()
的两次调用都会在一秒钟后显示一个警告框。
// 不建议传递字符串 setTimeout("console.log('Hello world!') ", 1000); // 推荐的调用方式 setTimeout(function() { console.log("Hello world!"); }, 1000);
虽然这两种调用方式都没有问题,但因为传递字符串可能致使性能损失,所以不建议以字符串做为第一个参数。
第二个参数是一个表示等待多长时间的毫秒数,但通过该时间后指定的代码不必定会执行。JavaScript 是一个单线程序的解释器,所以必定时间内只能执行一段代码。为了控制要执行的代码,就有一个 JavaScript 任务队列。这些任务会按照将它们添加到队列的顺序执行。setTimeout()
的第二个参数告诉 JavaScript
再过多长时间把当前任务添加到队列中。若是队列是空的,那么添加的代码会当即执行;若是队列不是空的,那么它就要等前面的代码执行完了之后再执行。
调用 setTimeout()
以后,该方法会返回一个数值 ID
,表示超时调用。这个超时调用 ID
是计划执行代码的惟一标识符,能够经过它来取消超时调用。要取消还没有执行的超时调用计划,能够调用 clearTimeout()
方法并将相应的超时调用 ID
做为参数传递给它,以下所示。
// 设置超时调用 var timeoutId = setTimeout(function() { console.log("Hello world!"); }, 1000); // 注意:把它取消 clearTimeout(timeoutId);
只要是在指定的时间还没有过去以前调用 clearTimeout()
,就能够彻底取消超时调用。前面的代码在设置超时调用以后立刻又调用了 clearTimeout()
,结果就跟什么也没有发生同样。
间歇调用与超时调用相似,只不过它会按照指定的时间间隔重复执行代码,直至间歇调用被取消或者页面被卸载。设置间歇调用的方法是 setInterval()
,它接受的参数与 setTimeout()
相同:要执行的代码(字符串或函数)和每次执行以前须要等待的毫秒数。下面来看一个例子。
// 不建议传递字符串 setInterval ("console.log('Hello world!') ", 10000); // 推荐的调用方式 setInterval (function() { console.log("Hello world!"); }, 10000);
调用 setInterval()
方法一样也会返回一个间歇调用 ID
,该 ID
可用于在未来某个时刻取消间歇调用。要取消还没有执行的间歇调用,可使用 clearInterval()
方法并传入相应的间歇调用 ID
。取消间歇调用的重要性要远远高于取消超时调用,由于在不加干涉的状况下,间歇调用将会一直执行到页面卸载。如下是一个常见的使用间歇调用的例子。
var num = 0; var max = 10; var intervalId = null; function incrementNumber() { num++; // 若是执行次数达到了max设定的值,则取消后续还没有执行的调用 if (num == max) { clearInterval(intervalId); console.log("Done"); } } intervalId = setInterval(incrementNumber, 500);
在这个例子中,变量num每半秒钟递增一次,当递增到最大值时就会取消先前设定的间歇调用。这个模式也可使用超时调用来实现,以下所示。
var num = 0; var max = 10; function incrementNumber() { num++; // 若是执行次数未达到max设定的值,则设置另外一次超时调用 if (num < max) { setTimeout(incrementNumber, 500); } else { console.log("Done"); } } setTimeout(incrementNumber, 500);
可见,在使用超时调用时,没有必要跟踪超时调用 ID
,由于每次执行代码以后,若是再也不设置另外一次超时调用,调用就会自行中止。通常认为,使用超时调用来模拟间歇调用的是一种最佳模式。在开发环境下,不多使用真正的间歇调用,缘由是后一个间歇调用可能会在前一个间歇调用结束以前启动。而像前面示例中那样使用超时调用,则彻底能够避免这一点。因此,最好不要使用间歇调用。
浏览器经过 alert()
、confirm()
和 prompt()
方法能够调用系统对话框向用户显示消息。系统对话框与在浏览器中显示的网页没有关系,也不包含 HTML。它们的外观由操做系统及(或)浏览器设置决定,而不是由 CSS 决定。此外,经过这几个方法打开的对话框都是同步和模态的。也就是说,显示这些对话框的时候代码会中止执行,而关掉这些对话框后代码又会恢复执行。
第一种对话框是调用 alert()
方法生成的。它向用户显示一个系统对话框,其中包含指定的文本和一个 OK(“肯定”)按钮。一般使用 alert()
生成的“警告”对话框向用户显示一些他们没法控制的消息,例如错误消息。而用户只能在看完消息后关闭对话框。
第二种对话框是调用 confirm()
方法生成的。从向用户显示消息的方面来看,这种“确认”对话框很像是一个“警告”对话框。但两者的主要区别在于“确认”对话框除了显示OK按钮外,还会显示一个 Cancel(“取消”)按钮,两个按钮可让用户决定是否执行给定的操做。
为了肯定用户是单击了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()
方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(能够是一个空字符串)。
若是用户单击了 OK 按钮,则 promp()
返回文本输入域的值;若是用户单击了 Cancel 或没有单击 OK 而是经过其余方式关闭了对话框,则该方法返回 null
。下面是一个例子。
var result = prompt("What is your name? ", ""); if (result !== null) { alert("Welcome, " + result); }
综上所述,这些系统对话框很适合向用户显示消息并请用户做出决定。因为不涉及 HTML、CSS 或 JavaScript,所以它们是加强 Web 应用程序的一种便捷方式。
location
对象location
对象提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。事实上,location
对象是很特别的一个对象,由于它既是 window
对象的属性,也是 document
对象的属性;换句话说,window.location
和 document.location
引用的是同一个对象。location
对象的用处不仅表如今它保存着当前文档的信息,还表如今它将 URL 解析为独立的片断,让开发人员能够经过不一样的属性访问这些片断。下表列出了 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:" | 返回页面使用的协议。一般是 http: 或 https: |
search | "?q=javascript" | 返回URL的查询字符串。这个字符串以问号开头 |
虽然经过上面的属性能够访问到 location
对象的大多数信息,但其中访问URL包含的查询字符串的属性并不方便。尽管 location.search
返回从问号到 URL 末尾的全部内容,但却没有办法逐个访问其中的每一个查询字符串参数。为此,能够像下面这样建立一个函数,用以解析查询字符串,而后返回包含全部参数的一个对象:
/* * 这个函数用来解析来自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('='); // 查找"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; // 返回解析后的参数 }
使用 location
对象能够经过不少方式来改变浏览器的位置。首先,也是最经常使用的方式,就是使用 assign()
方法并为其传递一个 URL,以下所示。
location.assign("http://shijiajie.com");
这样,就能够当即打开新URL并在浏览器的历史记录中生成一条记录。若是是将 location.href
或 window.location
设置为一个URL值,也会以该值调用 assign()
方法。例如,下列两行代码与显式调用 assign()
方法的效果彻底同样。
window.location = "http://shijiajie.com"; location.href = "http://shijiajie.com";
在这些改变浏览器位置的方法中,最经常使用的是设置 location.href
属性。
另外,修改 location
对象的其余属性也能够改变当前加载的页面。下面的例子展现了经过将 hash
、search
、hostname
、pathname
和 port
属性设置为新值来改变 URL。
// 假设初始 URL 为 http://shijiajie.com/about/ location.href = "http://shijiajie.com/about/" // 将 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()
方法。这个方法只接受一个参数,即要导航到的 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
。而后,“后退”按钮将处于禁用状态,若是不从新输入完整的 URL,则没法返回示例页面。
与位置有关的最后一个方法是 reload()
,做用是从新加载当前显示的页面。若是调用 reload()
时不传递任何参数,页面就会以最有效的方式从新加载。也就是说,若是页面自上次请求以来并无改变过,页面就会从浏览器缓存中从新加载。若是要强制从服务器从新加载,则须要像下面这样为该方法传递参数 true
。
location.reload(); // 从新加载(有可能从缓存中加载) location.reload(true); // 从新加载(从服务器从新加载)
位于 reload()
调用以后的代码可能会也可能不会执行,这要取决于网络延迟或系统资源等因素。为此,最好将 reload()
放在代码的最后一行。
history
对象history
对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。由于 history
是 window
对象的属性,所以每一个浏览器窗口、每一个标签页乃至每一个框架,都有本身的 history
对象与特定的 window
对象关联。出于安全方面的考虑,开发人员没法得知用户浏览过的 URL。不过,借由用户访问过的页面列表,一样能够在不知道实际 URL 的状况下实现后退和前进。
使用 go()
方法能够在用户的历史记录中任意跳转,能够向后也能够向前。这个方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(相似于单击浏览器的“后退”按钮),正数表示向前跳转(相似于单击浏览器的“前进”按钮)。来看下面的例子。
// 后退一页 history.go(-1); // 前进一页 history.go(1); // 前进两页 history.go(2);
也能够给 go()
方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置——可能后退,也可能前进,具体要看哪一个位置最近。若是历史记录中不包含该字符串,那么这个方法什么也不作,例如:
// 跳转到最近的 shijiajie.com 页面 history.go("shijiajie.com");
另外,还可使用两个简写方法 back()
和 forward()
来代替 go()
。顾名思义,这两个方法能够模仿浏览器的“后退”和“前进”按钮。
// 后退一页 history.back(); // 前进一页 history.forward();
除了上述几个方法外,history
对象还有一个 length
属性,保存着历史记录的数量。这个数量包括全部历史记录,即全部向后和向前的记录。对于加载到窗口、标签页或框架中的第一个页面而言,history.length
等于0。经过像下面这样测试该属性的值,能够肯定用户是否一开始就打开了你的页面。
if (history.length == 0){ //这应该是用户打开窗口后的第一个页面 }
虽然 history
并不经常使用,但在建立自定义的“后退”和“前进”按钮,以及检测当前页面是否是用户历史记录中的第一个页面时,仍是必须使用它。
BOM(浏览器对象模型)以 window
对象为依托,表示浏览器窗口以及页面可见区域。同时,window
对象仍是 ECMAScript 中的 Global
对象,于是全部全局变量和函数都是它的属性,且全部原生的构造函数及其余函数也都存在于它的命名空间下。本章讨论了下列 BOM 的组成部分。
在使用框架时,每一个框架都有本身的 window
对象以及全部原生构造函数及其余函数的副本。每一个框架都保存在 frames
集合中,能够经过位置或经过名称来访问。
有一些窗口指针,能够用来引用其余框架,包括父框架。
top
对象始终指向最外围的框架,也就是整个浏览器窗口。
parent
对象表示包含当前框架的框架,而 self
对象则回指 window
。
使用 location
对象能够经过编程方式来访问浏览器的导航系统。设置相应的属性,能够逐段或总体性地修改浏览器的 URL。
调用 replace()
方法能够导航到一个新 URL,同时该 URL 会替换浏览器历史记录中当前显示的页面。
navigator
对象提供了与浏览器有关的信息。到底提供哪些信息,很大程度上取决于用户的浏览器;不过,也有一些公共的属性(如 userAgent
)存在于全部浏览器中。
BOM中还有两个对象:screen
和 history
,但它们的功能有限。screen
对象中保存着与客户端显示器有关的信息,这些信息通常只用于站点分析。history
对象为访问浏览器的历史记录开了一个小缝隙,开发人员能够据此判断历史记录的数量,也能够在历史记录中向后或向前导航到任意页面。
// 挑战一 setTimeout(function () { console.log("1"); }, 0) console.log("2"); // ???
// 挑战二 for (var i = 0;i<5;i++) { setTimeout(function () { console.log(i); // ??? }, 0) };
// 挑战三 var a = 1; var obj = { a : 2, b : function(){ setTimeout(function () { console.log(this.a); }, 0) } } obj.b(); // ???
// 挑战四 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,获取最新动态。