一些面试题的记录

Posted 是小橙鸭丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一些面试题的记录相关的知识,希望对你有一定的参考价值。

1.async await异常处理 如何处理的 优雅处理
正常异常处理(这么看倒没什么 要是多个try catch就很累赘)

const fetchData = () => {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve('fetch data is me')
  }, 1000)
 })
}
 
(async () => {
 try {
  const data = await fetchData()
  console.log('data is ->', data)
 } catch(err) {
  console.log('err is ->', err)
 }
})()

优雅的封装处理

(async () => {
 const fetchData = () => {
  return new Promise((resolve, reject) => {
   setTimeout(() => {
    resolve('fetch data is me')
   }, 1000)
  })
 }
 
 // 抽离成公共方法
 const awaitWrap = (promise) => {
  return promise
   .then(data => [null, data])
   .catch(err => [err, null])
 }
 
 const [err, data] = await awaitWrap(fetchData())
 console.log('err', err)
 console.log('data', data)
 // err null
 // data fetch data is me
})()

promise处理异常

promise.catch()可以捕获promise所有状态的异常。包括:
1、执行resolve()和reject()对应的promise.then(()=>{},()=>{}) 中的俩回调函数中的异常
2、Promise.resolve(err)触发的
3、Promise.reject(err)触发的

<script>
// 定义Promise
const initPromise =  (status) => {
	return new Promise((resolve, reject) => {
		// status 成功 200,失败 其它
		if (status === 200) {
			resolve(); // 由"pending"变为"fulfilled"
		} else {
			reject(); // 由"pending"变为"rejected"
		}
	});
};

// 实例化并调用promise
let testPromise = (status) => {
	const promise = initPromise(status);
	try {
		promise.then(() => {
			// resolve走这个回调
			throw new Error('error from then resolve');
		}, () => {
			// rejected走这个回调
			throw new Error('error from then reject');
		}).catch(e => {
			console.log('promise catch捕获:' + e);
		});
	} catch(e) {
		console.log('try catch捕获:' + e);
	}
}

</script>

结果截图如下:
在这里插入图片描述

在这里插入图片描述

2.computer watch的区别以及使用场景

computed和watch的区别

computed是计算属性

1.支持缓存,只有依赖数据发生改变,才会重新进行计算

2.不支持异步,当computed内有异步操作时无效,无法监听数据的变化

3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过的数据通过计算得到的

4.如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

watch是侦听属性

1.不支持缓存,数据变,直接会触发相应的操作;

2.watch支持异步;

3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;

4.当一个属性发生变化时,需要执行对应的操作;一对多;

使用场景

computed     
    当一个属性受多个属性影响的时候就需要用到computed
    最典型的例子: 购物车商品结算的时候
watch
    当一条数据影响多条数据的时候就需要用watch
    搜索数据

5.微任务和宏任务 还有Event-Loop 是什么

概念

1 宏任务:当前调用栈中执行的代码成为宏任务。(主代码快,定时器等等)
2.微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)

区别:

宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。

运行机制

  1. 在执行栈中执行一个宏任务。

  2. 执行过程中遇到微任务,将微任务添加到微任务队列中。

  3. 当前宏任务执行完毕,立即执行微任务队列中的任务。

  4. 当前微任务队列中的任务执行完毕,检查渲染,GUI线程接管渲染。

  5. 渲染完毕后,js线程接管,开启下一次事件循环,执行下一次宏任务(事件队列中取)

微任务:process.nextTick、MutationObserver、Promise.then catch finally

宏任务:I/O、setTimeout、setInterval、setImmediate、requestAnimationFrame

Event Loop是一个程序结构,用于等待和发送消息和事件

简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。

axios的封装记录(axios请求错误处理比如404页面)

request.js

<script>
//拦截前后  进行封装request/axios请求
import axios from 'axios'

//axios.defaults.withCredentials = true; // 允许携带cookie


//创建单例
const instance = axios.create({
	baseURL: 'http://kumanxuan1.f3322.net:8001',
	timeout:5000, //同意设置请求超时时间
})

// //请求拦截
// instance.interceptor.request.use(config=>{
// 	return config;
// }, err=>{
// 	returnPromise.reject(error);
// })
// //响应拦截
// instance.interceptor.request.use(res=>{
// 	return res;
// }, err=>{
// 	return Promise.reject(error);
// })


//请求拦截
//请求前拦截
instance.interceptors.request.use(config => {
	console.log(config);
	
	//config.params.token = 1 //每个api请求都带token 做身份验证
	// config可以携带token
	let token = localStorage.getItem('token');
	if(token){
		//如果config.params是undefined  保证它config.params是一个对象
		
		config.params = config.params || {};
		//请求头带token
		config.headers['X-Nideshop-Token'] = token;
	}
	return config;
}, error=> {
	return Promise.reject(error);
});

