毫无疑问,我们学习JavaScript是为了完成特定的功能。在最初的JavaScript类型系统中,我们已经分析过JavaScript在页面开发中充当着添加逻辑的角色,而且我们知道JavaScript不仅仅包含基本的语法规范。下面我们就重点看一下JavaScript在页面中干的那些事。总的来说,JavaScript在页面端就干两件事:操作DOM与操作BOM (当然了向Server获取数据也是它的工作,不过获取到数据后还是回来干这两件事,大家对JavaScript最直接的印象应该就是各种光怪陆离的特效)。
 
操作BOM
  这里先看一下简单的BOM操作,BOM全称是Browser Object Model,说白了就是从浏览器抽象出来的JavaScript对象,使用这些对象就可以直接操作浏览器实现一些特殊的功能。 
在前面我们分析全局作用域的时候提到过的Window对象就是BOM中最重要的对象,它同时也是BOM最顶层的对象,通过这个对象我们可以轻松获得其它重要的对象,比如BOM中的Location,History,Navigator,Screen对象,DOM中最顶层的Document对象。
 
Window对象 - 浏览器窗口的抽象
  由于Window对象是窗口的抽象,所以很显然每新开一个窗口,都会创建一个全新的Window对象。
  每个页面的窗口对象可以在全局作用域中(在任何函数之外)通过this获得到,当然也可以在任何地方,任何时候通过window/self得到:
  1. <script type="text/javascript">
  2. alert(this);
  3. // 下面这两个可不局限于只能使用在全局作用域中,它们在任何时候获得的都是Window对象
  4. alert(self);
  5. alert(window);
  6. </script>

  这里的self专指窗口对象本身,它返回的对象跟window对象一模一样。

  在JavaScript中,我们定义在全局作用域中的成员都是window对象的成员,这个我们在前面已经说过了,除此之外,调用该对象的成员时是可以省略window对象:
  1. var a = 10;
  2. alert(a);
  3. alert(window.a);

  以后的例子中,我就省略window对象了。

  这里有个概念需要注意一下,仅仅注意一下就可以了,那就是JavaScript语言是存在全局对象的,这个对象与浏览器模型中的全局对象window严格来说不是一回事,但是浏览器的实现基本上把这个对象融合到了window对象中来了,也就是说从window对象可以直接调用全局对象的方法(不管是重写了,还是怎么样处理了,反正是统一了),所以使用的时候无人对它们进行区分,这里也仅仅就是提一下这个概念,以后也不再区分,因为对于前端的JavaScript来说,离开浏览器什么也不是;但是这种情况对于Server端的JavaScript就不一样了,在Nodejs中,你可以明确的感觉到JavaScript全局对象的存在。感兴趣的同学可以参看下面两个分别介绍JavaScript全局对象与BOM的window对象的链接:
 
  window对象(含JavaScript的全局对象)内置了很多方法,这些方法就是我们经常使用的全局方法。 获得window对象以后,可以做下面一些事:
1. 与用户简单进行信息交互: alert(), confirm(), prompt()
  这里面alert我们前面已经用过很多次了,其余两个也是类似的对话框:
  1. alert用于显示一段信息和一个确认按钮。
  2. confirm用于显示一段信息,一个确认按钮和一个取消按钮。
  3. prompt用于让用于输入一个信息。

  看一个简单的例子就可以了:

  1. <div id="testDiv" onclick="demo()">Click Me!</div>
  2. <script type="text/javascript">
  3. function demo() {
  4. var result = confirm('确认处理div的事件吗?');
  5. if (result == true) {
  6. alert('你选择确认处理div的事件了');
  7. var name = prompt('请输入你的名字!', 'Frank');
  8. if (name != null && name != '') {
  9. alert('Hello ' + name + '!');
  10. }
  11. } else {
  12. alert('你选择取消处理div的事件了');
  13. }
  14. }
  15. </script>
2. 类型判断与转换: parseInt(), parseFloat(), Number(), String(), Boolean(), isNaN(), isFinite()
  这些方法在类型系统里面已经总结过了,不再重复。
 
