前端八股第一弹

142 阅读25分钟

说一下生命周期

vue生命周期是指一个vue实例从创建到销毁的过程,通常在发送请求,清除定时器时都会用到。 vue生命周期分为八个阶段: beforecreated(创建前),created(创建后),beforeMounted(加载前),monted(加载后),beforeupdate(更新前),updated(更新后),beforedestroy(销毁前),destroied(销毁后)

说一下组件通信

6种方式

  1. props和$emit

父组件通过props向子组件传递数据,子组件通过$emit触发事件向父组件传递数据

  1. attrs和listeners

第一种方式的缺陷在于如果组件间存在多层嵌套关系,a的子组件是b,b的子组件是c,那么a该如何传递数据给c,如果还使用props就会很复杂,所以使用attrs和listeners a可以直接传递数据给c

  1. v-model

父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,子组件可以通过$emit('input',val)直接更改v-model绑定的值

  1. provide和inject

父组件通过provide提供变量,子组件通过inject注入变量,不论子组件有多深,只要调用了inject,都可以使用provide中的数据,而不是局限于只能从当前父组件的props属性中获取数据,只要在父组件的生命周期内,不管多深的子组件都可以调用

  1. 中央事件总线eventBus

兄弟之间组件通信就使用中央事件总线eventBus,创建一个vue事件bus对象,使用bus.emit触发事件bus.on监听触发的事件

  1. 使用vuex

通常需要多个组件同时处理数据,就需要用到vuex状态管理工具,将公共数据单独抽离出来,然后其他组件就可以对公共数据进行读写操作

说一下vuex

vuex是vue中提供的状态管理工具,将公共数据单独抽离出来,其他组件可以对公共数据进行一系列操作

  1. state()存储基本数据类型
  2. getters()计算属性
  3. mutation()通过$store.commit方法更改state中的数据
  4. action()通过 dispatch提交mutation,更改state中的数据

说一下双向绑定的原理

错误: v-bind:绑定data中的数据 oninput事件:绑定input事件

1. v-bind绑定响应式数据 2. 触发oninput事件并传递数据

知道哪些vue指令

v-html:插入一段html片段 相当于innerhtml v-text:会覆盖原先的字符串,插入文字 v-if:配合v-else和v-else-if使用控制显示隐藏,频繁显示隐藏时使用 v-show:控制绑定元素的显示隐藏,相当于display v-model:双向绑定 v-bind:给属性绑定值 v-on:@ 绑定事件 v-for:用来遍历数组对象,字符串

说一下自定义指令

自定义指令:自己定义的指令,可以封装一些dom操作,扩展额外功能

一.自定义指令的使用

1) 可以使用Vue.directive( dir_name , {} ) 来定义全局自定义指令

2) 也可以使用 directives{ dir_name : {} } 来定义局部自定义指令

二.构造函数 1) bind

只调用一次, 当指令第一次绑定在元素上时.用来做一次性初始化操作.

2) inserted

当绑定元素已插入到父节点时调用.也就是说 必定存在父节点.但是它及它的父节点未必存在文档中.

3) update

在包含该组件的VNode更新后调用该函数.可能在其子级更新前调用.指令的值可能已更改,可能未更改.最好通过判断新旧值来过滤掉不必要的操作.

4) componentUpdated

在包含该组件的VNode 以及 其子节点的VNodes已更新之后 调用.

5) unbind

指定从元素上解绑时,调用一次.局部的自定义指令,只能在当前组件的模板中去用

三.钩子函数的参数

1)el

绑定了该指令的元素.可以直接操作DOM元素.

2)binding ( 包含以下属性 ) name,刨除’v-'前缀的指令名

3)value

传递给指令的值. e.g. v-s="1+1", value就是2

4)oldValue

旧值 , 只在 钩子函数 update 以及 componentUpdated 中可用. 无论值是否改变都可用

5)expression

表达式的字符串形式.

6)arg

传递给指令的参数 . e.g. v-s:foo , arg就是 foo

7)modifiers

包含修饰符的对象.e.g. v-s.a.b 意味着 modifiers 为 {a : true , b:true}

8)vnode

vue编译器提供的虚拟节点对象. 详见 VNode API

