前端面试常见题目整理2020(持续更新)

2020-02-25  本文已影响0人  XKolento

1.元素查找document.getElementById() 和 document.querySelector() 的区别

1️⃣前者是动态获取元素,后者是静态获取元素

document.getElementById() //当元素被js操作过后还能获取,例如新增了一个
doument.querySelector() //静态获取,js新增的元素无法获取

2️⃣性能比较
document.getElementById()的性能要优于doument.querySelector()
jquery的选择器是由后者包装而来的,性能虽然差,但是操控DOM更便捷。

2.HTML5新特性

1️⃣新增了一些标签 section progress header footer article video ,新增了一些 input 的输入类型(time,week,month,number)
2️⃣canvas画布功能,js绘图
3️⃣元素拖放

<img draggable="true" /> //表示可以拖放
拖放触发的相关事件:
拖动什么 - ondragstart 和 setData()
放到何处 - ondragover
进行放置 - ondrop

4️⃣地理定位功能
HTML5 Geolocation API 用于获得用户的地理位置。
鉴于该特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是不可用的。
5️⃣web存储
Web Storage DOM API 为Web应用提供了一个能够替代cookie的Javascript解决方案
cookie—存储大小4kb,不够用。
sessionStorage—客户端数据存储,只能维持在当前会话范围内。
sessionStorage 方法针对一个 session 进行数据存储。当用户关闭浏览器窗口后,数据会被删除。
localStorage—客户端数据存储,能维持在多个会话范围内。
localStorage 对象存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。
以上存储大小大约5mb,
对于大量复杂数据结构,5mb不够用的,一般使用IndexDB(浏览器数据库),但是api等相对比较复杂,使用成本高。
6️⃣离线web应用,启用缓存,可以离线访问,降低服务器压力
7️⃣WebSocket
当浏览器与服务器建立连接后,该功能可以让客户端与服务端相互交换数据,类似的使用场景:聊天,网易云信等
8️⃣新增的一些css3动画效果等

3.js各循环之间的区别
1️⃣for循环,用于数组循环,性能一般
2️⃣for key in obj循环 与 for value of obj
可用于循环json对象,前者key输出key,后者value输出value
for...of是ES6新引入的特性。修复了ES5引入的for...in的不足
3️⃣foreach
属于es5的语法,可以同时获取到key和value,
不能使用contine和break跳出循环,不能终止循环,不能在函数内使用return,不返回新数组

let array = ['a','b','c']
array.forEach((currentValue, index, arr)=>{
  console.log(currentValue); // a b c  必选参数
  console.log(index); //0 1 2 可选参数
  console.log(arr); // abc abc abc 可选参数
})

4️⃣map
map的循环即将返回一个新数组
forEach适合于你并不打算改变数据的时候,而只是想用数据做一些事情 – 比如存入数据库或则打印出来。
map()适用于你要改变数据值的时候。不仅仅在于它更快,而且返回一个新的数组。这样的优点在于你可以使用复合(composition)(map(), filter(), reduce()等组合使用)来玩出更多的花样。
map的性能优于forEach,快将近70%
5️⃣jquery 中的each

$(selector).each(function(index,element){
  //都是必须的参数
  //index - 选择器的 index 位置
  //element - 当前的元素(也可使用 "this" 选择器)
})

6️⃣filter 循环过滤
循环并且返回筛选后的内容

var arr = [
 {"name":"apple", "count": 2},
 {"name":"orange", "count": 5},
 {"name":"pear", "count": 3},
 {"name":"orange", "count": 16},
];
var newArr = arr.filter((value,index,arr)=>{
 // value 当前元素的值 例如 {"name":"apple", "count": 2}
 // index 0 1 2 等
 // arr 整个数组
 return value.name === "orange"; //返回2个name是orange的数组
});

4.js各种初始化时间的区别

<!DOCTYPE html>
<html>
<head>
<title>首页</title>
<script type="text/javascript" src="js/jquery-1.8.0.min.js"></script>
<script>

$(function(){
    alert("A");
});

$(document).ready(function(){
    alert("B");
});

function load(){
    alert("D");
};

window.onload=function(){
    alert("E");
};

</script>
<body onload="load();">
</body>
</html>

运行下面代码。弹出A、B、D、E的顺序:A=B>D=E。
a与b在不关乎图片视频等资源的情况下直接加载,所以较快

5.vue的生命周期

beforeCreate:组件刚被创建,data和组件的属性被计算之前,不能访问到data,computed,watch,methods上的方法和数据,data什么的都是undefined
created:组件实例创建完成,data属性绑定,dom还没生成
beforeMounted:找到对应的template,并编译成render函数。此时,this.$el(打印当前组件的dom元素)上有值,但是数据还没挂载到页面上,即此时页面中的{{}}还没有被替换掉
mounted:dom已生成,此时可以通过DOM API获取到DOM节点,$ref属性可以访问。
beforeUpdate:响应式数据更新时调用,发生在虚拟DOM打补丁之前执行的函数。数据更新了,但是,vue(组件)对象对应的dom中的内部(innerHTML)没有变,所以叫作组件更新前。
update:由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
activated:keep-alive 组件激活时调用
deactivated:keep-alive 组件停用时调用。
beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

