js高级程序设计:BOM、客户端检测

BOM

window对象

在浏览器中,window 对象有双重角色,它既是通过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象

全局作用域

  1. 在全局作用域中声明的变量、函数都会变成 window 对象的属性和方法
  2. 定义全局变量与在 window 对象上直接定义属性的差别:全局变量不能通过 delete 操作符删除,而直接在 window 对象上的定义的属性可以
    后面的内容在首页不显示,请点击下方的展开全文或者

窗口关系和框架

  1. 如果页面中包含框架,则每个框架都拥有自己的 window 对象,并且保存在 frames 集合中
  2. 在 frames集合中,可以通过数值索引(从 0 开始,从左至右,从上到下)或者框架名称来访问相应的 window 对象。每个 window 对象都有一个 name 属性,其中包含框架的名称
  3. window对象的框架属性
  • top 对象始终指向最高(最外)层的框架,也就是浏览器窗口。使用它可以确保在一个框架中正确地访问另一个框架。例如top.frames[0]
  • parent(父)对象始终指向当前框架的直接上层框架。在某些情况下,parent 有可能等于 top;但在没有框架的情况下,parent 一定等于top(此时它们都等于 window)
  • self对象,它始终指向 window;实际上,self 和 window 对象可以互换使用
  1. 在使用框架的情况下,浏览器中会存在多个 Global 对象。在每个框架中定义的全局变量会自动成为框架中 window 对象的属性
  2. 跨框架传递的对象使用 instanceof 操作符有影响

窗口位置

  1. 使用 moveTo()和 moveBy()方法是有可能将窗口精确地移动到一个新位置,这两个方法都接收两个参数,其中moveTo()接收的是新位置的 x 和 y 坐标值,而 moveBy()接收的是在水平和垂直方向上移动的像素数
  2. 注意在 Opera 和 IE 7(及更高版本)中默认就是禁用的。另外,这两个方法都不适用于框架,只能对最外层的 window 对象使用。

窗口大小

  1. 不同浏览器,不同版本取得窗口大小的方法不一样
  2. 使用 resizeTo()和 resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接收两个参数,其中 resizeTo()接收浏览器窗口的新宽度和新高度,而 resizeBy()接收新窗口与原窗口的宽度和高度之差
  3. 注意:在 Opera和 IE7(及更高版本)中默认就是禁用的。另外,这两个方法同样不适用于框架,而只能对最外层的window 对象使用。

导航与打开窗口

  1. window.open()方法既可以导航到一个特定的 URL,也可以打开一个新的浏览器窗口。这个方法可以接收 4 个参数,通常只须传递第一个参数,最后一个参数只在不打开新窗口的情况下使用.该方法会返回一个指向新窗口的引用,通过这个引用可以对新窗口进行调整
  • 要加载的 URL、
  • 窗口目标,可以是_self、_parent、_top 或_blank,或者已有窗口或框架的名称,
  • 一个特性字符串,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NYUjIE3o-1569921280084)(JavaScript高级程序设计_files/6.jpg)]
  • 一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。
    举例
window.open("http://www.wrox.com/","wroxWindow", "height=400,width=400,top=10,left=10,resizable=yes");/*这行代码会打开一个新的可以调整大小的窗口,窗口初始大小为 400×400 像素,并且距屏幕上沿
和左边各 10 像素。*/
  1. 对于浏览器的主窗口,如果没有得到用户的允许是不能关闭它的。不过,弹出窗口倒是可以调用 top.close()在不经用户允许的情况下关闭自己,弹出窗口关闭之后,窗口的引用仍然还在
  2. 新创建的 window 对象有一个 opener 属性,其中保存着打开它的原始窗口对象。这个属性只在弹出窗口中的最外层 window 对象(top)中有定义,而且指向调用 window.open()的窗口或框架。将 opener 属性设置为 null 就是告诉浏览器新创建的标签页不需要与打开它的标签页通信,因此可以在独立的进程中运行
  3. 安全限制
    不同浏览器限制方法各有不同,一般有不允许在屏幕之外创建弹出窗口、不允许将弹出窗口移动到屏幕以外、不允许关闭状态栏,默认情况下不允许移动弹出窗口或调整其大小
  4. 弹出窗口屏蔽程序
    在弹出窗口被屏蔽时,考虑两种情况:
  • 如果是浏览器内置的屏蔽程序阻止的弹出窗口,那么 window.open()很可能会返回 null
  • 如果是浏览器扩展或其他程序阻止的弹出窗口,那么 window.open()通常会抛出一个错误
