一个初级面试题的分享,感觉干货满满

183 阅读8分钟

由于本人第一次写,看着有些东西会别扭,但是还是干货满满,话不多说直接开始

浏览器的存储方式有哪些呢?

答:localStorage 和sessionStorage以及indexedDB

localStorage和sessionStorage有什么区别

localStorage除非被清理,否则一直存在存储大小为5M ,sessionStorage页面关闭就会销毁存储大小为5M

补充不同浏览器对 HTML5 的本地存储大小基本均有限制,一个测试的结果如下:
IE 9 > 4999995 + 5 = 5000000firefox 22.0 > 5242875 + 5 = 5242880chrome 28.0 > 2621435 + 5 = 2621440safari 5.1 > 2621435 + 5 = 2621440opera 12.15 > 5M (超出则会弹出允许请求更多空间的对话框)

Websocket是什么

   3Websocket是一个全新的、独立的协议,基于TCP协议,与http协议兼容、却不会融入http协议,仅仅作为html5的一部分,其作用就是在服务器和客户端之间建立实时的双向通信。

  • 优点:真正意义上的实时双向通信,性能好,低延迟
  • 缺点:独立与http的协议,因此需要额外的项目改造,使用复杂度高,必须引入成熟的库,无法兼容低版本浏览器

请求回调地狱怎么解决

1、拆解function,吧嵌套在一起的function拆解为单个的fun

 2、设置事件监听,在发生某件事情之后触发那些操作

 3、Promise和async/await 

什么是Promise

要想解释promise是什么,首先我们要对JavaScript有一定的认识:在JS世界内所有代码都是单线程执行的。这就导致其所有网络操作、浏览器事件,都必须是异步执行

    function callBack() {
        console.log('执行完成');
    }
    console.log('执行回调函数前...');
    setTimeout(callBack, 2000);
    console.log('执行回调函数后...');
结果
执行回调函数前...
执行回调函数后...
(2秒钟后)
执行完成

而ajax是经典异步,异步操作是在将来的某个事件执行某件事情,但是这样写代码即不美观重复利用性也不好所以在se6时出现了Promise来高效的实现异步操作  注释:这里对Promise讲解不是很详细。

Promise.all是什么

Promise.all多任务执行

Promise.all = function (promise) {
	let promises = Array.from(promise)//将iterator转换为数组
    return new Promise((resolve, reject) => {
        if (promises.length === 0) {//如果数组长度是0就返回空数组
            resolve([]);
        } else {
            let result = [];//存放已成功的异步操作
            let index = 0;//记录已成功的操作数
            for (let i = 0;  i < promises.length; i++ ) {
                Promise.resolve(promises[i])//执行每一个promise
                	.then(data => {
                    	result[i] = data;
                    	if (++index === promises.length) {
                      
                       	 resolve(result);
                    }
                }, err => {
                    reject(err);
                    return;
                });
            }
        }
    });
}

Promise().then().then()...catch()多任务串行执行

大家可以看这里

如何实现一个ajax

<script>
        function testAjax(){
            var xhr= new XMLHttpRequest();
            xhr.open("get","text.php",true);
            xhr.onreadystatechange=function(){
                if(xhr.readyState==4 && xhr.status==200){
                    var resText = xhr.responseText;
                    document.getElementById("add").innerHTML=resText;
                }
            }
            xhr.send(null);
        }
    </script>

GET和POST有什么区别

这里简单的来说一下

get:请求请求题在url地址栏里客观来说没有体积限制,get只会返回一个tcp包 ,get方式的请求,浏览器会把http header和data一并发送出去 ,是不怎么安全的一种请求方式。

post :而对于POST会把请求体放到body,post会返回两个tcp包,浏览器先发送header,服务器响应,浏览器再发送data,服务器响应200 ok,post相对于get是安全的

在这里会牵扯出怎么设置请求头如果大家有较好的文章还请分享

js为什么是单线程

js作为浏览器脚本语言其主要用途是与用户交互,和DOM操作,这点就决定了js只能是单线程,如果js可以多线程那么在操作DOM的时候有两个操作,删除和添加,那么先执行哪个呢,所以这点就只能决定js是单线程,为了利用计算机cpu的计算能力,HTML5提出WEB Worker标准,允许js可以有多个子线程但这些子线程只能基于父线程,但是父线程只能是单线程

什么是防抖/节流

防抖

顾名思义,防抖就是防止抖动,避免事件的重复触发
应用场景:

  1. 点击按钮事件,用户在一定时间段内的点击事件,为了防止和服务端的多次交互,我们可以采用防抖。
  2. 输入框的自动保存事件

总之,防抖可以概括为触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间那么如何实现呢?

function debounce(fun,obj ){
    let timer;
    return (...args)=>{
    	if (timer){
        	clearTimeout(timer);
        }
        timer = setTimeout(()=>{
        	fun(...args);
        },wait)
    }
}
window.onresize = debounce(()=>{
	console.log(1);
},1000);
//打印一次

节流

减少流量,将频繁触发的事件减少,并每隔一段时间执行  ,控制事件触发的频率

//利用时间间隔实现
function throttle1(fun,wait){
	let time1 = 0;
	return (...args)=>{
   		const time2 = Date.now()
        const timeInterval = time2 - time1;
 		if ( timeInterval < wait){
 			return 
 		}else {
			time1 = time2;
            fun(...args);
		}
    }
}
window.onresize = throttle1(()=>{
	console.log(1);
},1000);
//频繁resize时,控制台每隔1秒打印一次