3. 开启关闭窗口: open(), close()
  1. open方法用于打开一个新的浏览器窗口或查找一个已命名的窗口。
  2. close方法用于关闭当前的窗口。

  看一下的例子:

  1. <div id="testDiv" onclick="demo()">Click Me!</div>
  2. <script type="text/javascript">
  3. function demo() {
  4. open('http://www.google.com');
  5. alert('新窗口已经打开,本窗口准备关闭!');
  6. close();
  7. }
  8. </script>

  注意open方法可以携带很多的参数,通过这些参数可以定制新窗口的许多特征,比如窗口大小,位置,状态等,不再详述,需要的时候直接查阅W3School上的说明即可。

4. 以特殊的方式运行一些代码: eval(), setTimeout(), clearTimeout(), setInterval(), clearInterval()
  简单的来说,eval用于将参数字符串转换成JavaScript代码并执行:
  1. eval('var a = 10; alert(a);');

  eval用好了可以化腐朽为神奇,用坏了可以导致网页一败涂地,这是个争议最多,也是安全风险最高的操作之一因为恶意用户很可能给你的页面传输一些包含可执行代码的字符串,一旦你使用eval去执行了,有可能你的服务器就收到攻击了,所以我的建议也是尽量少用这个方法,除非你深知使用它不会有问题,并且代码只有你能控制,不会有别人干预,这个条件过于苛刻了。

  setTimeout与clearTimeout是一组配套的方法,前者用于延迟一段时间执行代码,后者用于取消这个延迟操作:
  1. var timeout = setTimeout(function() {
  2. alert('timeout!');
  3. }, 1000);
  4.  
  5. //clearTimeout(timeout);

注意例子中的clearTimeout被注掉了,如果不注掉的话,那个alert就出不来了。

  setTimeout是可以实现循环效果的,这种循环可以作为动画的基础:
  1. function animation() {
  2. // 动画绘制...
  3. document.writeln('动画重绘了...');
  4. setTimeout('animation()', 1000);
  5. }
  6. // 启动动画流程
  7. animation();

  不过很多人推荐如下的动画写法,这种写法效率更高:

  1. // 一般是在初始化以后启动动画的循环
  2. (function animloop() {
  3. // 创建动画的推荐做法,不推荐使用setTimeout或者setInterval方法
  4. window.requestAnimationFrame(animloop);
  5. // 动画的逻辑,通常是更新窗口的内容,形成动画
  6. self.tick();
  7. })();

  setTimeout与clearTimeout配合使用也可以实现一些带停止效果的循环特效,比如下面的可停止秒表:

  1. <input type="button" value="开始计时" onclick="timeCount()" />
  2. <input type="text" id="timetxt" size="5" />
  3. <input type="button" value="停止计时" onclick="stopCount()" />
  4. <script type="text/javascript">
  5. var count = 0;
  6. var timeID;
  7. function timeCount()
  8. {
  9. document.getElementById('timetxt').value = count;
  10. count++;
  11. // 下面的写法等同于: timeID = setTimeout(timeCount,1000);
  12. timeID = setTimeout('timeCount()',1000);
  13. }
  14. function stopCount()
  15. {
  16. clearTimeout(timeID);
  17. }
  18. </script>

  不过从语义上来说,下面的这两个方法也许更适合写这样的循环代码。

  setInterval与clearInterval是一组配套的方法,前者用于按照指定的周期(以毫秒计)来调用函数或计算表达式,后者用于取消这个循环。让我们用这两个方法重新实现以下上面秒表的例子:
  1. <input type="button" value="开始计时" onclick="startCount()" />
  2. <input type="text" id="timetxt" size="5" />
  3. <input type="button" value="停止计时" onclick="stopCount()" />
  4. <script type="text/javascript">
  5. var count = 0;
  6. var timeID;
  7. function addSecond() {
  8. count++;
  9. document.getElementById('timetxt').value = count;
  10. }
  11. function startCount()
  12. {
  13. document.getElementById('timetxt').value = 0;
  14. // 下面的写法等同于: timeID = setInterval(addSecond, 1000);
  15. timeID = setInterval('addSecond()', 1000);
  16. }
  17. function stopCount()
  18. {
  19. clearInterval(timeID);
  20. }
  21. </script>

  我们可以使用setTimeout与setInterval实现很多有趣的效果,不过这里还有一个问题需要解决,那就是如何给调用的函数传参数?这要借助这两个函数的第一个参数,它们的第一个参数可以是函数名、匿名函数、函数的引用以及其他可执行代码。上面的例子中我们使用了字符串形式的调用和直接使用函数名字的方式,下面看一下使用匿名函数的形式创建闭包来传递参数:

  1. function show(msg) {
  2. alert(msg);
  3. }
  4. var msg = 'Hi!'
  5. setTimeout(function() { show(msg);}, 100);