1.在created钩子中可以对data数据进行操作,这个时候可以进行ajax请求将返回的数据赋给data
2.在mounted钩子对挂载的dom进行操作
3.在使用vue-router时有时需要使用<keep-alive></keep-alive>来缓存组件状态,这个时候created钩子就不会被重复调用了,如果我们的子组件需要在每次加载的时候进行某些操作,可以使用activated钩子触发。
4.beforeDestroy,页面组件内容销毁前使用,所有对象数据都会清空。

6.vue父子组件之间的生命周期执行顺序

初始化时顺序:
1.父组件:beforeCreate
2.父组件:created
3.父组件:beforeMounted
4.子组件:beforeCreated
5.子组件:created
6.子组件:beforeMounte
7.子组件:mounted
8.父组件:mounted

销毁时顺序如下:
1.父组件:beforeDestory
2.子组件:beforeDestory
3.子组件:destoryed
4.父组件:destoryed

当混入mixins加入时,混入mixins处在最优化触发
就是每个阶段都优先触发 混入mixins的生命周期钩子,然后到下一个阶段。

7.vue实现数据双向绑定的原理

是通过 数据劫持 + 订阅发布者模式 实现的
数据劫持:
指的是在修改或者访问某个对象的属性时,通过代码拦截劫持,然后进行修改返回这个最后的结果

vue2.x使用Object.defineProperty();
vue3.x使用es6的Proxy;

订阅发布者模式:
对象数据之间存在着一对多的相互依赖对应关系,当一个数据发生改变时,所有的依赖对象都会收到通知。

Object.defineProperty()的缺陷:

虽然Object.defineProperty通过为属性设置getter/setter能够完成数据的响应式,但是它并不算是实现数据的响应式的完美方案,某些情况下需要对其进行修补或者hack,这也是它的缺陷,主要表现在两个方面:
1️⃣无法检测到对象属性的新增或删除
2️⃣不能监听数组的变化

具体实现:
利用Object.defineProperty();把内部解耦为三部分
Observer: 递归的监听对象上的所有属性,当属性改变时触发对应的watcher
watcher(观察者):当监听的数据值修改时,执行相应的回调函数,更新模板内容
dep:链接observer和watcher,每一个observer对应一个dep,内部维护一个数组,保存与该observer相关的watcher

8.vue组件之间的传递

父组件→子组件
<div class="father">
    <child :inputName="name">
</div>

<div class="child">
    {{inputName}}
</div>
通过props接受数据
(1)props: {
   inputName: String,
   required: true
  }
(2)props: ["inputName"]
子组件→父组件
子组件使用 $emit('方法名','其他参数')传递

子组件:
<input type="button" value="点击触发" @click="childClick">
data:{
    childdata:'hello'
}
methods:{
    childClick(){
        this.$emit('goFather',childdata)
    }
}

父组件:
<child @goFather="fatherFunction"></child>
methhods:{
    fatherFunction(content){
        console.log(content) //content是传递上来的数据
    }
}

父组件调用子组件的方法

父组件:
<div @click="parentMethod">
    <children ref="child"></children>
</div>

this.$refs.child.childMethods(); //childMethods()是子组件中的方法

父子组件之间修改数据

this.$children.msg='123'
this.$parent.msg='456'

兄弟之间传值使用vuex或者 vue 全局事件(eventBus)

9.vue路由的钩子函数

主要包括beforeEachaftrEach

beforeEach函数有三个参数:

to:router即将进入的路由对象
from:当前导航即将离开的路由
next:Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是 confirmed (确认的);否则为false,终止导航。
afterEach函数不用传next()函数
这类钩子主要作用于全局,一般用来判断权限,以及以及页面丢失时候需要执行的操作

10.vuex的使用

1.state:用于存储状态,相当于公共data,可以让所有引入的组件获取。通过this.$store.state....获取
2.getters:相当于计算属性,可以以data中的数据源为基础,返回一个新的data,而且这个data是随着 state中数据的改变而改变的。
3.mutations:相当于methods,在这个属性中可以再添加方法,可以传递 state作为第一个参数,和第二个payload作为自定义参数。其他组件可以通过 commit 来调用这里的方法,来改变视图
4.action:大致和mutations类似,但可以用于异步操作。
备注:如果在mutations中进行异步操作,可能会导致最后的数据不可追踪,如果在该数据上进行计算可能不是最新的或者正确的。

11.computed与watch的区别

