javascript高级程序设计-第八章

没有一节一节写的很详细,就总结一些常用的,给自己或者也一起在学习的朋友一起过过眼瘾,一起理理,喜欢的朋友可以点赞关注哦。

BOM简介

ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript,那么 BOM(浏览器对象模型)则无疑才是真正的核心。BOM 提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。多年来,缺少事实上的规范导致 BOM 既有意思又有问题,因为浏览器提供商会按照各自的想法随意去扩展它。于是,浏览器之间共有的对象就成为了事实上的标准。这些对象在浏览器中得以存在,很大程度上是由于它们提供了与浏览器的互操作性。W3C 为了把浏览器中 JavaScript 最基本的部分标准化,已经将 BOM 的主要方面纳入了 HTML5 的规范中。

window对象

BOM 的核心对象是 window,它表示浏览器的一个实例。在浏览器中,window 对象有双重角色,它既是通过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象。这意味着在网页中定义的任何一个对象、变量和函数,都以 window 作为其 Global 对象,因此有权访问parseInt()等方法。

全局作用域

由于 window 对象同时扮演着 ECMAScript 中 Global 对象的角色,因此所有在全局作用域中声明的变量、函数都会变成 window 对象的属性和方法。我们在全局作用域中定义了一个变量 age 和一个函数 sayAge(),它们被自动归在了 window 对象名下。于是,可以通过 window.age 访问变量 age,可以通过 window.sayAge()访问函数 sayAge()。由于 sayAge()存在于全局作用域中,因此 this.age 被映射到 window.age,最终显示的仍然是正确的结果。

