javaScript核心-BOM

224 阅读9分钟

Window对象

BOM的核心是window对象,表示浏览器的实例,window对象在浏览器中有两重身份,一个是ECMAScript中的Global对象,另一个就是浏览器窗口的JavaScript接口,这就意味着网页中定义的所有对象、变量、和函数都以window作为其Global对象,都可以访问它上面的全局方法。

Global作用域

因为window对象被复用为ECMAScript的Global对象,所以通过var声明的所有全局变量和函数都会变成window对象的属性和方法。
注意:访问未声明的变量会抛出错误,但是可以在window对象上查询是否存在可能未声明的变量。 JavaScript中有很多对象都暴露在全局作用域中,比如location和navigator,因而他们也是window对象的属性。

窗口关系

top对象始终指向最外(上)层窗口,即浏览器窗口本身。而parent对象始终指向当前窗口的父窗口,如果当前窗口是最上层窗口,则parent等于top。最上层的window如果不是通过window.open打开的,那么其name属性就不会包含值。
还有一个self对象,它是终极window属性,始终会指向window。

窗口位置与像素比

window对象的位置可以通过它暴露的api方法去移动。现代的浏览器都提供了screenLeft和screenTop属性,用于表示窗口相对于屏幕左侧和顶部的位置,返回的单位是css像素。
可以使用moveTo和moveBy方法移动窗口,这两个方法都接受两个参数,其中moveTo接受要移动的新位置的绝对坐标x和y,而moveBy则接受相对当前位置在两个方向上移动的像素数。
像素比: css像素是web开发中使用的统一像素单位,这个单位的背后其实是一个角度:0.0213度,换句话说,如果屏幕距离人眼是一臂长,则以这个角度计算的css像素大小约是1/96英寸。从这个解释大家就应该知道,css的像素是一个逻辑单位,或者可以试着理解为一个长度单位,不管是什么分辨率的设备,1/96英寸的长度就是一个css像素。但是实际上这一个css像素可能会由好几个物理像素组成。
window.devicePixelRatio表示物理像素与逻辑像素之间的缩放系数。

导航与打开新窗口

window.open()方法可以用于导航到指定URL,也可以用来打开新浏览器窗口,这个方法接收4个参数,要加载的URL,目标窗口,特性字符串,和表示新窗口在浏览器历史记录中是否代替当前加载页面的布尔值。通常,调用这个方法时只传前3个参数,最后一个参数只有在不打开新窗口时才会使用。
如果window.open()的第二个参数是一个已经存在的窗口或者窗格的名字,则会在对应的窗口或窗格中打开URL。
弹出窗口: 如果window.open()的第二个参数不是已有窗口,则会打开一个新窗口或者标签页。第三个参数,即特性字符串,可以配置即将要打开的新窗口的特性,如果没传第三个参数,默认使用浏览器的默认配置。特性字符创是一个逗号分隔的设置字符串,如下:

window.open('url', 'name',"height=300,width=300,top=10,left=10,resizable=yes")

window.open()方法返回一个对新建窗口的引用,这个对象跟普通的window对象没有什么区别,只是为了控制新窗口提供了方便。

let oneWindow = window.open('url', 'name');
oneWindow.resizeTo(500, 500);
oneWindow.moveTo(100, 100);

注意window.close()方法只能用来关闭通过window.open()打开的窗口。
新建窗口的window对象有一个属性opener,指向打开它的窗口。

let oneWindow = window.open('url', 'name');
alert(oneWindow.opener === window); // true

虽然新建窗口中有指向打开它的窗口的指针,但反之不然,窗口不会记录自己打开的窗口,需要开发者自己记录。 把opener设置为null,表示新打开的标签页不需要与打开它的标签页通信,因此新的标签页可以在独立进程中运行,这个连接一旦切断,就无法恢复了。

安全限制和弹窗屏蔽程序

弹出窗口有段时间被在线广告用滥了,因此为了限制弹窗广告,浏览器开始对不合理的弹窗施加限制,现在只有用户触发了某个事件,才会创建弹窗,在网页加载过程中调用window.open()则打不开。
如果想知道弹窗是否被浏览器拦截了,可以看window.open()方法的返回值:

//在浏览器扩展或者其他程序屏蔽弹窗时,window.open()方法通常会抛出错误,因此要准确检测弹窗是否被屏蔽,最好用try/catch包装一下。
let blocked = false;
try {
  let oneWindow = window.open('url', 'name');
  if (oneWindow === null) {
    blocked = true;
  }
} catch (ex) {
  blocked = true;
}
if (blocked) {
  alert('弹窗被屏蔽了');
}

location对象

location是最有用的BOM对象之一,提供了当前窗口中加载文档的信息,以及通常的导航功能。该对象独特的是它既是window的属性又是document的属性。window.location和document.location实际上指向的是同一个对象。location对象不仅保存着当前加载文档的信息,也保存着把URL解析为离散片段后能通过属性访问的信息。

属性
location.hash哈希值
location.host服务器名和端口号
location.hostname服务器名
location.href当前加载页面的完整URL
location.protocal页面使用的协议

查询字符串

