• 前端面试:基础javascript篇(二)


    11. js的new操作符做了哪些事情

    new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

     

    12.

    改变函数内部this指针的指向函数(bind,apply,call的区别)

    通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2...这种形式。

    通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。

     

    13.js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?

    clientHeight:表示的是可视区域的高度,不包含border和滚动条

    offsetHeight:表示可视区域的高度,包含了border和滚动条

    scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。

    clientTop:表示边框border的厚度,在未指定的情况下一般为0

    scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

     

    14. . js拖拽功能的实现

    首先是三个事件,分别是mousedown,mousemove,mouseup

    当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。

    clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY来表示元素的元素的初始坐标,移动的举例应该是:

    鼠标移动时候的坐标-鼠标按下去时候的坐标。

    也就是说定位信息为:

    鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.

    还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left

    以及top等等值。

    补充:也可以通过html5的拖放(Drag 和 drop)来实现

    <!DOCTYPE html>

    <html>

       <head>

          <meta charset="utf-8" />

          <title>拖拽实现-</title>

          <style type="text/css">

              *{

                 margin: 0;

                 padding: 0;

              }

              html,body{

                 overflow: hidden;

                 height: 100%;

              }

              #warp{

                 150px;

                 height: 150px;

                 background-color: red;

                 position: absolute;

                 top: 0;

                 left: 0;

              }

          </style>

       </head>

       <body>

          <div id="warp">

             

          </div>

       </body>

       <script type="text/javascript">

           window.onload = function(){

             /*

              * 拖拽:1:在点击的时候获取元素的起始位置,鼠标的位置

              *     2:在移动的时候计算鼠标移动的距离

              *     3:设置元素的偏移量

              */

             var warp = document.querySelector("#warp");

             var startPoint = {x:0,y:0};

             var oldPoint = {x:0,y:0};

            

             warp.onmousedown = function(ev){

                 ev = ev||event;

                 if(this.setCapture)

                 {

                    this.setCapture();//事件的全局捕获  兼容IE8,阻止IE8的默认行为

                 }

                 startPoint.x = this.offsetLeft;

                 startPoint.y = this.offsetTop;

                

                 oldPoint.x = ev.clientX;

                 oldPoint.y = ev.clientY;

                

                 document.onmousemove = function(ev){

                    ev = ev||event;

                    newPoint = {x:0,y:0};

                    newPoint.x = ev.clientX;

                    newPoint.y = ev.clientY;

                   

                    var dis = {x:0,y:0};

                    dis.x = newPoint.x - oldPoint.x ;

                    dis.y = newPoint.y - oldPoint.y ;

                   

                    //边界判断

                    var L= startPoint.x +dis.x;

                    var T= startPoint.y +dis.y;

                   

                    if(L<0)

                    {

                       L = 0;//左边的标签

                    }

                    if(T<0)

                    {

                       T = 0;//左边的标签

                    }

                    if(T >= document.documentElement.clientHeight - warp.offsetHeight)

                    {

                       T = document.documentElement.clientHeight - warp.offsetHeight ;

                    }

                    if(L >= document.documentElement.clientWidth - warp.offsetWidth)

                    {

                       L = document.documentElement.clientWidth - warp.offsetWidth ;

                    }

                    //偏移

                    warp.style.left = L +"px";

                    warp.style.top =  T +"px";

                 }

                

                 document.onmouseup = function(){

                    document.onmouseup = document.onmousemove = null;

                    if(document.releaseCapture){

                       document.releaseCapture();

                    }

                 } 

             return false ; //阻止默认行为

             }

           }

       </script>

    </html>

    15. 异步加载js的方法

    defer:只支持IE如果您的脚本不会改变文档的内容,可将 defer 属性加入到<script>标签中,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。

     

    async,HTML5属性仅适用于外部脚本,并且如果在IE中,同时存在defer和async,那么defer的优先级比较高,脚本将在页面完成时执行。

    创建script标签,插入到DOM

     

    16. Ajax 解决浏览器缓存问题

    在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")

    在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")

    在URL后面加上一个随机数: "fresh=" + Math.random()

    在URL后面加上时间搓:"nowtime=" + new Date().getTime()

    如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

     

    17.js的节流和防抖

    防抖动:防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。

    节流函数:只允许一个函数在 X 毫秒内执行一次,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。

    rAF:16.7ms 触发一次 handler,降低了可控性,但是提升了性能和精确度。

     

    18. JS中的垃圾回收机制

    必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

     

    这段话解释了为什么需要系统需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收机制(Garbage Collection)。JavaScript的解释器可以检测到何时程序不再使用一个对象了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用的内存释放掉了。例如:

     

    var a="hello world";

    var b="world";

    var a=b;

    //这时,会释放掉"hello world",释放内存以便再引用

    垃圾回收的方法:标记清除、计数引用。

     

    标记清除

    这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离开环境。

     

    垃圾回收器在运行的时候会给存储在内存中的变量都加上标记(所有都加),然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量(条件性去除标记),删除所有被标记的变量,删除的变量无法在环境变量中被访问所以会被删除,最后垃圾回收器,完成了内存的清除工作,并回收他们所占用的内存。

     

    引用计数法

    另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数,当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为1,;相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次数就减1,当这个值的引用次数为0的时候,说明没有办法再访问这个值了,因此就把所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为0的这些值。

     

    用引用计数法会存在内存泄露,下面来看原因:

     

    function problem() {

        var objA = new Object();

        var objB = new Object();

        objA.someOtherObject = objB;

        objB.anotherObject = objA;

    }

    在这个例子里面,objA和objB通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,在采用引用计数的策略中,由于函数执行之后,这两个对象都离开了作用域,函数执行完成之后,因为计数不为0,这样的相互引用如果大量存在就会导致内存泄露。

     

    特别是在DOM对象中,也容易存在这种问题:

     

    var element=document.getElementById(’‘);

    var myObj=new Object();

    myObj.element=element;

    element.someObject=myObj;

    这样就不会有垃圾回收的过程。

     

    19.eval是做什么的

    它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行)

     

    20.如何理解前端模块化

    前端模块化就是复杂的文件编程一个一个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(编译等处理)的工具webpack

  • 相关阅读:
    面试回忆录(一)
    2013国内IT行业薪资对照表【技术岗】
    腾讯2013笔试题—web前端笔试题 (老题练手)
    Nicholas C. Zakas(JS圣经:JavaScript高级程序设计作者)如何面试前端工程师
    Js中 关于top、clientTop、scrollTop、offsetTop的用法
    JavaScript中的面向对象的讨论(转)
    javascript中的原型理解总结
    关于Javascript语言中this关键字(变量)的用法
    window.clearInterval与window.setInterval的用法(
    JavaScript经典魔力代码
  • 原文地址:https://www.cnblogs.com/love-life-insist/p/10258969.html
Copyright © 2020-2023  润新知