5. URL编码: escape(), unescape(), encodeURI(), decodeURI()
  1. escape方法将参数字符串编码生成可以用于URL的新字符串,比如把空格写成“%20”这种格式。“+”不被编码,如果要“+”也被编码,请用:escape('...', 1)。
  2. unescape escape的反过程。解码参数中字符串成为一般字符串。encodeURIdecodeURI两个方法是替代上面这两个方法的,功能基本没太大区别,但是推荐使用后面两个。

看个例子:

  1. // 推荐使用encodeURI与decodeURI
  2. var test1 = 'http://www.xxx.com.cn/My first/';
  3. var test2 = encodeURI(test1);
  4. document.write(test2 + '<br />');
  5. document.write(decodeURI(test2) + '<br />');
  6.  
  7. var test3 = '?!=()#%&';
  8. var test4 = escape(test3);
  9. document.write(test4 + '<br />');
  10. document.write( unescape(test4));
6. 操作窗口的尺寸信息: moveTo(), moveBy(), resizeTo(), resizeBy(), scrollTo(), scrollBy()
  使用这些方法可以移动窗口,改变窗口大小,滚动窗口,这些方法都接受两个参数:x和y坐标。以To结尾的方法处理的是绝对坐标,以By结尾的方法处理的是相对坐标。简单看个例子:
  1. <input type="button" value="移动myWindow" onclick="moveWin()" />
  2. <script type="text/javascript">
  3. myWindow = window.open('', '', 'width=200,height=100');
  4. myWindow.document.write('Hello');
  5. </script>
  6. <script type="text/javascript">
  7. function moveWin() {
  8. myWindow.moveTo(50,50)
  9. }
  10. </script>

  当然了,使用innerwidth, innerheight等属性是可以获得窗口的尺寸信息的。

7. 获取其它的BOM/DOM对象
  通过window对象,可以获取下面这些对象:
1). Location对象与History对象 - 地址信息与浏览记录信息的抽象
  这两个对象与浏览记录息息相关,从这里可以操作与获取浏览记录,实际编程中据我所知很少有人使用(也有可能很多人使用,只是我不知道),简单看个例子:
  1. <input type="button" value="New" onclick="newDoc()"></input>
  2. <input type="button" value="Back" onclick="goBack()"></input>
  3. <input type="button" value="Forward" onclick="goForward()"></input>
  4. <script type="text/javascript">
  5. // 当前地址
  6. document.write(location.href);
  7. // 输入新地址
  8. function newDoc(){
  9. location.assign('http://www.w3schools.com/js/js_window_history.asp');
  10. // 实现相同功能的其它方式
  11. // location.href = 'http://www.w3schools.com/js/js_window_history.asp';
  12. // location.replace('http://www.w3schools.com/js/js_window_history.asp');
  13. }
  14. // 后退到上一个地址,在这个例子中没什么意义,纯演示
  15. function goBack(){
  16. history.back();
  17. }
  18. // 前进道下一个地址
  19. function goForward(){
  20. history.forward();
  21. }
  22. </script>

  对于使用location对象打开新页面的3种方式需要说明一点,assign与href方式都会把新地址加入到历史记录中,这样你可以执行前进与后退操作,但是使用replace方式只是替换了当前的地址,并不会再历史记录中添加新的记录。