当我们需要根据一个数据的变化来进行操作或者计算另一个数据的时候,我们可以使用计算属性,如果计算比较复杂并且带有异步操作,建议用watch

12.v-if与v-show的区别

前者为false的时候,不生成节点,后者为false的时候为 display:none
前者有更高的切换渲染消耗,频繁切换建议使用后者

13.常用ES6

1.变量赋值,let const 新增块作用域
2.字符串模版
3.解构赋值
4.新增箭头函数,捕获上下文来产生this
5.模块化 export import
6.Set(可用于数组去重和数组合并等) 和 Map(对象方法)
7.promise 将同步变成改成异步变成,可以用来代替某些需要使用settimeout的尴尬时候

14.小程序组件传值

父组件→子组件

<!-- 父组件A wxml -->
<view>
  <componentB paramAtoB='{{paramAtoB}}'></componentB>
</view>

通过properties来接收父组件的传值,类似vue的props
//子组件B  js
Component({
  //B在这里接收与data类似可以直接在wxml上用
  properties: {
    paramAtoB: {
      type: String,//类型
      value: 'default value'//默认值
    }
  },
  data: {
    
  }
})

子组件→父组件

this.triggerEvent('方法名','参数') //类似vue的 this.$emit()

15.小程序的分包管理

改变目录结构,修改app.json的配置
打破2mb小程序大小的限制

16.浅拷贝与深拷贝

浅拷贝,只拷贝到了对象的第一层,方法:循环拷贝,Object.assign()

深拷贝,拷贝到对象的多有层级,json.prase(json.stringify(obj))
或者可以都使用第三方库

17.webpack热更新简要原理

1️⃣Webpack Watch:webpack通过调用watch监听文件变化,重新编译打包,将变化通过js对象先简单的保存在内存中
2️⃣Webpack-dev-middleware:页面的访问需要依赖web服务器,它把 Webpack 处理过的文件发送到一个服务器上,就是Webpack-Dev-Server,他内置了 Webpack-dev-middleware 和 Express 服务器,Webpack-dev-middleware可以通过插件访问内存文件。这样就能访问到之前保存在内存中的js对象了。
3️⃣通过webpack-dev-server,在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段的状态信息告知浏览器端
4️⃣浏览器向服务端发送一个请求,返回json,其中包含了所有需要更新模块的信息,最后HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块

18.原型链

每个对象都可以有一个原型proto,这个原型还可以有它自己的原型,以此类推,形成一个原型链。查找特定属性的时候,我们先去这个对象里去找,如果没有的话就去它的原型对象里面去,如果还是没有的话再去向原型对象的原型对象里去寻找...... 这个操作被委托在整个原型链上,这个就是我们说的原型链了。
原型链的最后一层:Object.prototype.__proto__ //null

19.闭包

闭包就是能够读取其他函数内部变量的函数。
例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。
功能:将函数内部和函数外部连接起来,读取其他函数内部变量

 //闭包demo
function a(){
  var x = 2
  function b(){
    console.log(x)
  }
}
a()

20.浏览器从输入url到页面展示过程

1️⃣将域名解析成IP地址,浏览器并不能直接通过域名找到服务器,而是要通过ip地址。
2️⃣浏览器与服务器建立tcp协议
三次握手:
第一次:浏览器向服务器发送请求报文
第二次:服务器接收后向浏览器发送确认报文
第三次:浏览器再向服务器发送确认报文
3️⃣浏览器发送http请求
4️⃣服务器处理http请求
5️⃣浏览器解析html,渲染页面,构建dom树,绘制页面
6️⃣断开TCP连接

21.js事件流

事件流:事件流描述的是页面中接受事件的顺序,微软为事件冒泡,网景为事件捕获

事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点

事件流包括三个阶段,分别是捕获阶段,目标阶段,冒泡阶段。

当事件发生时,最先得到通知的是window,然后是document,由上至下逐级依次而入,直到真正触发事件的那个元素(目标元素)为止,这个过程就是捕获。
接下来,事件会从目标元素开始起泡,由下至上逐级依次传播,直到window对象为止,这个过程就是冒泡。


image.png

21.包装对象

js数据类型被分为了两大类型:基本类型和引用类型。

 基本类型:Undefined,Null,Boolean,Number,String

 引用类型:Object,Array,Date,RegExp。

引用类型都有方法和函数,但是基本类型没有。

var str = 'hello'; //string 基本类型
var s2 = str.charAt(0);
alert(s2); // h

毫无疑问上面的string是一个基本类型,但是它却能召唤出一个charAt()的方法。

主要是因为在基本类型中,有三个比较特殊的存在就是:String Number Boolean,这三个基本类型都有自己对应的包装对象。并且随时等候召唤。包装对象呢,其实就是对象,有相应的属性和方法。至于这个过程是怎么发生呢,其实是在后台偷偷发生的。