var age = 29; 
function sayAge(){ 
 alert(this.age); 
} 
alert(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; //returns true 
alert(window.age); //29 
alert(window.color); //undefined 

刚才使用 var 语句添加的 window 属性有一个名为[[Configurable]]的特性,这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除。IE8及更早版本在遇到使用delete删除 window 属性的语句时,不管该属性最初是如何创建的,都会抛出错误,以示警告。IE9 及更高版本不会抛出错误。另外,还要记住一件事:尝试访问未声明的变量会抛出错误,但是通过查询 window 对象,可以知道某个可能未声明的变量是否存在。

//这里会抛出错误,因为 oldValue 未定义
var newValue = oldValue; 
//这里不会抛出错误,因为这是一次属性查询
//newValue 的值是 undefined 
var newValue = window.oldValue; 
窗口位置

用来确定和修改 window 对象位置的属性和方法有很多。IE、Safari、Opera 和 Chrome 都提供了screenLeft 和 screenTop 属性,分别用于表示窗口相对于屏幕左边和上边的位置。Firefox 则在screenX 和 screenY 属性中提供相同的窗口位置信息,Safari 和 Chrome 也同时支持这两个属性。Opera虽然也支持 screenX 和 screenY 属性,但与 screenLeft 和 screenTop 属性并不对应,因此建议大家不要在 Opera 中使用它们。使用下列代码可以跨浏览器取得窗口左边和上边的位置。

var leftPos = (typeof window.screenLeft == "number") ? 
 window.screenLeft : window.screenX; 
var topPos = (typeof window.screenTop == "number") ? 
 window.screenTop : window.screenY; 
console.log('leftPos', leftPos);
console.log('topPos', topPos);

在使用这些值的过程中,还必须注意一些小问题。在 IE、Opera 中,screenLeft 和 screenTop 中保存的是从屏幕左边和上边到由 window 对象表示的页面可见区域的距离。换句话说,如果 window 对象是最外层对象,而且浏览器窗口紧贴屏幕最上端——即 y 轴坐标为 0,那么 screenTop 的值就是位于页面可见区域上方的浏览器工具栏的像素高度。但是,在 Chrome、Firefox和 Safari中,screenY 或 screenTop中保存的是整个浏览器窗口相对于屏幕的坐标值,即在窗口的 y 轴坐标为 0 时返回 0。
更让人捉摸不透是,Firefox、Safari 和 Chrome 始终返回页面中每个框架的 top.screenX 和top.screenY 值。即使在页面由于被设置了外边距而发生偏移的情况下,相对于 window 对象使用screenX 和 screenY 每次也都会返回相同的值。而 IE 和 Opera 则会给出框架相对于屏幕边界的精确坐标值。
最终结果,就是无法在跨浏览器的条件下取得窗口左边和上边的精确坐标值。然而,使用 moveTo()和 moveBy()方法倒是有可能将窗口精确地移动到一个新位置。这两个方法都接收两个参数,其中moveTo()接收的是新位置的 x 和 y 坐标值,而 moveBy()接收的是在水平和垂直方向上移动的像素数。

//将窗口移动到屏幕左上角
window.moveTo(0,0); 
//将窗向下移动 100 像素
window.moveBy(0,100); 
//将窗口移动到(200,300) 
window.moveTo(200,300); 
//将窗口向左移动 50 像素
window.moveBy(-50,0); 

需要注意的是,这两个方法可能会被浏览器禁用;这两个方法都不适用于框架,只能对最外层的 window 对象使用。

窗口大小

跨浏览器确定一个窗口的大小不是一件简单的事。IE9+、Firefox、Safari、Opera 和 Chrome 均为此提供了 4 个属性:innerWidth、innerHeight、outerWidth 和 outerHeight。在 IE9+、Safari 和 Firefox中,outerWidth 和 outerHeight 返回浏览器窗口本身的尺寸(无论是从最外层的 window 对象还是从某个框架访问)。在 Opera中,这两个属性的值表示页面视图容器①的大小。而 innerWidth 和 innerHeight则表示该容器中页面视图区的大小(减去边框宽度)。在 Chrome 中,outerWidth、outerHeight 与innerWidth、innerHeight 返回相同的值,即视口(viewport)大小而非浏览器窗口大小。
IE8 及更早版本没有提供取得当前浏览器窗口尺寸的属性;不过,它通过 DOM 提供了页面可见区域的相关信息。
在 IE、Firefox、Safari、Opera 和 Chrome 中,document.documentElement.clientWidth 和document.documentElement.clientHeight 中保存了页面视口的信息。在 IE6 中,这些属性必须在标准模式下才有效;如果是混杂模式,就必须通过 document.body.clientWidth 和 document.body.clientHeight 取得相同信息。而对于混杂模式下的 Chrome,则无论通过document.documentElement 还是 document.body 中的 clientWidth 和 clientHeight 属性,都可以取得视口的大小。
虽然最终无法确定浏览器窗口本身的大小,但却可以取得页面视口的大小。

var pageWidth = window.innerWidth, 
 pageHeight = window.innerHeight; 
 
if (typeof pageWidth != "number"){ 
 if (document.compatMode == "CSS1Compat"){ 
 pageWidth = document.documentElement.clientWidth; 
 pageHeight = document.documentElement.clientHeight; 
 } else { 
 pageWidth = document.body.clientWidth; 
 pageHeight = document.body.clientHeight; 
 } 
} 

在以上代码中,我们首先将 window.innerWidth 和 window.innerHeight 的值分别赋给了pageWidth 和 pageHeight。然后检查 pageWidth 中保存的是不是一个数值;如果不是,则通过检查document.compatMode(这个属性将在第 10 章全面讨论)来确定页面是否处于标准模式。如果是,则分别使用 document.documentElement.clientWidth 和 document.documentElement.clientHeight 的值。否则,就使用 document.body.clientWidth 和 document.body.clientHeight 的值。
对于移动设备,window.innerWidth 和 window.innerHeight 保存着可见视口,也就是屏幕上可见页面区域的大小。移动 IE 浏览器不支持这些属性,但通过 document.documentElement.clientWidth 和 document.documentElement.clientHeihgt 提供了相同的信息。随着页面的缩放,这些值也会相应变化。
在其他移动浏览器中,document.documentElement 度量的是布局视口,即渲染后页面的实际大小(与可见视口不同,可见视口只是整个页面中的一小部分)。移动 IE 浏览器把布局视口的信息保存在document.body.clientWidth和document.body.clientHeight中。这些值不会随着页面缩放变化。
由于与桌面浏览器间存在这些差异,最好是先检测一下用户是否在使用移动设备,然后再决定使用哪个属性。
另外,使用 resizeTo()和 resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接收两个参数,其中 resizeTo()接收浏览器窗口的新宽度和新高度,而 resizeBy()接收新窗口与原窗口的宽度和高度之差。来看下面的例子。

//调整到 100×100 
window.resizeTo(100, 100); 
//调整到 200×150 
window.resizeBy(100, 50); 
//调整到 300×300 
window.resizeTo(300, 300);

需要注意的是,这两个方法与移动窗口位置的方法类似,也有可能被浏览器禁用;而且,在 Opera和 IE7(及更高版本)中默认就是禁用的。另外,这两个方法同样不适用于框架,而只能对最外层的window 对象使用。

导航和打开窗口

使用 window.open()方法既可以导航到一个特定的 URL,也可以打开一个新的浏览器窗口。这个方法可以接收 4 个参数:要加载的 URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。通常只须传递第一个参数,最后一个参数只在不打开新窗口的情况下使用。
如果为 window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的 URL。第二个参数也可以是下列任何一个特殊的窗口名称:_self、_parent、_top 或_blank。

//等同于< a href="http://www.wrox.com" target="topFrame"></a> 
window.open("http://www.wrox.com/", "topFrame"); 
间歇调用和超时调用

JavaScript 是单线程语言,但它允许通过设置超时值和间歇时间值来调度代码在特定的时刻执行。前者是在指定的时间过后执行代码,而后者则是每隔指定的时间就执行一次代码。

使用间歇调用的例子

var num = 0; 
var max = 10; 
var intervalId = null; 
function incrementNumber() { 
 num++; 
 //如果执行次数达到了 max 设定的值,则取消后续尚未执行的调用
 if (num == max) { 
 clearInterval(intervalId); 
 alert("Done"); 
 } 
} 
intervalId = setInterval(incrementNumber, 500); 

在这个例子中,变量 num 每半秒钟递增一次,当递增到最大值时就会取消先前设定的间歇调用。这个模式也可以使用超时调用来实现,如下所示。

var num = 0; 
var max = 10; 
function incrementNumber() { 
 num++; 
 //如果执行次数未达到 max 设定的值,则设置另一次超时调用
 if (num < max) { 
 setTimeout(incrementNumber, 500); 
 } else { 
 alert("Done"); 
 } 
} 
setTimeout(incrementNumber, 500); 

可见,在使用超时调用时,没有必要跟踪超时调用 ID,因为每次执行代码之后,如果不再设置另一次超时调用,调用就会自行停止。一般认为,使用超时调用来模拟间歇调用的是一种最佳模式。在开
发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动。
而像前面示例中那样使用超时调用,则完全可以避免这一点。所以,最好不要使用间歇调用。

location对象

location 是最有用的 BOM 对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能。事实上,location 对象是很特别的一个对象,因为它既是 window 对象的属性,也是document 对象的属性;换句话说,window.location 和 document.location 引用的是同一个对象。location 对象的用处不只表现在它保存着当前文档的信息,还表现在它将 URL 解析为独立的片段,让开发人员可以通过不同的属性访问这些片段。

属性名例子说明
hash“#contents”返回URL中的hash(#号后跟零或多个字符),如果URL中不包含散列,则返回空字符串
host“www.wrox.com:80”返回服务器名称和端口号(如果有)
hostname“www.wrox.com”返回不带端口号的服务器名称
href“http:/www.wrox.com”返回当前加载页面的完整URL。而location对象的toString()方法也返回这个值
pathname“/WileyCDA/”返回URL中的目录和(或)文件名
port“8080”返回URL中指定的端口号。如果URL中不包含端口号,则这个属性返回空字符串
protocol“http:”返回页面使用的协议。通常是http:或https:
search“?q=javascript”返回URL的查询字符串。这个字符串以问号开头
查询字符串参数

虽然通过上面的属性可以访问到 location 对象的大多数信息,但其中访问 URL 包含的查询字符串的属性并不方便。尽管 location.search 返回从问号到 URL 末尾的所有内容,但却没有办法逐个访问其中的每个查询字符串参数。为此,可以像下面这样创建一个函数,用以解析查询字符串,然后返回包含所有参数的一个对象:

function getQueryStringArgs(){ 
 //取得查询字符串并去掉开头的问号
 var qs = (location.search.length > 0 ? location.search.substring(1) : ""), 
 
 //保存数据的对象
 args = {}, 
 
 //取得每一项
 items = qs.length ? qs.split("&") : [], 
 item = null, 
 name = null, 
 value = null, 
 //在 for 循环中使用
 i = 0, 
 len = items.length; 
 //逐个将每一项添加到 args 对象中
 for (i=0; i < len; i++){ 
 item = items[i].split("="); 
 name = decodeURIComponent(item[0]); 
 value = decodeURIComponent(item[1]); 
 if (name.length) { 
 args[name] = value; 
 } 
 } 
 
 return args; 
} 

这个函数的第一步是先去掉查询字符串开头的问号。当然,前提是 location.search 中必须要包含一或多个字符。然后,所有参数将被保存在 args 对象中,该对象以字面量形式创建。接下来,根据和号(&)来分割查询字符串,并返回 name=value 格式的字符串数组。下面的 for 循环会迭代这个数组,然后再根据等于号分割每一项,从而返回第一项为参数名,第二项为参数值的数组。再使用 decodeURIComponent()分别解码 name 和 value(因为查询字符串应该是被编码过的)。最后,将 name 作为 args 对象的属性,将 value 作为相应属性的值。下面给出了使用这个函数的示例。

//假设查询字符串是?q=javascript&num=10 
let args = getQueryStringArgs(); 
alert(args["q"]); //"javascript" 
alert(args["num"]); //"10"
位置操作

使用 location 对象可以通过很多方式来改变浏览器的位置。首先,也是最常用的方式,就是使用assign()方法并为其传递一个 URL,如下所示。
location.assign(“http://www.wrox.com”);
这样,就可以立即打开新 URL 并在浏览器的历史记录中生成一条记录。如果是将 location.href或 window.location 设置为一个 URL 值,也会以该值调用 assign()方法。例如,下列两行代码与显式调用 assign()方法的效果完全一样。
window.location = “http://www.wrox.com”;
location.href = “http://www.wrox.com”;
在这些改变浏览器位置的方法中,最常用的是设置 location.href 属性。

navigator 对象

查看浏览器的类型的方法。

检测插件

检测浏览器中是否安装了特定的插件是一种最常见的检测例程。对于非 IE 浏览器,可以使用plugins 数组来达到这个目的。该数组中的每一项都包含下列属性。
name:插件的名字。
description:插件的描述。
filename:插件的文件名。
length:插件所处理的 MIME 类型数量。
一般来说,name 属性中会包含检测插件必需的所有信息,但有时候也不完全如此。在检测插件时,需要像下面这样循环迭代每个插件并将插件的 name 与给定的名字进行比较。

//检测插件(在 IE 中无效)
function hasPlugin(name){ 
 name = name.toLowerCase(); 
 for (var i=0; i < navigator.plugins.length; i++){ 
 if (navigator. plugins [i].name.toLowerCase().indexOf(name) > -1){ 
 return true; 
 } 
 } 
 return false; 
} 
//检测 Flash 
alert(hasPlugin("Flash")); 
//检测 QuickTime 
alert(hasPlugin("QuickTime"));

这个 hasPlugin()函数接受一个参数:要检测的插件名。第一步是将传入的名称转换为小写形式,以便于比较。然后,迭代 plugins 数组,通过 indexOf()检测每个 name 属性,以确定传入的名称是否出现在字符串的某个地方。比较的字符串都使用小写形式可以避免因大小写不一致导致的错误。而传入的参数应该尽可能具体,以避免混淆。
检测 IE 中的插件比较麻烦,因为 IE 不支持 Netscape 式的插件。在 IE 中检测插件的唯一方式就是使用专有的 ActiveXObject 类型,并尝试创建一个特定插件的实例。IE 是以 COM 对象的方式实现插件的,而 COM 对象使用唯一标识符来标识。因此,要想检查特定的插件,就必须知道其 COM 标识符。例如,Flash 的标识符是 ShockwaveFlash.ShockwaveFlash。知道唯一标识符之后,就可以编写类似下面的函数来检测 IE 中是否安装相应插件了。

//检测 IE 中的插件
function hasIEPlugin(name){ 
 try { 
 new ActiveXObject(name); 
 return true; 
 } catch (ex){ 
 return false; 
 } 
} 
//检测 Flash 
alert(hasIEPlugin("ShockwaveFlash.ShockwaveFlash")); 
//检测 QuickTime 
alert(hasIEPlugin("QuickTime.QuickTime")); 
screen 对象

JavaScript 中有几个对象在编程中用处不大,而 screen 对象就是其中之一。screen 对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等。

history 对象

history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。因为 history 是 window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的 history 对象与特定的window 对象关联。出于安全方面的考虑,开发人员无法得知用户浏览过的 URL。不过,借由用户访问过的页面列表,同样可以在不知道实际 URL 的情况下实现后退和前进。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值