//检测出弹出窗口是否被屏蔽
var blocked = false;
try { var wroxWin = window.open("http://www.wrox.com", "_blank"); if (wroxWin == null){ blocked = true; }
} catch (ex){ blocked = true;
}
if (blocked){ alert("The popup was blocked!");
}

间歇调用和超时调用

  1. 超时调用需要使用 window 对象的 setTimeout()方法,在指定的时间过后执行代码,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒)
  • 第一个参数可以是一个包含 JavaScript 代码的字符串(不建议使用),也可以是一个函数
  • 第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后指定的代码不一定会执行,因为js是单线程的,一定时间只能执行一段代码,代码执行由js任务队列管理,这个参数只是告诉JS过多久时间将当前任务添加到队列中,如果队列中不是空的,那要等前面的代码执行完成再执行
    调用 setTimeout()之后,该方法会返回一个数值 ID,表示超时调用。这个超时调用 ID 可以用来取消超时调用
  1. 要取消尚未执行的超时调用计划,可以调用clearTimeout()方法并将相应的超时调用 ID 作为参数传递给它
//设置超时调用
var timeoutId = setTimeout(function() { alert("Hello world!");
}, 1000);
//注意:把它取消
clearTimeout(timeoutId);
  1. setInterval()间歇调用,按照指定的时间间隔重复执行代码,直至间歇调用被取消或者页面被卸载,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒),参数与setTimeOut相同
var num = 0;
var max = 10;
var intervalId = null;
function incrementNumber() { num++; //如果执行次数达到了 max 设定的值,则取消后续尚未执行的调用if (num == max) { clearInterval(intervalId); alert("Done"); }
}
intervalId = setInterval(incrementNumber, 500);

调用 setInterval()方法同样也会返回一个间歇调用 ID,该 ID 可用于在将来某个时刻取消间歇调用
如果不取消间歇调用,间歇调用将会一直执行到页面卸载
4. 取消尚未执行的间歇调用,可以使用 clearInterval()方法并传入相应的间歇调用 ID
5. 使用超时调用来模拟间歇调用,最好不要使用间歇调用,因为后一个间歇调用可能会在前一个间歇调用结束之前启动

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

系统对话框

alert()、confirm()和 prompt()方法,系统对话框与在浏览器中显示的网页没有关系,也不包含 HTML。它们的外观由操作系统及(或)浏览器设置决定,而不是由 CSS 决定

  1. alert()方法,这个方法接受一个字符串并给用户显示一个系统对话框,其中包含指定的文本和一个 OK(“确定”)按钮
  2. confirm()方法,显示的对话框除了显示 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. ");
}
  1. 用 prompt()方法,个“提示”框,用于提示用户输入一些文本。提示框中除了显示 OK 和 Cancel 按钮之外,还会显示一个文本输入域,以供用户在其中输入内容。prompt()方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(可以是一个空字符串)。
  • 如果用户单击了 OK 按钮,则 prompt()返回文本输入域的值;如果用户单击了 Cancel 或没有单击OK 而是通过其他方式关闭了对话框,则该方法返回 null。

location 对象

  1. location 对象是很特别的一个对象,因为它既是 window 对象的属性,也是document 对象的属性;换句话说,window.location 和 document.location 引用的是同一个对象
  2. location 对象的用处不只表现在它保存着当前文档的信息,还表现在它将 URL 解析为独立的片段,让开发人员可以通过不同的属性访问这些片段
  3. location对象的属性,[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VtjHlkCI-1569921280085)(JavaScript高级程序设计_files/7.jpg)]

查询字符串参数

  1. 访问 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; }//假设查询字符串是?q=javascript&num=10 var args = getQueryStringArgs(); alert(args["q"]); //"javascript" alert(args["num"]); //"10"

位置操作

  1. 改变浏览器位置可以使用assign()方法并为其传递一个 URL
