2019-7-29  牛客网   前端工程师    在线面试
1.如果要画一条0.5px的线,你会怎么去实现呢?讲讲你的方法。
像素<-------屏幕显示最小的单位
像素数量1920 * 1080(宽W有1920个像素,高H为1080个)<---------一个1080p的屏幕
像素实际上是一个面积的概念,因此像素本身有大小.
同样大小的屏幕,像素越小,需要的像素点就越多,像素就越密集.
1寸=1.31233596英寸
1英寸=25.4毫米
图像的采样率ppi--------在图像中,每英寸所包含的像素数目
打印分辨率dpi-----------每英寸所能打印的点数,即打印精度
图像的宽W(高H)像素数=打印宽W(高H)分辨率×打印的宽W(高H)尺寸
435pix = 435dpi/ppi * 1inch
15寸的分辨率为2880 x 1800,15寸是指屏幕的对角线为15寸(具体为15.4)实际按照宽高勾股比例计算,宽W为13寸,所以2880/13=220ppi,可见,同一大小屏幕,像素数越多,像素越密集,分辨率也高,屏幕越细腻越高清.

在Mac/Windows上可以设置屏幕显示的分辨率,Mac默认为设备分辨率的一半,它的dpr= 2,即宽和高用2个像素表示1个像素,所以2880个物理像素点实际上只表示1440个逻辑像素。

如果我们直接设置0.5px,在不同的浏览器会有不同的表现
<!DOCType html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        .hr {
            width: 300px;
            background-color: #000;
        }
        .hr.half-px {
            height: 0.5px;
        }
        .hr.one-px {
           height: 1px;
        }
    </style>
</head>
<body>
    <p>0.5px</p>
    <div class="hr half-px"></div>
    <p>1px</p>
    <div class="hr one-px"></div>
</body>
</html>

自己验证的如上图---------
几乎没什么不一样

Chrome把0.5px四舍五入变成了1px,把小于0.5px的当成0
firefox/safari能够画出0.5px的边,把不小于0.55px当成1px,Safari是把不小于0.75px当成1px
手机上观察IOS苹果的Chrome会画出0.5px的边,而安卓(5.0)原生浏览器是不行的
所以直接设置0.5px不同浏览器的差异比较大,并且我们看到不同系统的不同浏览器对小数点的px有不同的处理。所以如果我们把单位设置成小数的px包括宽高等,其实不太可靠,因为不同浏览器表现不一样.
<!DOCType html>
<html>
<head>
    <meta charset="utf-8">
    <style>
       .hr {
            width: 300px;
            background-color: #000;
        }    
       .hr.scale-half {   height: 1px;   transform: scaleY(0.5);   }  </style>
</head>
<body>
    <p>1px + scaleY(0.5)</p>  <div class="hr scale-half"></div>
</body>
</html>


自己验证的如上图--------
IE浏览器中使用transform属性后,线不可见了
火狐几乎没什么变化
360浏览器线变虚了

Chrome/Safari都变虚了
Firefox比较完美看起来是实的而且还很细,效果和直接设置0.5px一样
所以通过transform: scale会导致Chrome变虚了,而粗细几乎没有变化
<!DOCType html>
<html>
<head>
    <meta charset="utf-8">
   <style>
       .hr {
            width: 300px;
            background-color: #000;
        }  .hr.scale-half {  height: 1px;  transform: scaleY(0.5);  transform-origin: 50% 100%;  }  </style>
</head>
<body>
    <p>1px + scaleY(0.5)</p>  <div class="hr scale-half"></div>
</body>
</html> 

