前端
一点也不简单

WEB前端面试题

基础Javascript篇

闭包

什么是闭包

就是函数内部变量外用,在一个函数内部嵌套一层或多层函数可以将内部变量外用

闭包的作用

可以将内部的变量保存下来,方便在外部随时调用

闭包的副作用

违背垃圾回收机制,造成内存泄漏

解决副作用的方案

量使用结束后删除(var a = 1)

a = null || {a:1}

cookie,LocalStorage与SessionStorage的异同

特性CookielocalStoragesessionStorage
数据的生命期一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效除非被清除,否则永久保存仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小4K左右一般为5MB
与服务器端通信每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题仅在客户端(即浏览器)中保存,不参与和服务器的通信
易用性需要程序员自己封装,源生的Cookie接口不友好源生接口可以接受,亦可再次封装来对Object和Array有更好的支持

类的创建和继承

类的创建(es5):new一个function,在这个function的prototype里面增加属性和方法。

下面来创建一个Animal类

// 定义一个动物类
function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

类的继承:

原型链继承

构造继承

实例继承和拷贝继承

组合继承

寄生组合继承

如何解决异步回调地狱

promise、generator、async/await

说说前端中的事件流

HTML和javascript的交互是通过事件驱动来实现的,例如鼠标点击事件onclick,页面滚动事件onscroll等,要知道这些事件是什么时候调用的,就需要知道”事件流”的概念:

在DOM2级事件中,javascript将事件分为三个阶段

  1. 事件捕获阶段
  2. 事件目标阶段
  3. 事件冒泡阶段

addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

注意: IE只支持事件冒泡

如何让事件先冒泡后捕获

在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行(例如用setTimeOut()),直到冒泡事件被捕获后再执行捕获之间。

事件委托

原理:事件冒泡

简介:事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。

举例:最经典的就是ul和li标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加。

好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。因为不需要循环了,所以也节省了性能。

举个栗子:给ul中的li添加点击事件

    <ul id="oUl">
        <li>A</li>
        <li>B</li>
    </ul>
let oUl = document.getElementById('oUl');
          let oLi = document.getElementsByTagName('li')
          for ( var i = 0;i < oLi.length;i++){
              oLi[i].onclick=function(){
                  this.style.background = 'red'
                  console.log(this)
              }
          }

这是我们常规的添加点击事件的写法,但是有个缺点,如果我们的li动态创建的呢????这种方法固然是不行的,需要用到事件委托

事件委托写法:

 <ul id="oUl">
 </ul>
let oUl = document.getElementById('oUl');
        let oLi = document.createElement('li');
        oLi.innerText="A";
        let oLi1 = document.createElement('li');
        oLi1.innerText="B";
        oUl.appendChild(oLi);
        oUl.appendChild(oLi1);

        oUl.onclick=function(ev){
            var ev = ev || window.event;//
            var target = ev.target || ev.srcElement;//事件源兼容写法
            if(target.nodeName.toLowerCase() == 'li' ){
            target.style.background = 'red';
            }
        }

图片的懒加载和预加载

  • 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。
  • 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。 懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

mouseover和mouseenter的区别

  • mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
  • mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave

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

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

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

共同点:

通过apply和call都可以改变函数的this指向,和借用其他对象的方法, 当使用 call 或者 apply 的时候,如果我们传入的第一个参数为 null,函数体内的 this 会指 向默认的宿主对象,在浏览器中则是 window

区别:

apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向, 第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数

let func = function (a,b,c) {
    console.log([a,b,c]);//输出:[1,2,3]
}
func.apply(null,[1,2,3]);

而 call 传入的参数数量不固定, 跟apply 相同的是,第一个参数也是代表函数体内的 this 指向, 从第二个参数开始往后,每个参数被依次传入函数

var func1 = function( a, b, c ){ 
    console.log([a,b,c]); //输出:[1,2,3]
};
func1.call( null, 1, 2, 3 );

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

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

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

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

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

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

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

js拖拽功能的实现

  • 首先是三个事件,分别是mousedown,mousemove,mouseup 当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。
  • clientX,clientY标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用offsetX和offsetY来表示元素的元素的初始坐标,移动的举例应该是: 鼠标移动时候的坐标-鼠标按下去时候的坐标。 也就是说定位信息为: 鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的offetLeft.
  • 还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left 以及top等等值。

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

post和get的区别

  • get参数通过url传递,post放在request body中。
  • get请求在url中传递的参数是有长度限制的,而post没有。
  • get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
    • get请求只能进行url编码,而post支持多种编码方式
    • get请求会浏览器主动cache,而post支持多种编码方式。
    • get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
  • GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
  • GET产生一个TCP数据包;POST产生两个TCP数据包。

对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

(据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。)

判断数组有哪些方法

  • a instanceof Array
  • a.constructor == Array
  • Object.protype.toString.call(a) == [Object Array]

进阶javascript篇

赞(1) 打赏
未经允许不得转载:专注前端开发和vps技术交流的博客-纸飞机 » WEB前端面试题

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

微信扫一扫打赏