2). Navigator对象 - 浏览器信息的抽象
  这个对象可以用于获取浏览器的信息,看个例子:
  1. <input type="button" value="Navigator" onclick="showBroswer()"></input>
  2. <div id="example"></div>
  3. <script type="text/javascript">
  4. function showBroswer() {
  5. var txt = '<p>Browser CodeName: ' + navigator.appCodeName + '</p>';
  6. txt += '<p>Browser Name: ' + navigator.appName + '</p>';
  7. txt += '<p>Browser Version: ' + navigator.appVersion + '</p>';
  8. txt += '<p>Cookies Enabled: ' + navigator.cookieEnabled + '</p>';
  9. txt += '<p>Platform: ' + navigator.platform + '</p>';
  10. txt += '<p>User-agent header: ' + navigator.userAgent + '</p>';
  11. txt += '<p>User-agent language: ' + navigator.systemLanguage + '</p>';
  12.  
  13. document.getElementById('example').innerHTML = txt;
  14. }
  15. </script>

  我在Chrome上运行这个例子,得到下列混乱的信息:

  1. Browser CodeName: Mozilla
  2. Browser Name: Netscape
  3. Browser Version: 5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36
  4. Cookies Enabled: true
  5. Platform: Win32
  6. User-agent header: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36
  7. User-agent language: undefined

  这些信息通常不是很准确,比如浏览器的Name严重错误。除了appVersion和userAgent还可以勉强有解析的意义外,其他的似乎可以忽略了。

  navigator对象最常用的场景就是判断浏览器的类型去解决兼容性问题了。
  一般来说,通过JavaScript判断浏览器类型,我们通常使用两种方法,一种是根据各种浏览器独有的属性来分辨,另一种是通过分析navigator对象的userAgent属性来判断的。在许多情况下,判断出浏览器类型之后,还需判断浏览器版本才能处理兼容性问题,而判断浏览器的版本还是需要解析userAgent属性才能知道。现在比较流行的JavaScript框架,都有浏览器兼容的判断代码,像jquery,YUI就是使用userAgent,而Mootools则是使用用各种浏览器独有的属性来分辨。
  这两种检测方法都有其局限性,userAgent信息是可以通过代码修改的,所以检测userAgent信息可能会带来一定的风险。而使用不同特征来判断浏览器的方法,虽然在速度上比用正则表达式分析userAgent要来的快,不过这些特征可能会随浏览器版本而变化。比如,一种浏览器本来独有的特性取得了市场上的成功,其他浏览器也就可能跟着加入该特性,从而使该浏览器的独有特征消失,导致我们的判断失败。
  从上面的比较来看,相对比较保险的做法还是通过解析userAgent中的特征来判断浏览器类型。何况,反正判断版本信息也需要解析浏览器的userAgent的。所以,在我们的实际编程中,一般还是使用解析userAgent的方式,看下面的例子:
  1. var Sys = {};
  2. var ua = navigator.userAgent.toLowerCase();
  3. var s;
  4. (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
  5. (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
  6. (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
  7. (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
  8. (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
  9.  
  10. //以下进行测试
  11. if (Sys.ie) document.write('IE: ' + Sys.ie);
  12. if (Sys.firefox) document.write('Firefox: ' + Sys.firefox);
  13. if (Sys.chrome) document.write('Chrome: ' + Sys.chrome);
  14. if (Sys.opera) document.write('Opera: ' + Sys.opera);
  15. if (Sys.safari) document.write('Safari: ' + Sys.safari);

3). Screen对象 - 屏幕几何信息的抽象

  Screen对象比较特别,它是没有公开标准的对象,不过所有浏览器都不约而同的实现了这个对象。这个对象主要是获取浏览器的窗口信息,看个简单的例子:
  1. document.write("<p>可用高度: ")
  2. document.write(screen.availHeight + "</p>")
  3. document.write("<p>可用宽度: ")
  4. document.write(screen.availWidth + "</p>")
  5. document.write("<p>屏幕高度: ")
  6. document.write(screen.height + "</p>")
  7. document.write("<p>屏幕宽度: ")
  8. document.write(screen.width + "</p>")

  可用高度与可用宽度指的是去掉任务栏这些东西后剩余的空间。

4). Document - 文档信息的抽象
  Document对象是DOM的重点,放到后面总结。这里我们已经用过它的一个方法了,就是write/writeln,作用是输出信息到页面中。

JavaScript大杂烩9 - 理解BOM的更多相关文章

  1. JavaScript大杂烩11 - 理解事件驱动

    前面我们回顾了前端JavaScript只干的两件事:操作BOM与操作DOM,那么什么时候去干这些事呢?答案是需要干的时候去干.那么什么时候是需要干的时候呢?答案是事件被触发的时候.这就是通常所说的“事 ...

  2. JavaScript大杂烩1 - 理解JavaScript的类型系统

    随着硬件水平的逐渐提高,浏览器的处理能力越来越强大,本人坚信,客户端会越来越瘦,瘦到只用浏览器就够了,服务端会越来越丰满:虽然很多大型的程序,比如3D软件,客户端仍然会存在,但是未来的主流必将是浏览器 ...

  3. JavaScript大杂烩12 - 理解Ajax

    AJAX缘由 再次谈起这个话题,我深深的记得就在前几年,AJAX被炒的如火如荼,就好像不懂AJAX,就不会Web开发一样.要理解AJAX为什么会出现,就要先了解Web开发面临的问题. 我们先来回忆一下 ...

  4. JavaScript大杂烩10 - 理解DOM

    操作DOM 终于到了JavaScript最为核心的部分了,通常来说,操作DOM,为页面提供更为友好的行为是JavaScript根本目标.   DOM树 - HTML结构的抽象 既然DOM是操纵HTML ...

  5. JavaScript大杂烩8 - 理解文本解析的"黄金搭档"

    文本解析"黄金搭档" - String与RegExp对象 文本解析是任何语言中最常用的功能,JavaScript中也是一样,而正则表达式作为最常用的方式,JavaScript也同样 ...

  6. JavaScript大杂烩7 - 理解内置集合

    JavaScript内置了很多对象,简单的类型如String,Number,Boolean (相应的"值类型"拥有相同的方法),复杂一点的如Function,Object,Arra ...

  7. JavaScript大杂烩6 - 理解JavaScript中的this

    在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this) ...

  8. JavaScript大杂烩4 - 理解JavaScript对象的继承机制

    JavaScript是单根的完全面向对象的语言 JavaScript是单根的面向对象语言,它只有单一的根Object,所有的其他对象都是直接或者间接的从Object对象继承.而在JavaScript的 ...

  9. JavaScript大杂烩3 - 理解JavaScript对象的封装性

    JavaScript是面向对象的 JavaScript是一种基于对象的语言,你遇到的所有东西,包括字符串,数字,数组,函数等等,都是对象. 面向过程还是面向对象? JavaScript同时兼有的面向过 ...

随机推荐

  1. Maven 如何发布 jar 包到 Nexus 私库

    Nexus2可以通过管理界面来上传jar包到私库中,而最新的Nexus3却找不到了上传界面,只能通过以下方式来发布到私库. 发布第三方jar包 这种情况是maven远程仓库没有,本地有的第三方jar包 ...

  2. spring boot -thymeleaf-日期转化

    <span th:text="${#dates.format(date)}" ></span><span th:text="${#dates ...

  3. 批量插入bulkcopy

     public static void InsertBatch<T>(IDbConnection conn, IEnumerable<T> entityList, string ...

  4. Go并发编程之美-CAS操作

    摘要: 一.前言 go语言类似Java JUC包也提供了一些列用于多线程之间进行同步的措施,比如低级的同步措施有 锁.CAS.原子变量操作类.相比Java来说go提供了独特的基于通道的同步措施.本节我 ...

  5. 学习DDD之路--勇于纠正自己的错误

    写这篇文章主要是之前三篇对DDD的介绍算是自己学习的一次试水,也希望能够有更多的人能帮我发现其中的问题.昨天继续阅读了DDD书,发现了自己之前的例子存在了一些问题,早上也和园友进行了一些讨论.最后整理 ...

  6. Zuul过滤器

    1.Zuul过滤器生命周期Zuul大部分功能都是通过过滤器来实现的,Zuul定义了4种标准的过滤器类型,这些过滤器类型对应于请求的典型生命周期.a.pre: 这种过滤器在请求被路由之前调用.可利用这种 ...

  7. SPI 驱动框架

    SPI 驱动框架 1. 枚举过程 drivers/spi/spi.c: spi_register_board_info /* 对于每一个spi_master,调用spi_match_master_to ...

  8. C#.net使用DotNetCharting控件生成报表统计图

    在做项目时要对数据进行统计分析,所以必须生成一些报表统计图(如柱形图.饼图.曲线图等),网上强烈推荐了使用DotNetCharting控件来实现,于是自己对DotNetCharting控件进行了简单的 ...

  9. linq left join ,inner join ,crossjoin

    inner join : linq 默认使用Inner Join的链接方式,如下面的表达式一样: Left Join: 左链接返回左表的全部数据,以及右表中满足链接条件和不满足链接条件的数据,不满足的 ...

  10. [转载] C# 调用C++ DLL 的类型转换

    //C#调用C++的DLL搜集整理的所有数据类型转换方式,可能会有重复或者多种方案,自己多测试 //c++:HANDLE(void *) ---- c#:System.IntPtr //c++:Byt ...