location.assign("http://www.wrox.com");
//相当于
window.location = "http://www.wrox.com";
location.href = "http://www.wrox.com";
  1. 些改变浏览器位置的方法中,最常用的是设置 location.href 属性。
  2. 修改location对象的其他属性也可以改变当前加载的页面,每次修改 location 的属性(hash 除外),页面都会以新 URL 重新加载。
  3. 通过上述任何一种方式修改 URL 之后,浏览器的历史记录中就会生成一条新记录,因此用户通过单击“后退”按钮都会导航到前一个页面。如果不希望产生新纪录可以使用 replace()方法导航到其他页面
  4. reload(),作用是重新加载当前显示的页面。如果调用 reload()时不传递任何参数,页面就会以最有效的方式重新加载,如果传递参数 true,强制从服务器重新加载。位于 reload()调用之后的代码可能会也可能不会执行,这要取决于网络延迟或系统资源等因素。为此,最好将 reload()放在代码的最后一行。
location.reload(); //重新加载(有可能从缓存中加载)
location.reload(true); //重新加载(从服务器重新加载)

navigator 对象

  1. 属性[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OeTJj60G-1569921280086)(JavaScript高级程序设计_files/8.jpg)]

检测插件

  1. 对于非 IE 浏览器,可以使用plugins 数组来达到这个目的。该数组中的每一项都包含下列属性
  • name:插件的名字。
  • description:插件的描述。
  • filename:插件的文件名
  • length:插件所处理的 MIME 类型数量。
//检测插件(在 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"));
  1. 在 IE 中检测插件的唯一方式就是使用专有的 ActiveXObject 类型,并尝试创建一个特定插件的实例。IE是以 COM 对象的方式实现插件的,而 COM 对象使用唯一标识符来标识。因此,要想检查特定的插件,就必须知道其 COM 标识符
//检测 IE 中的插件
function hasIEPlugin(name){ try { //创建未知 COM 对象会导致抛出错误new ActiveXObject(name); return true; } catch (ex){ return false; }
}
//检测 Flash
alert(hasIEPlugin("ShockwaveFlash.ShockwaveFlash"));
//检测 QuickTime
alert(hasIEPlugin("QuickTime.QuickTime"));
  1. 典型的做法是针对每个插件分别创建检测函数
//检测所有浏览器中的 Flash
function hasFlash(){ var result = hasPlugin("Flash"); if (!result){ result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash"); }return result; }//检测 Flash alert(hasFlash());

注册处理程序

registerContentHandler()和 registerProtocolHandler()方法,这两个方法可以让一个站点指明它可以处理特定类型的信息

  1. registerContentHandler()方法接收三个参数:要处理的 MIME 类型(资源的媒体类型)、可以处理该 MIME类型的页面的 URL 以及应用程序的名称
//将一个站点注册为处理 RSS 源的处理程序
navigator.registerContentHandler("application/rss+xml", "http://www.somereader.com?feed=%s", "Some Reader");// %s 表示RSS 源 URL
  1. registerProtocolHandler()方法,它也接收三个参数:要处理的协议(例如,mailto 或 ftp)、处理该协议的页面的 URL 和应用程序的名称
// 将一个应用程序注册为默认的邮件客户端
navigator.registerProtocolHandler("mailto", "http://www.somemailclient.com?cmd=%s", "Some Mail Client");

screen对象

  1. screen 对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等
  2. 每个浏览器中的 screen 对象都包含着各不相同的属性
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5OwsEH2P-1569921280087)(JavaScript高级程序设计_files/9.jpg)]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-46Rcx7cp-1569921280089)(JavaScript高级程序设计_files/10.jpg)]

history对象