location的多数信息都可以通过上面的属性获取,但是在URL中的查询字符串并不容易使用。为了更好的使用查询字符串的值,我们可以自己定义一个方法,也可以使用URLSearchParams类。

let getQueryStringArgs = function() {
  let qs = (location.search.length > 0) ? location.search.substring(1) : '';
  let args = {};
  for (let item of qs.split('&').map(kv => kv.split('='))) {
    let name = decodeURIComponent(item[0]);
    value = decodeURIComponent(item[1]);
    if (names.length) {
      args[name] = value;
    }
  }
  return args;
}
// URLSearchParams 提供了一组标准的API方法,通过他们可以检查和修改查询字符串。给URLSearchParams构造函数可以传如
//一个字符串,就可以创建一个实例。这个实例上暴露了get,set,delete方法,可以对查询字符串执行相应操作。
let qs = "?a=2&b=3";
let search = new URLSearchParams(qs);
console.log(search.get('a'));
console.log(search.has('a'));
for(let item of search) {
console.log(item);
}

操作地址

可以通过修改location对象修改浏览器的地址,常用的方法有assign方法,使用该方法会立即启动导航到新URL的操作,同时还会在浏览器历史记录中增加一条记录。如果给location.href或window.location设置一个URL,也会以同一个值调用assign方法。下面的两行代码都会执行与显示调用assign一样的操作。

location.assign('http://www.com');
window.location = 'http://www.com';
location.href = 'http://www.com';

注意:修改location对象的属性也会修改当前加载的页面。其中,hash,search,hostname,pathname,port属性被设置为新值之后都会修改当前URL。除了hash之外,只要修改location的一个属性,就会导致页面重新加载新的URL。修改hash的值会在浏览器历史中增加一条新纪录,同样上面其他的值也会增加对应的历史记录。如果不希望增加历史记录,可以调用replace方法,它接受一个URL参数。此外,能修改地址的还有一个reload方法,他能重新加载当前显示的页面。调用reload而不传参数,页面会以最有效的方式重新加载,也就是说可能会从缓存中加载,如果想要强制从服务器重新加载,可以给这个方法传一个true参数。

location.reload(); // 重新加载,可能会从缓存加载
location.reload(true); // 重新从服务器加载 

注意: 脚本中位于reload()方法调用之后的代码可能执行也可能不执行,这取决于网络延迟和系统资源等因素。因此,最好把reload()放到最后一行代码处。

navigator对象

navigator是由Netscape Navigator2最早引入浏览器的,现在已经成为客户端标识浏览器的标准,只要浏览器启用JavaScript,navigator对象就一定存在,与其他BOM对象一样,每个浏览器都支持自己的属性。下面是一些常见的navigator对象的属性:

属性/方法描述
appName浏览器全名
cookieEnabled返回布尔值,表示是否启用了cookie
deviceMemory返回单位为GB的设备内存容量
onLine返回布尔值,表示浏览器是否联网
userAgent返回浏览器的用户代理字符串
vibrate()触发设备振动

检测插件

检测浏览器是否安装了某个插件是开发中常见的需求,处IE10及更低版本外的浏览器,都可以通过plugins数组来确定。这个数组中的每一项都包含如下属性。name插件名称,description插件介绍,filename插件的文件名,length由当前插件处理的MIME类型数量。
通常name属性包含识别插件所需的必要信息,尽管不是特别准确。

let hasPlugin = function (name) {
  name = name.toLowerCase();
  for(let plugin of window.navigator.plugins) {
    if (plugins.name.toLowerCase().indexOf(name) > -1) {
      return true;
    }
  }
  return false;
}
alert(hasPlugin("Flash"));

// 旧版本的插件检测
//IE10及更低版本中检测插件问题比较多,需要使用专有的ActiveXObject,并尝试实例化特定的插件。IE中的插件是实现为
//COM对象的,由唯一的字符串标识。因此,要检测某个插件就必须知道其COM标识符,例如Flash的标识符是"ShockwaveFlash.ShockwaveFlah"。

function hasIEplugin(name) {
  try {
    new ActiveXObject(name);
    return true;
  } catch (ex) {
    return false;
  }
}
alert(hasIEplugin("ShockwaveFlash.ShockwaveFlah"));

history对象

history对象表示当前窗口首次使用以来用户的导航历史记录。因为history是window的属性,所以每个window都有自己的history对象。出于安全考虑,这个对象并不会暴露用户访问过的URL,但是可以通过浏览器的前进后退按钮访问相应的URL。

导航

go()方法可以在用户历史记录中沿任何方向导航,可以前进也能后退。这个方法只接受一个参数,这个参数可以是一个整数,表示前进或者后退多少步。负值代表后退,正直代表前进。
go()方法的参数也可以是一个字符串,这种情况下浏览器会导航到历史中包含该字符串的第一个位置。最接近的位置可能涉及后退,也可能涉及前进。如果历史记录中没有匹配的项,则这个方法什么也不做。
go有两个简写方法,分别是back(),forward()。顾名思义,这两个方法模拟了浏览器的后退按钮和前进按钮。history.back(),history.forward()。
history对象还有一个length属性,表示历史记录中有多个条目。通过判断history.length是否等于1可以确定用户浏览器的起点是不是你的页面。