5道面试金题!你值得拥有!

147 阅读6分钟

1、javascript中的委托事件

基本概念

事件委托,简单地说,就是把一个元素的响应事件委托给另一个元素。

事件冒泡

事件委托的本质是利用事件冒泡机制。

在document.addEventListener的时候设置事件模型:事件冒泡、事件捕获,一般来说都是使用事件冒泡的。

事件冒泡:事件从最底层逐层向最外层(根元素)传播,通常用document.addEventListener(‘click’,function(){},false)来监听事件;

事件捕获:简单来讲就是从最外层到最底层(目标事件)传播,通常用document.addEventListener(‘click’,function(){},true)来监听事件;

目标阶段:目标阶段就是指事件响应到触发事件的最底层元素上,遵循谁先注册谁执行原则。

事件委托的使用场景

当有大量类似元素需要批量添加事件监听时,使用事件委托可以减少内存开销;

当有动态元素节点上树时,使用事件委托可以让新上树的元素也具有事件监听。

使用事件委托时的注意事项

onmouseenter和onmouseover都表示“鼠标进入”,它俩有什么区别呢?

onmouseenter是不冒泡的,onmouseover是冒泡的。

使用事件委托的优缺点

优点:

  • 可以节省大量内存,减少事件注册;
  • 可以进行动态绑定,当需要新增子对象时,无需再对其进行事件绑定。 缺点:

如果把所有事件都用事件绑定,可能会出现事件误判,即本来不需要被触发的事件被绑定上了事件。

2、页面优化有哪些方法?

css

  • 合并重复的css文件,减少HTTP请求数量
  • 从页面中剥离js和css文件
  • 将css文件放到页面最上方
  • 删除空的css规则
  • 优化选择器嵌套,尽量避免层级过深
  • 提取公共样式,减少代码的书写
  • 充分利用css的继承属性,减少代码量
  • 当属性值为0时,不加单位
  • 当属性值是小于1的小数时,省略小数点前面的0
  • 使用CSS Sprites(精灵图)将多张照片拼接成一张图片,通过CSS background属性来访问图片内容

js

  • 减少DOM元素的数量
  • 节流、防抖
  • 使用图片懒加载(data-src)
  • 长列表滚动到可视化区域动态加载(大数据渲染)
  • 使用闭包时,在函数结尾处手动删除不需要的局部变量,尤其在缓存dom节点的情况下
  • DOM操作优化
    • 批量添加dom元素时,可先createElement创建并添加节点,最后一次性加入dom
    • 批量绑定事件,使用事件委托绑定父节点实现,利用了事件冒泡机制
    • 情况允许的话,使用innerHTML代替appendChild
    • 在DOM操作时添加样式时尽量增加class属性,而不是通过style样式,减少重排(reflow)

3、Cookie、localStorage和sessionStor有什么区别?

基本概念

Cookie:本意为“小饼干”,它的存储容量非常小,通常只有4KB,主要用于存储用户登录浏览器的一些用户名密码等信息。

localStorage:意为本地存储,是HTML5中新增的一个新技术,对于多数浏览器来说都是兼容的,localStorage可以长时间存储数据,即生命周期是永久性的,即使用户刷新页面或者是关闭浏览器也不能清除数据,除非用户自己主动清除数据,主要用于存储各种信息。

sessionStorage:会话存储,顾名思义,存储在会话窗口的数据。比如在浏览器界面,当用户刷新页面时,sessionStorage存储的数据并不会失效,当用户关闭浏览器时存储的数据才会消失。

总结

| 特性 | Cookie | localStorage | sessionStorage | | :------:| :------: | :------: | | :------: | | 数据的生命周期 | 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 | 永久性的,除非被清除,否则永久保存 | 当用户刷新页面时,数据不会失效。只有关闭浏览器,存储的数据才会清除 | | 存储数据的大小 | 4KB左右 | 一般为5MB | 一般为5MB | | 与服务器端通信 | 每次都会携带在HTTP头中,发送给服务端。但是使用cookie保存过多数据会影响它的性能 | 仅在客户端(即浏览器)中保存,不和服务器通信 | 同localStorage |

4、什么是子选择器?什么是后代选择器?

子选择器

大于号 > 代表子选择器,如div>span,表示获取div的子标签span,

 <div>
        <span>子span</span>
        <span>子span</span>
        <span>子span</span>
        <p>
            <span>后代span</span>
        </p>
 </div>
div>span{
            color: red;
        }

捕获.PNG

后代选择器

空格 代表后代选择器,如div span,表示获取div标签内的所有span标签

 <div>
        <span>子span</span>
        <span>子span</span>
        <span>子span</span>
        <p>
            <span>后代span</span>
        </p>
 </div>
div span{
            color: red;
        }

后代选择器.PNG

5、什么是闭包?

闭包定义

闭包指的是一个函数可以访问另一个函数作用域中的变量。

内嵌函数可以访问定义在外层函数中的所有变量和函数,还包括外层函数能访问的所有变量和函数。但是在此函数外部却不能访问此函数的内部变量和嵌套函数。

        var a=1;
        function aaa(){
            var b=2;
            return function ccc(){
                console.log(a);//1
            }  
         }
        console.log(b);// ReferenceError: b is not defined
        aaa()();

闭包的作用

闭包的作用是保存和保护。

保存作用

当我们在网页中使用选项卡时,通常会遇见因为索引值引发的问题。

   <ul>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>
 var lis = document.getElementsByTagName('li');
        // 此方法不可行
        for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                console.log(i); //5 5 5 
            }
        }

此时的运行结果打印的都是lis.length的值,即5。不管你点击哪一个li,打印的都是5.

解决方案:

当点击事件执行时,就会在私有作用域查找i的值,此时私有作用域中没有i,就会全局作用域查找,而此时全局作用域的值已经改变,所以,需要创建一个私有作用域的i。

// 解决方案一  闭包的形式
for (var i = 0; i < lis.length; i++) {
    function getli(i) {
        lis[i].onclick = function () {
           console.log(i);
        }
    }
    getli(i)
}
 // 解决方案二   使用自定义属性
        for (var i = 0; i < lis.length; i++) {
            lis[i].index = i;
            lis[i].onclick = function () {
                console.log(this.index); //0 1 2 3 4
                //  console.log( lis[i].index);
            }
        }
// 解决方案三  使用let声明变量
        // let 是块级作用域
        for (let i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                lis[i].style.color="red"
                console.log(i); //0 1 2 3 4
            }
        }

保护作用

在闭包内可以保护一些变量,闭包函数是一个私有作用域,当程序猿/媛在开发时,为了避免相互之间的变量名冲突,可以将其放在一个私有作用域下。