history 是 window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的 history 对象与特定的window 对象关联

  1. 用 go()方法可以在用户的历史记录中任意跳转,可以向后也可以向前。
  • 这个方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(类似于单击浏览器的“后退”按钮),正数表示向前跳转(类似于单击浏览器的“前进”按钮,0表示刷新当前页面
  • 也可以给 go()方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置——可能后退,也可能前进,具体要看哪个位置最近。如果历史记录中不包含该字符串,那么这个方法什么也不做
//后退一页
history.go(-1);
//前进两页
history.go(2);
//跳转到最近的 wrox.com 页面
history.go("wrox.com");
  1. back()和 forward()来代替 go()模仿浏览器的“后退”和“前进”按钮
  2. history 对象还有一个 length 属性,保存着历史记录的数量
if (history.length == 0){ //这应该是用户打开窗口后的第一个页面
}

客户端检测

浏览器之间的差异以及不同浏览器的“怪癖”(quirk),多得简直不胜枚举。因此,客户端检测除了是一种补救措施之外,更是一种行之有效的开发策略。不到万不得已,就不要使用客户端检测,先设计最通用的方案,然后再使用特定于浏览器的技术增强该方案

能力检测(特性检测)

  1. 能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。采用这种方式不必顾及特定的浏览器如何如何,只要确定浏览器支持特定的能力,就可以给出解决方案
  2. 模式
if (object.propertyInQuestion){ //使用 object.propertyInQuestion
}
//示例,IE 的早期版本中确实不存在 document.getElementById()
function getElement(id){ if (document.getElementById){ return document.getElementById(id); } else if (document.all){ return document.all[id];} else { throw new Error("No way to retrieve element!"); } }
  1. 必须测试实际要用到的特性。一个特性存在,不一定意味着另一个特性也存在

更可靠的能力检测

  1. 示例,检测一个对象是否支持排序
//不要这样做!这不是能力检测——只检测了是否存在相应的方法
function isSortable(object){ return !!object.sort;
}
//任何包含 sort属性的对象也会返回 true,上面的方法就检测不出来了
var result = isSortable({ sort: true });
//这样更好:检查 sort 是不是函数
function isSortable(object){
return typeof object.sort == "function";
}
  1. 在可能的情况下,要尽量使用 typeof 进行能力检测。特别是,宿主对象没有义务让 typeof 返回合理的值,尤其是在IE中typeof返回的值不一定合理
  2. 在浏览器环境下测试任何对象的某个特性是否存在,要使用下面这个函数
//作者:Peter Michaux
function isHostMethod(object, property) { var t = typeof object[property]; return t=='function' || (!!(t=='object' && object[property])) || t=='unknown';
}
result = isHostMethod(xhr, "open"); //true

能力检测,不是浏览器检测

在实际开发中,应该将能力检测作为确定下一步解决方案的依据,而不是用它来判断用户使用的是什么浏览器

怪癖检测

目标是识别浏览器的特殊行为,知道浏览器存在什么缺陷bug

  1. 举例
  • ,IE8 及更早版本中存在一个 bug,即如果某个实例属性与[[Enumerable]]标记为 false 的某个原型属性同名,那么该实例属性将不会出现在fon-in 循环当中
var hasDontEnumQuirk = function(){ var o = { toString : function(){} }; for (var prop in o){
if (prop == "toString"){ return false; } } return true;
}();
  1. “怪癖”都是个别浏览器所独有的,而且通常被归为 bug

用户代理检测

  1. 用户代理检测通过检测用户代理字符串(指明浏览器的名称和版本号)来确定实际使用的浏览器
  • 在服务器端,通过检测用户代理字符串来确定用户使用的浏览器是一种常用而且广为接受的做法
  • 在客户端,用户代理检测一般被当作一种万不得已才用的做法,其优先级排在能力检测和(或)怪癖检测之后
  1. 电子欺骗,就是指浏览器通过在自己的用户代理字符串加入一些错误或误导性信息,来达到欺骗服务器的目的

用户代理字符串的历史,了解就好啦

用户代理字符串检测技术

  1. 识别呈现引擎,五大呈现引擎:IE、Gecko、WebKit、KHTML 和 Opera
  2. 识别浏览器
  3. 识别平台,三大主流平台是 Windows、Mac 和 Unix(包括各种 Linux
  4. 识别 Windows 操作系统
  5. 识别移动设备
  6. 识别游戏系统

完整的代码。略过,想知道自己看书去P260

使用方法

用户代理检测一般适用于下列情形

  • 不能直接准确地使用能力检测或怪癖检测
  • 同一款浏览器在不同平台下具备不同的能力。
  • 为了跟踪分析等目的需要知道确切的浏览器。

js高级程序设计第四部分相关推荐

  1. 读书笔记 - js高级程序设计 - 第四章 变量 作用域 和 内存问题

    5种基本数据类型 可以直接对值操作 判断引用类型 var result = instanceof Array 执行环境 每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对 ...

  2. JS高级程序设计——阅读笔记四

    JS高级程序设计--阅读笔记四 第六章 集合引用类型 6.1 Object 6.2 Array 6.2.1 创建数组 from()函数 6.2.2 数组空位 6.2.3 数组索引 6.2.4 检测数组 ...

  3. 《Ext JS 高级程序设计》的目录与样张

    第一部分 Ext Core 第1 章 Ext Core 重要概念 ············· 2 1.1 Ext.Element······························· 2 1. ...

  4. Ext JS高级程序设计

    Ext JS高级程序设计 图书详细情况查看: http://www.china-pub.com/193076 市场价 :¥59.00 会员价 : ¥44.25(75折) [作 者]黄灯桥;徐会生 [同 ...

  5. 读js高级程序设计中有感

    我现在都到js高级程序设计最难的章节,第六章,对象,虽然有人推荐不用全部读完,但我还是完整的读一遍吧,一遍可以敲代码一边看书理解加百度,我认为这种方式很好,可以加深理解增强印象,这是我觉得这本书比JS ...

  6. JavaScript高级程序设计第四版学习--第二十四章

    title: JavaScript高级程序设计第四版学习–第二十四章 date: 2021-5-31 10:46:01 author: Xilong88 tags: JavaScript 本章内容: ...

  7. JS高级程序设计【红宝书】学习笔记——数据类型

    目录 数据类型 Number类型 1.值的范围 2.NaN 3.数值转换 String类型 1.字符字面量(详见JS高级程序设计P63 2.转换为字符串 Symbol类型 Object类型 objec ...

  8. Js高级程序设计第三版学习(十二章)

                                  Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3   1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...

  9. JS高级程序设计拾遗

    <JavaScript高级程序设计(第三版)>反反复复看了好多遍了,这次复习作为2017年上半年的最后一次,将所有模糊的.记不清的地方记录下来,方便以后巩固. 0. <script& ...

最新文章

  1. 如何在python开发的GUI界面程序中恰当地使用PyExecJS
  2. [转]Android NDK几点回调方式
  3. [***]HZOJ 跳房子
  4. 贫穷中透着零基础的单人制作游戏手册之三:独立游戏怎么评估Steam市场
  5. 错误代码1500什么意思_啊早安打工人是什么梗???
  6. Ubuntu系统下允许Apache的mod_rewrite功能
  7. mysql命令的依赖库_3.EZMM工程(常用shell命令,及需要用到的基本依赖库)
  8. wlst启动weblogic
  9. Android进阶笔记12:ListView篇之图片优化
  10. Java菜鸡的学习日常——2021华为软挑(练手)
  11. 使用动软.net代码生成器生成数据库文档
  12. HBuilder X运行到微信小程序报错 [微信小程序开发者工具] Error: read EBADF
  13. 人工智能为什么要用Python语言?
  14. UNIX 标准化 --ISO C标准 IEEE POSIX 标准 Single Unix Specification(SUS)
  15. 自己制作 Android Vector Asset 矢量图
  16. NLP--2 语言结构和传统pipeline
  17. halcon变量,图像与C++的一些转换(未完待续)
  18. English Learning - L3 综合练习 1 VOA-Color 2023.04.26 周三
  19. stm32封装库官网下载方法 bxl下载
  20. 4.口袋西游怪物周围遍历(01)

热门文章

  1. 网贷风控体系之-决策引擎
  2. Ukey证书校验流程和使用注意事项
  3. 计算机文化教程实验基础知识,《计算机文化基础》课程实验教学大纲
  4. 高防BGP服务器速度怎么样?选用高防BGP服务器需要考虑什么
  5. 基于Netty的Android局域网IP电话
  6. C#模拟QQ项目源代码
  7. php是什么电荷,分子中电荷变化种种 - 量子化学 - 小木虫 - 学术 科研 互动社区...
  8. GQM 概述:构建研发效能度量体系的根本方法
  9. 归并排序的思想以及应用——试解《逆序对的数量》
  10. 墨者学院-SQL注入漏洞测试(布尔盲注)