Js高级程序设计第三版学习(八章,九章)

                              Js高级程序设计第三版学习(章,九章)

 

 第八章 BOM

如果要在web中使用js,那么bom(浏览器对象)就是核心,BOM提供了很多对象用与访问浏览器功能

  1.window对象:

  • 全局作用域

window对象再es标准中也代表着global对象,所以在全局作用域中声明的变量,方法,都会成为window对象的变量方法,在全局作用域定义的变量不能delete删除,而window对象的属性可以,这是因为用var 声明的变量 他的描述符中[[Configurable]]的默认值为false

      var variables = 'TT';
      console.log(window.variables);//TT

      delete variables; //证明此行代码无效
      delete window.variables;//证明此行代码无效
      console.log(variables) //TT
       //{value: "TT", writable: true, enumerable: true, configurable: false}
       console.log(Object.getOwnPropertyDescriptor(window,'variables')); 

      window.ppap = 'TT TT'
      //{value: "TT TT", writable: true, enumerable: true, configurable: true}
      console.log(Object.getOwnPropertyDescriptor(window,'ppap')); 
      delete window.ppap;
      console.log(window.ppap) //undefined
  • 窗口及框架关系

 如果页面包含框架,那么每个框架都拥有自己的window对象,并且保存在frame集合中, 我们可以通过索引或者框架名来访问,每个window对象都有一个name,包含框架名. PS(由于h5已经废除 frame frameset noframes 所以本节知识点 仅仅了解大概 并未详细了解)

 <iframe src="https://www.baidu.com" frameborder="0" name="frames1"> </iframe>
    <iframe src="https://www.baidu.com" frameborder="0" name="frames2"></iframe>
    <script>
      console.log(window.frames[0].name) //frames1
      console.log(window.frames[1].name) //frames2
    </script>

top对象指向的是最外层的框架,既浏览器对象,他可以确保一个框架正确使用另一个框架,parent对象指向的是当前框架的直接上层对象,在没有框架的情况下parent = top

    <iframe src="https://www.baidu.com" frameborder="0" name="frames1">
    </iframe>
    <iframe src="https://www.baidu.com" frameborder="0" name="frames2"></iframe>
    <script>
      console.log(top === window); //true
      console.log(top.frames[0].name)//frames1
      console.log(top.frames[1].name)//frames2
      console.log(parent === window);//true
      console.log(top.frames[0].parent === window) //true
    </script>

self也指向window, 有时候可以与window互换, 在存在多个框架时, 每个框架都有各自的构造函数, 所以 top.obj !== top.frames[0].obj

  console.log(self === window); // true
  • 窗口位置

主流浏览器都提供 4个属性 用来表示窗口距离屏幕的位置 screenTop,screenLeft,screenX,screenY, (电脑只有 火狐,谷歌和ie11) 但是这4个属性在不同浏览器返回的值并不相同(火狐64以上已支持screenTop), 其中谷歌的两对属性返回值相同,但他是相对于窗口的坐标 在全屏下返回 0 0 , 而火狐两队也相同, 但是全屏返回-8,而ie screenTop 返回的是导航栏 下方距离屏幕的距离, left 等于0  而screenX 和 Y 全屏下都是-8 , 综上所以由于浏览器不同对于这两队属性的返回值也不相同, 相对统一的就是screenX和ScreenY这两个属性

 

  •  窗口大小

可视窗口大小 innerWidth innerHeight 浏览器窗口大小 outerHeight Width, 书中讲到了对于不同浏览器可能存在的不同差异,但在2019年1月 拿火狐 谷歌 ie11 测试的时候 除了浏览器自身的些许差异  inner 就是代表可视窗口,而outer代表浏览器窗口大小,这三个浏览器都相同

 

 对于视口 我们也可以用 clientWidth 和 clientHeigh 来获取, 我们可以通过 document.body 和document.documentElement来调用,  其中document.body代表着 body节点  document.documentElement代表着html节点, 这两个节点调用这两个属性是有区别的, body节点调用会获取 body的宽和body的实例的高(内容高度)(不包含滚动条宽度), 而用documentElement 会获得可视区域的宽高 (包含滚动条宽度),(都不包含工具栏,地址栏)

  • 导航和打开窗口

