由于本人第一次写,看着有些东西会别扭,但是还是干货满满,话不多说直接开始
浏览器的存储方式有哪些呢?
答: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可以有多个子线程但这些子线程只能基于父线程,但是父线程只能是单线程
什么是防抖/节流
防抖
顾名思义,防抖就是防止抖动,避免事件的重复触发
应用场景:
- 点击按钮事件,用户在一定时间段内的点击事件,为了防止和服务端的多次交互,我们可以采用防抖。
- 输入框的自动保存事件
总之,防抖可以概括为触发高频事件后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
第一次在掘金上写文章,希望大佬们勿喷,骚话实在是想不出来,那就祝阅读这篇的读者越来越帅,越来越漂亮,哈哈哈哈哈哈哈~~~~~~~~~~~