9)oldVnode

之前的虚拟节点对象. 只在钩子函数 update 和 componentUpdated 中可用.

说一下路由传参

  1. 路由是什么? 路由传参是指在前端路由中通过URL传递参数的方式,用于在不同页面之间传递数据和状态信息

  2. 路由跳转的两种方式?

    ①声明式导航:通过router-link实现(必须要有to属性),实现路由跳转
    ②编程式导航:利用的是组件实例的router.pushrouter.push或router.replace方法,实现路由的跳转,同时也可在里面书写一些其他业务,比如路由传参

  3. 路由传参的三种写法:

    params传参:属于路径当中的一部分,在配置路由的时候需要占位
    query传参:不属于路径当中的一部分,比如/home?k=v&k=v,不需要占位
    props传参:路由组件传参(有三种方式)

说一下防抖节流

防抖:一定时间内(定时器延时间),用户频繁地去触发一个事件,只执行最后一次的触发--比如输入框的input事件,每输入一个文字就会触发一次,这样频繁的触发会消耗性能,使用防抖之后,只会在你输入完成后才会触发

节流:控制触发事件的次数,控制多久才能触发一次,分为首节流和尾节流 节流可以理解为游戏中的技能,释放一个技能会有技能cd,等cd事件结束才可以再次释放技能 首节流:使用时间戳实现,触发事件之后能立即执行 尾节流:使用定时器实现,触发事件后要经过延时才会执行

说一下this

this指向调用者,谁调用的this就指向谁, 箭头函数中this指向windows

怎么阻止默认事件

prevent.default()

怎么阻止事件冒泡

1. 使用 event.stopPropagation() 方法: 2. Vue 提供了一种更简洁的方式来阻止事件冒泡,那就是使用 .stop 修饰符。(@click.stop)

数组常用的方法

带~符号的方法会改变原数组

  1. array.push() :表示向数组末尾进行追加~
  2. array.pop() :从数组的末尾开始删除,并且返回这个元素~
  3. array.length():获取当前数组的长度
  4. array.include():用来判断一个数组是否包含一个指定的值
  5. array.slice():用来截取某一个片段 浅拷贝
  6. array.splice() :删除替换插入~
  7. array.filter() :过滤
  8. array.unshift():表示向数组最前面进行追加~
  9. array.shift():删除数组的第一个元素,并返回这个数组~
  10. array.sort():排序~
  11. array.reverse():可以将数组进行翻转~
  12. array.concat():做合并,拼接
  13. array.join()
  14. array.map():表示映射,对数组中的每个元素进行处理,返回新的数组,数组中的元素为原始数组元素调用函数处理后的值
  15. array.forEach():对数组进行遍历循环,这个方法没有返回值
  16. array.isarray():判断类型是否为数组
  17. array.every():根据一个条件判断当前数组是不是都满足这个条件
  18. array.reduce():为数组提供一个累加器,合并为一个值
  19. array.find():找某个符合条件的数据
  20. array.findIndex():找某一个符合条件的数据的索引
  21. array.some();根据一个条件判断当前数组是不是有一个满足这个条件

数组去重知道哪些方法

  1. for循环+findIndex

    主要利用findIndex 的特性,查找元素找不到返回-1, 接下来就需要判断,如果是-1,说明没找到,就往新数组里面添加元素。

var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法2: for + indexof
    function newArrFn (arr) {
      let newArr = []
      for(let i = 0;i<arr.length;i++){
        newArr.indexOf(arr[i]) === -1 ? newArr.push(arr[i]) : newArr
      };
      return newArr
    }
    console.log(newArrFn(arr));

  1. sort排序

    首先利用 sort 方法进行排序。进行循环,如果原数组的第 i 项和新数组的i - 1 项不一致,就push进去。

var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法3: for + sort
    function newArrFn (arr) {
      arr = arr.sort()
      let newArr = []
      for(let i = 0;i<arr.length;i++){
        arr[i] === arr[i-1] ? newArr : newArr.push(arr[i])
      };
      return newArr
    }
    console.log(newArrFn(arr));

  1. Set

    ES6中新增了数据类型Set,Set的一个最大的特点就是数据不重复,Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重。