//定时器实现
function throttle2(fun,wait){
	let timer;
	return (...args)=>{
		if (timer){
			return
		}else {
			timer = setTimeout(()=>{
				timer = null;
				fun(...args);
			},wait);
		}
	}
}
window.onresize = throttle2(()=>{
	console.log(1);
},1000);
//频繁resize时,控制台每隔1秒打印一次

总结

防抖 :触发高频事件后n秒内执行一次函数,如果n内频繁触发那么从新计算

节流:高频事件触发时,在n秒内只会执行一次,稀释函数的执行频率

说了那么多来做一些题吧,一起来看一下 堆栈、闭包和深浅克隆

堆栈

 let a = {}        b = '0'        c = 0        a[b] = 'aaaa'        a[c] = 'bbbbb'        console.log(a[b]);
运行结果为'bbb’你答对了吗
堆:存储的时引用类型的空间
栈:存储基本类型值,和执行代码的环境
栈有顺序,堆没有

为什么会是bbb呢

因为a是引用内存,而引用内存是按照堆来运行的而在底层运行时,a指向的是内存地址aaabbbccc,b和c分别存储为基本类型值,a[b],a[c]相当于在a中创建出a['1']/a[1],对于一个堆或者fun来说属性名不能重复,无论是字符串0还是数字0在这里都代表0,那么数组属性名是索引属性名可以为数字 ,但在对象中编译机制中数字和字符串是相等的,那么这里就可以知道a[1]不是新添加而是更改。

 let a = {}        b = Symbol('1')        c = Symbol('1')        a[b] = 'aaa'        a[c] = 'bbb'        console.log(a[b]);
答案:'aaa'

Symbol()唯一,所以不会更改

拓展问题:如何实现是个symbol

看这里

闭包

  var demo = (function(i) {            return function() {                alert(i * 2)            }        })(2);        demo(5)答案:‘4’  闭包

为什么是字符串4而不是数字4呢因为在alert时会转化为字符串,那么为什么会转化呢,我们alert({})发现输出的时object object

代码执行 i形参赋值 创建一个空间i=2  在往下执行发现 return fun 而fun时引用类型引用指向的时16进制的一个地址,这个地址里面存储这alert(i * 2) 现在return的时存储alert(i * 2) 的16进制地址 由于是自执行函数吧函数执行的结果给demo也就是16进制的地址

创建执行上下文,demo传参由于return  fun ,fun没有形参,执行alert(i*=2)= i=i*2在创建的栈内没有i那么去它的上一级查找并调用,执行完比自动销毁,形成闭包

深浅克隆

克隆我们在哪里用过呢例如 vuex

 let obj = {            a: 100,            b: [10, 20, 30],            c: {                x: 10            },            d: /^\d + $ /        }  

这是一个多维对象,什么是多维对象,二维和二维以上皆为多维对象,什么是浅克隆呢,浅克隆就是 克隆第一层那么我们先来实现浅克隆

        a: 100,            b: [10, 20, 30],            c: {                x: 10            },            d: /^\d + $ /        }        let a = {}        for (let key in obj) {            //   先判断是否唯一            if (!obj.hasOwnProperty(key)) break            a[key] = obj[key]        }


在es6中新增了展开寻运算符
let a = {
   ...obj
}        console.log(a, obj);



为什么obj.c.x改变a.c.x也会改变呢?因为这是个多维对象,而浅克隆它只克隆了第一级并没有克隆下面的,所以下面的改变整个都会改变,那么我们想拿到同样的数据却又不想改变他,该怎么办呢?这里就用到了深克隆

//首先想到的是JSON.stringify()和json.parse
//但是会有一些问题  "{"a":100,"b":[10,20,30],"c":{"x":10},"d":{}}"
//我们发现了正则表达式没有了,那么除了正则还有什么特殊的吗?
//console.log(JSON.stringify({                a: function() {},                x: 10000            }))
//运行结果为{"x":10000}
//为什么要使用json.stringify,json.parse呢因为每次吧字符串转化的过程会新创建一个地址,在工作中使用足以//但是面试不能这样那么要怎么写呢
 function deepClone(obj) {            if (obj === null) return null            if (typeof obj !== "Object") return obj;            if (obj instanceof REGEXP) {                return new RegExp(obj)            }            console.log(obj, oobj);            if (obj instanceof Date) {                return new Date(obj)            }            let newObj = new obj.constructor;            for (let key in obj) {                if (obj.hasOwnProperty(key)) {                    newOBJ[key] = deepClone(obj[key])                }            }            return newObj;        }        let oobj = deepClone(obj)        console.log(obj, oobj);        console.log(obj === oobj);        console.log(obj.c === oobj.c);
结果为:
{a: 100, b: Array(3), c: {…}, d: /^\d + $ /} {a: 100, b: Array(3), c: {…}, d: /^\d + $ /}
demo.html:70 true
demo.html:71 true

第一次在掘金上写文章,希望大佬们勿喷,骚话实在是想不出来,那就祝阅读这篇的读者越来越帅,越来越漂亮,哈哈哈哈哈哈哈~~~~~~~~~~~