window.open(), 用来打开一个地址, 类似与A标签的click效果,  第一个参数: url 第二个参数 可以是框架或者字符串, 字符串可以用特殊字如 '_self' 代表原窗口打开, 第三个参数, 如果在新窗口打开 那么可以调整打开窗口的一些显示属性 如 宽高等, 另外在目前我测试的浏览器中除了ie 在页面加载或者onload 的时候 调用window.open() 都会被默认拦截, 但是写在某个dom元素点击事件不会拦截(与浏览器设置有关) 而 ie默认会直接打开

      //直接使用window.open() 会被浏览器拦截
      window.onload = function() {
        window.open('file:///D:/books/study/one/study2.html');
      };

      //把window.open()放在点击事件中 就可以调用了
      // 第一个参数 打开的地址 第二个参数 打开的框架 也可以本身打开 '_self' 第三个参数设置打开窗口的大小等属性 
      var iframe1 = top.frames['test'];
      var study2 = null;
      document.getElementById('asd').onclick = function() {
        study2 = window.open('file:///D:/books/study/one/study2.html','','width=400;height=500;');
      };

window.open(); 会返回被打开的窗口对象(ie会返回null), 这个对象的opener属性 代表着 调用window.open()的这个窗口对象(parent) , 如果这个属性 设置为null 那么就切断了 两个窗口的通信. 如果在发生通信时 会报错


      document.getElementById('dsa').onclick = function() {
        console.log(study2)
        if (study2 !== null) {
          console.log(study2.opener === top); // true
          /* 
          Blocked a frame with origin "null" from accessing a cross-origin frame.
    at HTMLLIElement.document.getElementById.onclick
           */
          study2.opener = null // 如果设置为null 那么就会切断框架间的通信 
          study2.close(); //会关闭弹出窗口
        }
      };
  • 间歇调用和超时调用

超时调用 setTimeout() 间歇调用 setInterval() ,两者参数相同 第一个参数: 方法(匿名,箭头)或字符串(不推荐性能损耗严重). 第二个参数 : 时间,毫秒为单位, 在传入方法时, 如果使用函数名的形式, 那么不能传入参数, 不过可以使用立即执行函数来迂回,setTimeout或setInterval 都会返回一个数值id, 我们可以使用clearTimeout 或 clearInterval 来清除, 就不会执行了, 减少了性能损耗,也可以在某一时间点结束调用.

      var tt = setTimeout(() => {
        console.log('timeout');
      }, 1000); //timeout
      var ti = setInterval(() => {
        console.log('inteval');
      }, 1000); //inteval

      setTimeout(tttttt, 5000);
      setTimeout(function() {
        tttttt('asd');
      }, 5000);
      
      function tttttt(obj) {
        console.log(obj);
      }

      setTimeout(function() {
        clearInterval(ti);
      }, 5000);

js是单线程模式,也就是说在当前代码未执行完之前不会执行其他的代码, 而setT 或setI 都是延迟执行的,它们只会在当前执行队列为空时,才会执行,那怕第二个参数传入了0ms 其实也会有4ms延迟, 所以这两个代码总是会在当前执行顺序的最后才会执,行,这也就造成了可能setT或许并不会在规定的延迟时间后执行(执行队列可能不为空), 也有可能造成在setInterval间歇执行时,每次执行的间隙并不一定相等,所以书中也不推荐使用间歇调用, 而是用超时调用来模拟间歇调用,(之前在写转盘抽奖时,也使用了setinterval,出现了转盘抽奖指针位置不对的情况, 当时使用了 promise和 return 来解决误差)

      var timeout = setTimeout(function(){
        console.log('timeout1');
      },0)
      for (let index = 0; index < 15000; index++) {
        console.log('delay1')
      }
      var timeout = setTimeout(function(){
        console.log('timeout2');
      },1000)
      for (let index = 0; index < 15000; index++) {
        console.log('delay2')
      }
      for (let index = 0; index < 15000; index++) {
        console.log('delay3')
      }
      var timeout = setTimeout(function(){
        console.log('timeout3');
      },3000)
      for (let index = 0; index < 15000; index++) {
        console.log('delay4')
      }

  • 系统对话框