var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法4: set
    function newArrFn (arr) {
      // .new Set方法,返回是一个类数组,需要结合 ...运算符,转成真实数组
      return ([...new Set(arr)])
    }
    console.log(newArrFn(arr));

  1. filter + indexOf indexOf,可以检测某一个元素在数组中出现的位置,找到返回该元素的下标,没找到返回 -1
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法6 :filter + findIndex
    function newArrFn (arr) {
      // 利用indexOf检测元素在数组中第一次出现的位置是否和元素现在的位置相等,
      // 如果相等,说明数组中没有重复的
      return Array.prototype.filter.call(arr, function (item, index) { 
        return arr.indexOf(item) === index
       })
    }
    console.log(newArrFn(arr));

  1. includes

    利用 includes 检查新数组是否包含原数组的每一项。 如果不包含,就push进去

var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法7 :for + includes
    function newArrFn (arr) {
      // 利用includes 检查新数组是否包含原数组的每一项
      // 如果不包含,就push进去
      let newArr = []
      for(let i = 0;i<arr.length;i++){
        newArr.includes(arr[i]) ? newArr:  newArr.push(arr[i]) 
      };
      return newArr
    }
    console.log(newArrFn(arr));

  1. Map

var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法11 :Map
    function newArrFn (arr) {
      let newArr = []
      let map = new Map()
      for(let i = 0;i<arr.length;i++){
        // 如果 map里面不包含,就设置进去
        if (!map.has(arr[i])) {
          map.set(arr[i], true)
          newArr.push(arr[i])
        }
      };
      return newArr
    }
    console.log(newArrFn(arr));

  1. reduce
var arr = [1, 2, 3,4 ,5,6, 4, 3, 8, 1]
    // 数组去重:
    // 方法12 :reduce
    function newArrFn (arr) {
      let newArr = []
      return  arr.reduce((prev, next,index, arr) => {
        // 如果包含,就返回原数据,不包含,就把新数据追加进去 
        return newArr.includes(next) ? newArr :  newArr.push(next)
      }, 0)
    }
    console.log(newArrFn(arr));

字符串操作方法

查找

  1. find():检测某个子串是否包含在这个字符串中,如果在返回这个子串 开始的位置下标,否则返回-1
  2. index():检测某个子串是否在这个字符串中,如果在,返回这个子串开始的位置下标,否则就报错
  3. count():返回某个子串在字符串中出现的次数

修改

  1. replace():替换
  2. split():按照指定字符分割字符串

判断(返回的结果都是布尔类型)

  1. startwith():检查字符串是否以指定子串开头
  2. ends with():检查字符串是否以指定子串结尾
  3. isalpha():如果字符串至少有一个字符,并且所有字符都是字母true
  4. isdigit():如果字符串只包含数字就返回true

怎么判断一个数是不是素数,逻辑怎么写?

//	判断一个数是不是素数(质数)。(只能被1和自身整除的数,或者说:除了1和它自身以外,再没有其它数能整除它)
//方法一:
 
function test(){
	//1、输入
	var num = parseInt(document.getElementById("num").value);//9
	//2、业务逻辑
	
	for(var i=2;i<=num-1;i++){//i=7  num=7
		if(num%i==0){
			break;
		}
	}
	
	if(i>num-1){
		alert(num+"是素数");
	}else{
		alert(num+"是合数");
	}	
}
//方法二:
 
 
function test(){
	//1、输入
	var num = parseInt(document.getElementById("num").value);//9
	//2、业务逻辑
	var isSu=true;//isSu:表示是否为素数;假设是素数;
	
	for(var i=2;i<=num-1;i++){
		if(num%i==0){
			isSu = false;
			break;
		}
	}	
	if(isSu==true){
		alert(num+"是素数");
	}else{
		alert(num+"是合数");
	}	
}
 
//方法三:
function test(){
	//1、输入
	var num = parseInt(document.getElementById("num").value);//9
	
	//2、业务逻辑
	var count=0;//记录整除的次数
	for(var i=2;i<=num-1;i++){//
		if(num%i==0){
			count++;
			break;
		}
	}
	
	if(count==0){
		//3、输出
		alert(num+"是素数");		
	}else{
		alert(num+"是合数");		
	}
	
}