//响应拦截
//返回结果后的拦截
instance.interceptors.response.use(result => {
	console.log(result);
	return result.data;  //返回结果优化 不用写两层data
}, error=> {
	处理401 404 500那些的
	if(error.response){
		console.log('请求错误')
		console.log(error.response.status)
		switch(error.response.status){
			case 401: 
			console.log('401');
			break;
			case:404:
			router.push('Error/Error404');//跳转404页面
			break;
			case 500:
			router.push('/Error/Error500')
		}
	}
	return Promise.reject(error);
});

export default instance;
</script>

在这里插入图片描述
在这里插入图片描述

//记录学习 下次试试
<script>
// options中包含着数据
export function axiosPackage(options) {
    
  return new Promise((resolve, reject) => {
      
      let httpDefaultOpts = { //http默认配置
          method:options.method,
          url:options.url,
          timeout: 600000,
          params:Object.assign(options.params),
          data:Qs.stringify(options.params),
          headers: options.method=='get'?{
              'X-Requested-With': 'XMLHttpRequest',
              "Accept": "application/json",
              "Content-Type": "application/json; charset=UTF-8",
              // "Authorization": token
          }:{
              'X-Requested-With': 'XMLHttpRequest',
              'Content-Type': options.ContentType || 'application/x-www-form-urlencoded; charset=UTF-8', // 由于部分post请求使用的Content-Type是application/json
              "Accept": "application/json",
          }
      }
      if(options.ContentType == 'application/json'){
        httpDefaultOpts.data = JSON.stringify(Object.assign(options.params))
      }
      if(options.method=='get'){ //判断是get请求还是post请求
          delete httpDefaultOpts.data
      }else{
          delete httpDefaultOpts.params
      }
      instance(httpDefaultOpts)
          .then(response => {//then 请求成功之后进行什么操作
              if(response.data.code == 200){ // 服务端返回code200为成功,其他为错误提示
               resolve(response.data)//把请求到的数据发到引用请求的地方
              }else{
                reject(response)
              }
          })
          .catch(error => {
              if (error && error.response) {   
                switch (error.response.status) {
                case 400: error.message = '请求错误(400)' ; break;
                case 401: error.message = "未授权,请重新登录(401)"; break;
                case 403: error.message = "拒绝访问(403)"; break;
                case 404: error.message = "请求出错(404)"; break;
                case 408: error.message = "请求超时(408)"; break;
                case 500: error.message = "服务器错误(500)"; break;
                case 501: error.message = "服务未实现(501)"; break;
                case 502: error.message = "网络错误(502)"; break;
                case 503: error.message = "服务不可用(503)"; break;
                case 504: error.message = "网络超时(504)"; break;
                case 505: error.message = "HTTP版本不受支持(505)"; break;
                default: error.message = `连接出错(${error.response.status})!`;
                }
                reject(error)             } 
          })

  })
}
</script>

1.src 和href的区别

1.请求资源类型不同
(1) href是Hypertext Reference的缩写,表示超文本引用。用来建立当前元素和文档之间的链接。常用的有:link、a。
(2)在请求 src
资源时会将其指向的资源下载并应用到文档中,常用的有script、img 、iframe;
2.作用结果不同
(1)href 用于在当前文档和引用资源之间确立联系; (2)src 用于替换当前内容;

3.浏览器解析方式不同

(1)若在文档中添加href ,浏览器会识别该文档为 CSS 文件,就会并行下载资源并且不会停止对当前文档的处理。
(2)当浏览器解析到src,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等也如此,类似于将所指向资源应用到当前内容。这也是为什么建议把
js 脚本放在底部而不是头部的原因。

2.前端存储的方式有哪些 有什么区别
1.cookies
2.localstorage
3.sessionstorage
4.Web SQL
5.IndexedDb

区别:

1.cookies:在html5标准前本地储存的主要方式,优点是兼容性好,请求自带cookie,缺点是大小只有4k,自动请求头加入cookie浪费流量,每个domain限制20个cookie,使用起来麻烦需要自行封装。

2.localStorage:HTML5加入的以键值对(key-value)为标准的方式,优点是操作方便,永久性储存(除非手动删除)大小为5M,兼容IE8+
3.sessionStorage:与localStorage基本类似,区别是sessionStorage当前页面关闭后会被清理,而且cookie、localStorage不同,它不能在所有同源窗口中共享,是会话级别的储存方式。

4 Web SQL:2010年被W3C废弃的本地数据存储方案,但是主流浏览器(火狐除外)都已经有了相关实现websql类似于SQLite,是真正意义上的关系型数据库,用sql进行数据操作,当我们用Java Script时要进行转换,较为繁琐。

5.IndexedDB:是被证实纳入HTML5标准的数据存储方案,它是NoSQL数据库,用键值对进行储存,可以进行快速读取,非常适合web场景,同时用javascript进行操作会非常方便。

3.CSS选择器的优先顺序