自己验证如上图------
IE因添加了transform属性,线不可见,3当不添加transform属性,线可见,再添加transform-origin属性,线可见几乎无变化.
360浏览器,线变实了,
火狐因添加了transform-origin属性,线不可见了,但是transform-origin和transform二选一则线变可见.
<!DOCType html>
<html>
<head>
    <meta charset="utf-8">
   <style>
   .hr {
            width: 300px;
            background-color: #000;
        }  .hr.gradient {  height: 1px;  background: linear-gradient(0deg, #fff, #000);  }  </style>
</head>
<body>
    <p>linear-gradient(0deg, #fff, #000)</p>  <div class="hr gradient"></div>
</body>
</html> 

自己验证如上图------
除了虚实效果,大概看不出什么不同

inear-gradient(0deg, #fff, #000):渐变的角度从下往上,从白色#fff渐变到黑色#000,而且是线性的,在高清屏上,1px的逻辑像素代表的物理(设备)像素有2px,由于是线性渐变,所以第1个px只能是#fff,而剩下的那个像素只能是#000,这样就达到了画一半的目的
<!DOCType html>
<html>
<head>
    <meta charset="utf-8">  <meta name="viewport" content="width=device-width,initial-sacle=0.5">
   <style>
   .hr {  width: 300px;  background-color: #000;
    }  .hr.boxshadow {  height: 1px;  background: none;  box-shadow: 0 0.5px 0 #000;  }  </style>
</head>
<body>
   <p>box-shadow: 0 0.5px 0 #000</p>  <div class="hr boxshadow"></div>
</body>
</html>

自己验证如上图-------
几乎一样

width=device-width表示将viewport视窗的宽度调整为设备的宽度,这个宽度通常是指物理上宽度。默认的缩放比例为1时,如iphone 6竖屏的宽度为750px,它的dpr=2,用2px表示1px,这样设置之后viewport的宽度就变成375px。但是我们可以改成0.5,viewport的宽度就是原本的750px,所以1个px还是1px,正常画就行,但这样也意味着UI需要按2倍图的出,整体面面的单位都会放大一倍
2.请讲一下对于前端中的事件流,你是怎么理解的
事件流--------描述的是从页面中接受事件,事件发生的顺序,自下而上(由具体节点到不具体节点)---事件捕获流/自上而下(由不具体节点到具有节点)----事件冒泡流
IE提出的是“事件冒泡流”
Netscape提出的是“事件捕获流”
事件冒泡流:从下而上的过程,由具体节点到不具体节点,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(文档)
事件捕获流:与冒泡流截然相反,从上而下的过程,由不具体节点到具体节点,它的定义是最不具体的节点应该更早接收到事件,而最具体的节点最后接收到事件
<html>
    <head>
        <tltle>事件流</title>
        <meta charset="UTF-8" >
    </head>
    <body>
        <div>
            <input type="button" value="按钮"  id="btn">
        </div>
    </body>
用户点击按钮,浏览器就会认为你点击按钮的同时也点击了div,认为你点击了div就会认为你也点击了body,一直往上,会认为你点击了document.也就是说你点击了按钮,浏览器会一级一级往上冒,认为你点击了整个document
如button和button的父元素都添加了click事件,当点击button的时候,button和其父元素的点击事件都会执行,自下而上的顺序执行。这个事件需要阻止冒泡事件。
解决方法:
$('button').click(function(e){   //可以是任何需要阻止冒泡的元素。
e.stopPropagation();
//ie
e.cancelBubble = true;
})

一些不支持冒泡的事件:
blur:元素失去焦点时触发,不支持冒泡。
focus: 元素获得焦点时触发,不支持冒泡。
mouseenter:鼠标移入元素触发,不支持冒泡。
mouseleave:鼠标移出元素时触发,不支持冒泡。

3.给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
此问题包含两个步骤:
(1)判断链表中是否有环
(2)找出环
如何判断链表是否有环?
设置两个指针,开始都指向链表头,然后其中一个指针每次向前走一步,另一个指针每次向前走两步,如果快的遇到NULL了,证明该链表中没有环,如果有环,快的指针每次都要比慢的多走一步,最终两个指针会相遇,(注意:这里快指针不会跳过慢指针而不相遇,因为它每次都只比慢指针多走一个单位)
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function EntryNodeOfLoop(pHead)
{
    // write code here
    // 使用两个指针,一个快的,一个慢的,快的时慢的两倍,如果有环,那么他么一定会相遇。
    if (pHead == null || pHead.next == null) {
        return null;
    }
    
    var p1 = pHead;
    var p2 = pHead;
    while (p2 != null && p2.next != null) {
        p1 = p1.next;
        p2 = p2.next.next;
        if (p1 == p2) {
            p2 = pHead;
            while (p1 != p2) {
                p1 = p1.next;
                p2 = p2.next;
            }
            if (p1 == p2) {
                return p1;
            }
        }
    }
    return null;
    
}
module.exports = {
    EntryNodeOfLoop : EntryNodeOfLoop
};