怎么清除浮动

页面布局当中,在无法确定子元素的高度时,我们无法给父级标签一个固定的高度,我们想要的是通过子元素的高度来确定父元素的高度,所以当子元素设置了浮动的属性之后,父元素的高度没有进行设置,这样就会导致父元素的高度塌陷(原本的height被重置为0),这就涉及到了浮动的重要性

  1. 额外标签法:该方法就是在浮动元素末尾添加一个空的标签,在给空标签添加一个清除浮动的样式
<div class="app">
  <div class="app1">手机</div>
  <div class="app2">电脑</div>
  <div class="clear" style="clear: both;"></div>  <!-- 添加一个空的标签 -->
</div>


  1. 给父元素添加overflow:hidden

html

<div class="app">
  <div class="app1">手机</div>
  <div class="app2">电脑</div>
</div>


css

<style type="text/css">
	* {
		margin: 0px;
		padding: 0px;
	}
	.app{
		overflow: hidden; /* 父元素添加 overflow 属性清除浮动 */
		width: 500px;
		margin: 0 auto;
		border: 1px solid #409EFF;
	}
	.app1{
		float: left;  /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: skyblue;
	}
	.app2{
		float: left; /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: pink;
	}
</style>


  1. :after伪元素法
<style type="text/css">
	* {
		margin: 0px;
		padding: 0px;
	}
	/* --------以下两行样式代码为固定写法--------  */
	.clearfix:after{
		content: '';
		display: block;
		height: 0;
		clear: both;
		visibility: hidden;
	}
	.clearfix{
		/* 为 IE6、IE7浏览器设置的清除浮动 */
		*zoom: 1;
	}
	/* --------以上两行样式代码为固定写法--------- */
	.app{
		width: 500px;
		margin: 0 auto;
		border: 1px solid #409EFF;
	}
	.app1{
		float: left;  /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: skyblue;
	}
	.app2{
		float: left; /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: pink;
	}
</style>


  1. :after和:before双伪元素清除浮动
<style type="text/css">
	* {
		margin: 0px;
		padding: 0px;
	}
	/* --------以下两行样式代码为固定写法--------  */
	.clearfix:after,.clearfix:before{
		content: '';
		display: table;
	}
	.clearfix:after{
		clear: both;
	}
	.clearfix{
		/* 为 IE6、IE7浏览器设置的清除浮动 */
		*zoom: 1;
	}
	/* --------以上两行样式代码为固定写法--------- */
	.app{
		width: 500px;
		margin: 0 auto;
		border: 1px solid #409EFF;
	}
	.app1{
		float: left;  /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: skyblue;
	}
	.app2{
		float: left; /* 子元素向左浮动 */
		width: 200px;
		height: 100px;
		background-color: pink;
	}
</style>


后面都是固定写法,记住即可

