每日思考(2019/12/30)

题目概览

  • <form>标签的enctype属性的理解
  • CSS的优先级是如何计算的
  • 为什么 JavaScript 中 0.1 0.2 不等于 0.3 ?

题目解答

<form>标签的enctype属性的理解

  • enctype的定义和用法:enctype属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX值)

  • enctype 有哪些值

    描述
    application/x-www-form-urlencoded在发送前编码所有字符(默认)
    multipart/form-data不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
    text/plain空格转换为 "+" 加号,但不对特殊字符编码。
  • 说明

    • 所谓的设置表单的MIME编码,就是设置enctype的值。默认值为"application/x-www-form-urlencoded",默认值不支持文件上传。如果在服务器端要通过Request对象来获取相应表单域的值,则应该将enctype属性设置为application/x-www-form-urlencoded值(即默认值,可以不显示设置)

    • 如果要上传文件的话,是一定要将encotype设置为multipart/form-data的,设置enctype为multipart/form-data值后,不对字符编码,则数据通过二进制的形式传送到服务器端,这时如果用request是无法直接获取到相应表单的值的,而应该通过stream流对象,将传到服务器端的二进制数据解码,从而读取数据。

      <form action="demo_post_enctype.html" method="post" enctype="multipart/form-data">
        First name: <input type="text" name="fname"><br>
        Last name: <input type="text" name="lname"><br>
        <input type="submit" value="提交">
      </form>

CSS的优先级是如何计算的

  • 选择器种类

    • 标签名选择器,如:p{},即直接使用HTML标签作为选择器,伪元素特指度等同于标签名选择器
    • 类选择器,如.polaris{},伪类,属性选择器特指度等同于类
    • ID选择器,如#polaris{},
    • 后代选择器,如 .polaris span img{},后代选贼器实际上是使用多个选择器加上中间的空格来找到具体的要控制标签
    • 群组选择器,如 div,span,img{},群组选择器实际上是对CSS的一种简化写法,只不过把有相同定义的不同选择器放在一起,省了很多代码
  • 特指度-优先级计算

    • 含义:特指度表示一个css选择器表达式的重要程度,可以通过一个公式来计算出一个数值,数越大,越重要。
    • 针对一个css选择器表达式,遇到一个id就往特指度数值中加100,遇到一个class就往特指度数值中加10,遇到一个element就往特指度数值中加1
    • !important 优先级最高,高于上面一切。* 选择器最低,低于一切、
  • 后代选择器的定位原则:浏览器CSS匹配不是从左到右进行查找,而是从右到左进行查找。比如div#divBox p span.red{color:red;},浏览器的查找顺序如下:先查找html中所有 class=‘red‘ 的 span 元素,找到后,再查找其父辈元素中是否有 p 元素,再判断 p 的父元素中是否有 id 为 divBox 的 div 元素,如果都存在则匹配上。浏览器从右到左进行查找的好处是为了尽早过滤掉一些无关的样式规则和元素

  • 简洁、高效的CSS:

    • 不要在ID选择器前使用标签名,因为ID选择器是唯一的,加上 div 反而增加不必要的匹配

    • 不要再class选择器前使用标签名,同第一条,但如果你定义了多个.red,而且在不同的元素下是样式不一样,则不能去掉,比如你css文件中定义如下

      p.red{color:red;}  
      span.red{color:#ff00ff}
    • 尽量少使用层级关系,如#divBox p .red{color:red;}写成.red{..}

    • 使用class代替层级关系,如#divBox ul li a{display:block;}写成.block{display:block;}

为什么 JavaScript 中 0.1 + 0.2 不等于 0.3 ?

  • 根源:EcmaScrpt规范定义Number的类型遵循了IEEE754-2008中的64位浮点数规则定义的小数后的有效位数至多为52位导致计算出现精度丢失问题

  • 解析:计算机内部存储数据的编码的时候,0.1在计算机内部根本就不是精确的0.1,而是一个有舍入误差的0.1。当代码被编译或解释后,0.1已经被四舍五入成一个与之很接近的计算机内部数字,以至于计算还没开始,一个很小的舍入错误就已经产生了。这也就是 0.1 + 0.2 不等于0.3 的原因

    对于 0.1 + 0.2 这样的运算,操作数会先被转成二进制,然后再计算:
    0.1 => 0.0001 1001 1001 1001…(无限循环)
    0.2 => 0.0011 0011 0011 0011…(无限循环)
  • 结果:双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100... 因浮点数小数位的限制而截断的二进制数字,这时候,再把它转换为十进制,就成了 0.30000000000000004

    console.log(0.1+0.2==0.3);//false
  • 解决方法

    • 对于JS来说,这个值通常是 2^-52 , 而在ES6中,提供了一个属性:Number.EPSILON,而这个值正等于2^-52。这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近0,但不等于0。这个时候我们只要判断(0.1+0.2)-0.3小于Number.EPSILON,在这个误差的范围内就可以判定0.1+0.2===0.3为true

      function numEqual(a,b){
      //abs()绝对值
          return Math.abs(a-b)<Number.EPSILON;
      }
      var a=0.1+0.2,b=0.3;
      console.log("Number.EPSILON:",numEqual(a,b));//true
    • 把计算数字 提升 10 的N次方 倍 再 除以 10的N次方。一般都用 1000 就行了

      var equl=(0.1*1000+0.2*1000)/1000==0.3;
      console.log("10的N次方倍:",equl);//true
    • toFixed() 方法:在判断浮点数运算结果前对计算结果进行精度缩小,因为在精度缩小的过程总会自动四舍五入

      //parseFloat((数学表达式).toFixed(digits)); toFixed() 精度参数须在 0 与20 之间
      parseFloat((0.1 + 0.2).toFixed(10))//结果为0.3
      parseFloat((0.3 / 0.1).toFixed(10)) // 结果为 3  
      parseFloat((0.7 * 180).toFixed(10))//结果为126
      parseFloat((1.0 - 0.9).toFixed(10)) // 结果为 0.1   
      parseFloat((9.7 * 100).toFixed(10)) // 结果为 970 
      parseFloat((2.22 + 0.1).toFixed(10)) // 结果为 2.32
    • 不是所有浮点数都有舍入误差。二进制能精确地表示位数有限且分母是2的倍数的小数,比如0.5,0.5在计算机内部就没有舍入误差。所以0.5 + 0.5 === 1

相关推荐