alert() confrim(), 都接收字符串, 在对话框执行时 页面停止(之后的代码不会执行), confrim()点击确定会返回true 点击cancel会返回false  , window.print() 会打印页面, 弹出浏览器打印页

      if (confirm('nihao')) {
        console.log('ok');
      } else {
        console.log('cancel');
      }

      window.print();

  2.location对象:

location对象提供了窗口中加载的文档有关信息,还提供了导航功能, window.location 与 document.location 引用的是同一个对象, location对象提供了 路径 host 端口号 ...等等信息,(需要什么自己查)

其中loaction.href  location =  location.assign()方法都会是页面跳转, 其实每次修改location的对象属性都会造成页面重新加载(hash属性除外), 并且会产生新的历史纪录(用户可以使用回退按钮, 返回上一次的页面), 如果不想有新的历史纪录 可以使用 replace方法,他会导致浏览器位置改变但并不会产生新的历史纪录

    /*  三者实际效果相同 
       window.location.href = 'https://www.baidu.com';
      window.location ='https://www.baidu.com';
     */
     window.location.replace('https://www.baidu.com');
    

    //不产生新的历史纪录
    window.location.replace('https://www.baidu.com')

location.reload(), 页面重新加载, 如果不传参数, 会采用最有效率的加载,页面未曾改变过,会从内存直接加载, 如果参数为true,则会重新向服务器请求页面

  3.navigator对象:  

navigator用来识别客户端浏览器标准,不同浏览器的属性都会不同, 像appName 基本所有浏览器都返回Netscape , userAgent属性对于各个浏览器返回的信息比较全,

      console.log(window.chrome);
      console.log(navigator.appName);
      console.log(navigator.appVersion);
      console.log(navigator.userAgent)

 

  4.history对象:  

history对象保存着用户浏览的纪录,虽然我们无法获取纪录url 但是可以用根据history提供的方法 来实现页面的后退或前进,go()  -1代表后退 -2 后退两次 1代表前进1次 字符串: 历史纪录中包含这个字符串 就跳转 不包含就不动 back() 后退 forward() 前进, history记录历史纪录的个数

     if (history.length) {
       history.go(-1)
     }
     console.log(history.length)

 

 第九章 客户端检测

由于不同浏览器,提供的公共方法不同,所以我们需要设计最通用的方案,在使用特定浏览器技术增强该方案

  1.能力检测:

能力检测不是为了确定浏览器,而是识别浏览器的能力,例如有时候我需要确定在当前浏览器中是否可以使用该方法,然后再执行

     if (document.getElementById) {
       var pp = document.getElementById('asd');
       console.log(pp);
     }

但有时我们并不单单需要确认是否存在改属性或方法 而是需要判断 是不是符合我们的预期,如 下面的代码,我重写了toString 如果toString 不是fuction类型就不执行

      var ppap = {
        toString:'change'
      }

      if (typeof ppap.toString === 'function') {
        console.log(ppap.toString())
      }
      var hehe = {
        pp:'a'
      }
      if (typeof hehe.toString === 'function') {
        console.log(hehe.toString());//[object Object]
      }

  2.用户代理检测:

客户端代理检测,是万不得已的用法,应该最后使用,这是由于浏览器厂商根据版本不同,都会留有一些错误的或者欺骗性的信息,来达到欺骗服务器的目的, 例如下方代码中 ie11 chrome firefox 都是一样的字段

      console.log(navigator.appCodeName); //Mozilla
      console.log(navigator.appName); //Netscape

大多数情况下我们需要识别浏览器引擎,或者识别浏览器, 再navigator.userAgent 字段中来自己判断是什么

 

 

 

由此可见每个浏览器都有不同之处, 所以建议我们优先使用能力检测或怪异检测

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值