div怎么垂直居中

  1. 使用外边距属性来使div水平垂直居中
  2. 绝对定位:只要让容器开启绝对定位,并且left,right,top,bottom全为0,margin:auto就能实现div水平居中了
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绝对定位</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    /* 父容器 */
    .container{
      height: 700px;
      position: relative;
      background-color: black;
    }
    /* 子容器 */
    .son{
      width: 300px;
      height: 300px;
      background-color: white;
      position:absolute;
      /* 水平垂直居中 */
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="son"></div>
  </div>
</body>
</html>


  1. 子元素绝对定位,父元素相对定位---给父容器开启相对定位,子元素开启绝对定位。水平据中:left:50%;margin-left:-150px;垂直居中:top:50%;margin-top:-150px
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>子绝父相</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    /* 父容器 */
    .container{
      height: 700px;
      background-color: black;
       /* 父容器开启相对定位*/
      position: relative;
    }
    /* 子容器 */
    .son{
      width: 300px;
      height: 300px;
      background-color: white;
      /* 子容器开启绝对定位*/
      position:absolute;
      /* 水平垂直居中 */
      top: 50%;
      margin-top: -150px;
      left: 50%;
      margin-left: -150px;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="son"></div>
  </div>
</body>
</html>


  1. flex布局:给父容器开启flex布局,父容器就变成flex容器了,子容器就变成flex项目了,利用flex布局控制项目水平方向和垂直方向排列的属性,使div垂直水平据中

justify- content:center;水平据中

align-items:center;垂直居中

怎么画0.5px的线

  1. box-shadow :box-shadow允许小数点,该属性可设置的值包括阴影的x轴偏移量,模糊偏移量,y轴偏移量,模糊半径,扩散半径和颜色,所以我们可以设置他的扩散半径来实现0.5px的线
  2. transform:缩放实现的思路,transform:scaleY(0.5);
  3. 线性渐变 linear-grandient background:linear-grandient(0deg,#fff,#000);边框线性渐变的答案,同样设置任意大小的边框,通过渐变属性改变一部分边框的颜色效果,比如将一部分边框融入背景,这样就能得到想要的效果

说一下盒模型

  1. 盒模型是css布局的基石,规定了网页元素如何显示以及元素之间相互关系,css定义所有的元素都可以拥有像盒子一样的外形和平面空间,即都包含内容区,内填充,边框,外边距,这就是盒模型

盒模型的组成=content+padding+border+margin

  1. 内填充:padding,在设定页面中一个元素内容到元素的边缘之间的距离,也称补白,padding不可以写负值。padding的作用:改变元素在父元素的位置,改变内容在容器中的位置,padding会把盒子撑大,如果想让盒子保持原有的大小:在宽高的值基础上减掉

padding值的设定:先上下后左右,一个值表示上下,两个值表示一个上下,一个左右,三个值:上 左右 下,四个值:上 右 下 左;还可以单独设定单独方向的padding,padding-top,padding-bottom,padding-left,padding-right

  1. 外边距margin,margin可以写负值!作用:控制元素跟元素之间的间距,margin在元素外围,不会撑大元素的大小。说明:可单独设置某一方向边界。margin:0 auto 元素水平居中

  2. 盒模型:标准盒模型中,width(height)=content;ie盒子模型中(怪异盒模型)中,width(height)= border+padding+content;box-sizing:border-box(怪异盒模型);box-sizing:contnt-box(标准盒模型)

两个异步请求数据操作怎么合并

  1. 使用promiseAll().then(()=>{}).catch(()=>{});并发处理多个异步任务,所有任务都执行完成才能得到结果
Promise.all( [p1,p2,p3] ) .then ( (result) => {consoleog (result)
})

  1. Promise.race().then().catch();并发处理多个异步任务,只要有一个任务完成就能得到结果
 
Promise.race ( [p1,p2,p3] ).then ( (result)=>{
console. log (result)
})

v-model是谁的语法糖

语法糖:对语言功能并没有语法,但是更方便程序员使用,简而言之,语法糖让程序更加简洁,有更高的可读性 相当于:<mycom ;value="xxx" @input="新值=>xxx=新值"/>

总结:v-model做两件事:

  1. 向自组件传来一个名为value的属性
  2. 在子组件监听input事件,这个事件的回调中修改value所绑定的值

一个值实现两个功能,子传父(input事件),父传子(value属性)

query和params的区别

vue怎么获取dom

  1. 使用dom API直接找元素

这种方法足够简单直观,vue组件在patch阶段结束时会把this.el赋值为挂载的根dom元素,我们可以直接使用el赋值为挂载的根dom元素,我们可以直接使用el的querySelector,querySelectorAll等方法获取匹配元素

  1. refs

使用组件实例的$refs即可拿到组件上ref属性对应的元素。如果ref属性加在一个组件上,那么拿到的是这个组件的实例,否则拿到的就是dom元素了。值得注意的是包含v-for循环模版指令的情况,其循环元素和子元素上ref属性对应的都是一个数组(就算动态生成ref,也是数组)

  1. 使用自定义指令

vue提供了自定义指令,el就是dom元素的引用

flex布局怎么把元素搞到右上角

display:flex justify-content:flex-end 设置水平线上的元素靠右 justify-content:center 设置水平线上的元素居中 元素默认靠左,第一行第一个 align-items:center 元素垂直居中 flex-end垂直向下对齐 复杂的在csdn收藏中看

promise有几种状态,会不会改变

三种状态,同一时间只能存在一种状态,且状态一旦改变就不能再变,promise是一个构造函数,promise对象代表一项只有两种可能结果的任务,他还持有多个回调,出现不同结果时发出不同相应回调函数

  1. pending(待处理)

初始化之后状态就是待处理状态pending

  1. fulfilled(成功)

当调用resolve时,即为成功,状态由pending=>fulfilled

  1. rejected(失败)

当调用reject 时,即为失败,状态pending=>rejected

优点:

  1. promise分离了一部数据获取和业务逻辑,有利于代码复用
  2. 可以采用链式写法
  3. 一旦promise的值确定为fulfilled或者rejected之后,不可改变

缺点:

  1. 代码冗余,语义不清

async和await解决什么问题?

async和await是一种建立在promise之上的编写异步或阻塞代码的新方法,被普遍认为是js异步操作的最终且最优雅的解决方案。相对于promise和回调,他的可持续性和简洁度都更高。一直.then()也不好看

所以从语义上就很好理解async用于声明一个function是异步的,而await用于等待一个异步方法执行完成,一个函数如果加上async,那么函数返回的是一个promise对象,如果在async函数中追额return一个量,async会把这个量通过promise.resolve()封装成promise对象返回

let和const区别

相同点:

  1. let只在声明所在的块级作用域内有效
  2. 没有变量提升,同时存在暂时性死区,只能在声明的位置后面使用
  3. 不可以重复声明

不同点:

  1. let声明的变量可以改变,值和类型都可以改变;const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值

let和var比较是比较声明问题,let和const比较是比较值的修改问题

const定义对象里面的属性能不能改?

const定义的对象属性可以修改,但是const定义的基本数据类型string,number等,定义后不可修改,如果修改会报错。

const定义中的不变指的是指向对象的指针不变,因为修改对象中的属性并不会让指向对象的指针发生改变,所以可以改变const定义对象的属性。

常见状态码

当我们访问一个网页时,浏览器会向网页所在服务器发出请求,当服务器收到请求后,就会解析请求并作出响应,同时服务器会返回一个包含http状态码的信息头用以响应浏览器的请求。但是这个过程并不百分百成功,并且情况也很复杂,所以状态码就起到了至关重要的作用。 状态码共分为五种类型:

  1. 1**:信息,服务器收到请求,需要请求者继续执行操作
  2. 2**:成功,操作被成功接受并处理
  3. 3**:重定向,需要进一步的操作以完成请求
  4. 4**:客户端错误,请求包含语法错误或者无法完成请求
  5. 5**:服务器错误,服务器错误,服务器在处理请求的过程中发生了错误

对同步和异步的理解

同步:同步是指一个进程在执行某个请求时,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,知道收到返回信息才会继续执行下去

异步:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就提高了执行的效率,即异步是我们发出的一个请求,该请求会在后台自动发出并获取数据,然后对数据进行处理,在此过程中,我们可以继续做其他操作,不管他怎么发送请求,不关心她怎么处理数据。

  • 为什么要在js中使用异步

由于js是单线程的,自己能在js引擎的主线程上运行的,所以js代码只能一行一行执行,不能在同一时间执行多个js代码任务,这就导致如果有一段耗时较长的计算,或者是一个ajax请求等io操作,如果没有一部的存在,就会出现用户长时间等待,并且由于当前任务还未完成,所以这时候其他操作都会没有响应

  • 为什么js不设计成多线程的?

这主要和js的历史有关,js最开始只是为了处理一些表单验证和dom操作而被创造出来的,所以主要为了语言的轻量和简单采用了单线程的模式,多线程相比于单线程要复杂很多,比如多线程要处理线程间资源共享的问题,还要解决状态同步等问题。如果js是多线程的话,当你要执行往div中插入一个dom的操作的同时,另一个线程执行了删除这个div操作,这个时候就会出现很多的问题,我们还需要为此增加解锁机制等

  • 常见的异步模式有哪些呢?

回调函数,事件监听,发布订阅模式(观察者模式),promise

js是如何实现异步操作呢?

就是js的事件循环机制

什么是js事件循环机制?

当js解析执行时,会被引擎分为两类任务,同步任务和异步任务,对于同步任务来说,会被推倒执行栈按顺序去执行这些任务,对于异步任务来说,当其可以执行时,会被放到一个任务队列中等待js引擎去执行。当执行栈中所有的同步任务完成后,js引擎才会去任务队列中查看是否有任务存在,并将任务放到执行栈中去执行,执行完了又回去任务队列中查看是否有已经可以执行的任务。这种检查的机制就叫做事件循环

常见的宏任务,微任务?

对于任务队列,其实有更细的分类,其被分为微任务队列和宏任务队列

宏任务:setTimeout,setInterval等,会被放在红任务队列中

微任务:promise的then,Mutation Observer等会被放在微任务队列中

EventLoop的执行顺序是:首先执行执行栈里的任务,执行栈清空后,检查微任务队列,将可执行的微任务全部执行。取宏任务队列中的一项执行。回到第二步。注意:微任务队列每次全部执行,红任务队列中每次只取一项执行。

怎么判断两个数组相等?

通过把数组转成字符串的形势判断 arr.toString() ===arr2.toString()

es6遍历数组的方法?

  • for in :以任意字段遍历一个对象的可枚举属性,遍历数据组时,key为下标字符串;遍历对象时,key为对象字段名

for in缺点:

  1. 迭代顺序依赖于执行环境,不一定保证顺序
  2. 不仅会遍历当前对象,还包括愿原型链上的可枚举属性
  3. 没有break中断
  4. 不适合遍历数组,主要应用为对象
  • for of

ES6新引入的语法,在可迭代的对象上(包括Array,Map,Set,String,TypedArray,arguments对象,nodeList对象)创建一个迭代循环,调用自定义迭代勾子,并为并为每个不同属性的值执行语句

let arr = [{age: 1}, {age: 5}, {age: 100}, {age: 34}]
for(let {age} of arr) {
    if (age > 10) {
        break // for of 允许中断
    }
    console.log(age)
}
// 打印
// 1
// 5

for of优点:

  1. 有和for in一样的简介语法,但没有他的缺点
  2. 保证顺序且不会仅仅遍历当前的对象
  3. 可以与break,continue,return配合
  • forEach提供回调函数,不能使用break语句中跳出循环,也不能使用return语句从闭包函数中返回
  • map :map可以改变当前循环的值,返回一个新的被改变过值之后的数组,需要return,一般用来处理需要修改某一个数组的值
  • filter:filter方法有返回值,返回值是一个新的数组,过滤筛选数组
  • some和every:some返回布尔值,只要找到一项为真值,即返回true,只要找到第一个满足条件的元素,就终止循环,不再继续查找;every只要有一项为假,就返回为false,即使找到了符合的元素也会继续查找,every不会对空数组进行检测
  • reduce和findIndex(返回第一个符合条件的)
  • 基础的for循环

前端怎么给数据加密?

  1. Basse64加密:Base64是一种用来将二进制数据编码可读文本形式的编码规范。 调用window.btoa()方法进行加密,调用window.atob()方法进行解密
  2. MD5是一种常用的密码散列函数,通常用于对一段数据产生唯一的“指纹”,以便于验证数据的完整性和一致性。使用md5()方法进行MD5加密操作。

两个html文件怎么传值?

1、url携带参数

优点:取值方便,可以跨域,利于页面分享,没有环境限制。

缺点:url携带参数值的长度有限制。

2、cookie方式

优点:可以在同源内的的任意网页中访问,存储数据的周期可以自由设置。

缺点:有长度限制。

3、设置窗口之间的父子关联关系

优点:取值方便.只要window.opener指向父窗口,就可以访问所有对象.不仅可以访问值,还可以访问父窗口的方法.值长度无限制。
缺点:两窗口要存在着关系.就是利用window.open打开的窗口。不能跨域。

4、h5技术,window.localStorage存储数据

优点:储存空间大,有5M存储空间。

缺点:不是所有浏览器都支持。

个人倾向第一种方式,主要是自己做的网页可以分享,在任何的地方都可以打开,其他的方式都有环境的要求。如果是做大型项目,架构是实现客户端与服务端的分离,建议还是引入客户端框架,框架实现了路由、参数的传递、以及安全问题,可以大大的提高开发效率。

vue3了解多少?