id选择器(#id)-类选择器(.class)-标签选择器§-子代选择器(ul < li) - 后代选择器(li a)
伪类选择器(nth-child)

4.js数据类型

null Number undefined string symbol(es6) object Boolean

5.js跳出循环的方式

1.break 2.return 3.continue

6.清除浮动的方法
方式一:使用overflow属性来清除浮动

.parent{
    overflow:hidden;
}

方式二:使用额外标签法

.clear{
    clear:both;
}

方法三:使用伪元素来清除浮动(after意思:后来,以后)

.clearfix:after{
    centent:"";//设置内容为空
    height:0;//高度为0
    line-height:0;//行高为0
    display:block;//将文本转为块级元素
    visibility:hidden;//将元素隐藏
    clear:both//清除浮动
}
.clearfix{
    zoom:1;为了兼容IE
}``

方法四:使用双伪元素清除浮动

.clearfix:before,.clearfix:after {
	content: "";    
 	display: block;     
 	clear: both; 
 }

7.如何将一个div垂直水平居中

display:flex;
align-items:center;
justify-content:center;

<html>
<div class="parent">
	<div class="child">
	</div>
</div>

<style>
.parent{
	position:relative;
}
.child{
	position:absolute; //第一种方法
	top:50%;
	left:50%;
	margin-top:-50px;
	margin-left:-50px;
}
.child2{
	position:absolute; //第二种方法
	margin: auto;
	top:0;
	bottom:0;
	left: 0;
	right: 0;
}

</style>
</html>

8.浏览器向服务器发送请求的常见方式有几种

1.表单form的提交
2.超链接 <a href="url"></a>
3.document.location/document.location.href
4.window.location/window.location.href
5.window.open(‘url’)
6.直接在浏览器输入url,然后回车

9.一道作用域的题目

var a=123;
function fun(){
    alert(a)//原因变量提升
     //加这个var a = 456 的时候 alert(a)显示undefined 
	 var a = 456 //没有加这个的时候 alert(a)显示123
}
fun()

10.数组去重的代码
1.双层for循环

<script>
function unique(arr){            
   for(var i=0; i<arr.length; i++){
       for(var j=i+1; j<arr.length; j++){
           if(arr[i]==arr[j]){         //第一个等同于第二个,splice方法删除第二个
               arr.splice(j,1);
               j--;
           }
       }
   }
	return arr;
}
</script>

2.利用indexOf去重

<script>
function unique(arr){
	var array = []
	for(var i=0; i<arr.length;i++){
		if(array.indexOf(arr[i]) === -1){
			array.push(arr[i])
		}
	}
	return array;
}

var arr =[1,2,3,4,5,5,7,8,6,4,5,1,2,3]
console.log(unique(arr))
</script>

3.利用sort()

<script>
function unique2(arr) {
				
	arr = arr.sort() //排序
	console.log(arr)
	var arrry= [arr[0]];
	console.log(arrry)
	for (var i = 1; i < arr.length; i++) {
	   if (arr[i] !== arr[i-1]) {
	       arrry.push(arr[i]);
	   }
	}
	return arrry;
}
</script>

11.从浏览器地址栏输入URL到显示页面的步骤

  1. 浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
  2. 服务器交给后台处理完成后返回数据,浏览器接收文件(html,js,css,图像等);
  3. 浏览器对加载到的资源(html,js,css等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
  4. 载入解析到的资源文件,渲染页面,完成。

12.关于foo的一道面试题

function foo(){// 第16行
    getName = function(){console.log(1)}
    return this
}
foo.getName = function(){
    console.log(2)
}
foo.prototype.getName = function(){
    console.log(3)
}
var getName = function(){
    console.log(4)
}
function getName(){
    console.log(5)
}

foo.getName()//2
getName()//4
foo().getName()//1
getName()//1
new foo.getName()//2
new foo().getName()//3
new new foo().getName()//3

接下来对以上的代码进行分析:我先将每块函数进行编号

// 方式1:一个构造函数嘛,里面有个全部变量getName 指向一个匿名函数(小心闭包)
      function foo() {
		getName = function () { 
			console.log (1); 
		};
	    return this;
	}
// 方式2:构造函数的一个属性getName 指向一个匿名函数
       foo.getName = function () { 
		console.log (2); 
	};
// 方式3:构造函数的原型上有个getName方法
       foo.prototype.getName = function () { 
		console.log(3);
	};
// 方式4:定义一个变量指针指向一个匿名函数
       var getName = function () { 
		console.log (4);
	};
// 方式5:声明一个叫getName的有名函数
        function getName() { 
		console.log (5);
	}

1.Foo.getName(): 这句就没什么要说的了,就是直接调用方式二的函数代码块,所以它的结果为2

2.getName() :如果单独看这条执行语句,一般我们会直接看到有个全局函数声明,就是方式5—function getName(){},此时我们可能很开心屁颠屁颠的就认为是5了,但是冷静分析下来,在这么复杂的作用域下,我们发现了方式4–var getName = function(){}来捣乱了,当定义的变量和声明的函数重名了怎么办? 答:它们都会进行预解析,函数声明提前于变量声明!但是函数声明最终会被变量声明给覆盖了。 所以这里我们

以上是关于一些面试题的记录的主要内容,如果未能解决你的问题,请参考以下文章

有趣的css面试题

BAT面试的准备—iOS篇

刷题的网站

关于一道JS面试题的思考

剑指Offer(第二版)面试题目分析与实现-解决面试题的思路

面试常用的代码片段