var str = 'hello'; //string 基本类型
var s2 = str.charAt(0); 
//在执行到这一句的时候 后台会自动完成以下动作 :
( 
// 1 找到对应的包装对象类型,然后通过包装对象创建出一个和基本类型值相同的对象
 var str = new String('hello'); 
 // 2 然后这个对象就可以调用包装对象下的方法,并且返回结给s2.
 var s2 = str.chaAt(0);
//    3 之后这个临时创建的对象就被销毁了, str =null; 
 str = null;  
 ) 
alert(s2);//h 
alert(str);//hello     注意这是一瞬间的动作 实际上我们没有改变字符串本身的值。就是做了下面的动作.这也是为什么每个字符串具有的方法并没有改变字符串本身的原因。

由此我们可以知道,引用类型和基本包装对象的区别在于:生存期
那如何给字符串添加属性方法呢

//给字符串添加方法  要写到对应的包装对象的原型下才行
var str = 'hello';
String.prototype.last= fuction(){ 
    return this.charAt(this.length);
}; 
str.last(); // 5 执行到这一句,后台依然会偷偷的干这些事
{ 
    var str = new String('hello');// 找到基本包装对象,new一个和字符串值相同的对象,
    str.last();  // 通过这个对象找到了包装对象下的方法并调用 
    str =null; //  这个对象被销毁
}

22.css中 可以被继承的属性

以下的都是可以被继承的,除了这些之外,其他的都不可被继承。
文本相关属性:
color,font-family,font-size,font-style,font-variant,font-weight,font,letter-spacing,line-height,text-align,text-indent,text-transform,word-spacing
列表相关属性:
list-style-image,list-style-position,list-style-type,list-style

23.冒泡排序

小的在底下,大的在上面
让数组中的当前项与后一项作对比,交换位置大的排后边,循环进行 。
sort()

let  ary =[11,33,22,44];
ary.sort(function(a,b){
//a代表当前项,b代表下一项,判断 a与b的大小,如果a>b,a与b交换  位置
  return a-b;//升序  
})
console.log(ary)  //[11,22,33,44]
ary.sort(function(b,a){
  return b-a;//降序  
})
console.log(ary)  //[44,33,22,11]

不传参数 只能 处理十以内的排序,会按照第一位数字的大小排序.

冒泡排序思想
image.png

实现 代码


image.png

24.防抖和节流

防抖:

当使用 onmouseover 滚轮滚动,延迟加载等的操作触发事件的时候,容易造成一瞬间一定时间内执行多次,从而造成一些问题或者性能降低。
假如我希望在5秒内一个操作只执行一次,如果到4秒的时候去触发它则仍不执行,并且重新计时,只有在5秒内没有操作后去触发才会执行。

节流:

与 防抖 不同的是,节流就算在延迟时间内不停的触发 ,不会重新计算时间,仍旧会在5秒后输出,而不会像防抖那样,在第四秒触发后,重新从0在开始计时。
作用:提高性能节省资源

25.真随机 伪随机

1.真随机数 TRUE Random Number
真正的随机数是使用物理现象产生的:比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等,这样的随机数发生器叫做物理性随机数发生器,它们的缺点是技术要求比较高。 ----百度百科

2.伪随机数 Pseudo-Random Number

真正意义上的随机数(或者随机事件)在某次产生过程中是按照实验过程中表现的分布概率随机产生的,其结果是不可预测的,是不可见的。而计算机中的随机函数是按照一定算法模拟产生的,其结果是确定的,是可见的。我们可以这样认为这个可预见的结果其出现的概率是100%。所以用计算机随机函数所产生的“随机数”并不随机,是伪随机数。

---百度百科

从定义我们可以了解到,伪随机数其实是有规律的。只不过这个规律周期比较长,但还是可以预测的。主要原因就是伪随机数是计算机使用算法模拟出来的,这个过程并不涉及到物理过程,所以自然不可能具有真随机数的特性。
————————————————
版权声明:本文为CSDN博主「绘夜」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/czc1997/java/article/details/78167705

26.apply call

我们知道,在函数中谁调用函数,this就指向谁

function  test(){
    console.log(this)  //this 指向window 对象 
}

let  hello = {
   fun:test
}
hello.fun() //{fun:f} 此时this指向hello
//也可以这样操作 
test.apply()
test.call()
//当传入参数
test.apply(hello )   //打印 hello对象 
test.call(hello )     //打印 hello对象 
apply和call的作用 :

1️⃣他们可以通过传入其他对象来改变当前this的指向

apply和call的区别 :
test.call(hello,1,2,3 )   //以此传入hello和1,2,3参数 
test.apply(hello,[1,2,3] )   //打印 hello对象, 但后面的参数需要放在一个数组中 

27.构造函数

是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。

上一篇下一篇

猜你喜欢

热点阅读