1.null和undefined区别
定义:
undefined:是所有没有赋值变量的默认值,是基本数据类型,表示未定义,缺少的意思,
是一个表示‘无’的原始值,转为数值为NAN
undefined表示缺少值,就是此处应该有一个值,但是还没有定位,典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
var i;
i // undefined
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
function f(x){console.log(x)}
f() // undefined
(3)对象没有赋值的属性,该属性的值为undefined。
var o = new Object();
o.p // undefined
(4)函数没有返回值时,默认返回undefined。
var x = f();
x // undefined
null:主动释放一个变量引用的对象,表示一个变量不再指向任何对象地址,是对象,表示空对象,是一个表示‘无’的对象,转为数值时是0
null表示没有对象,即该处不应该有值,典型用法师:
(1)作为函数的参数,表示该函数的参数不是对象
(2)作为对象原型链的终点
Object.getPrototypeOf(Object.prototype)
// null
何时使用null?
当使用完一个比较大的对象时,需要对其进行释放内存,设置为null
null和undefined异同点?
共同点:
都是原始类型,保存在栈中变量本地
不同点:
(1)undefined——表示变量声明过但并未赋过值。
它是所有未赋值变量默认值。
例如:var a; //a自动被赋值为undefined
(2)null——表示一个变量将来可能指向一个对象。
一般用于主动释放指向对象的引用。
例如:var emps = [‘ss’,‘nn’];
emps = null; //释放指向数组的引用
4、延伸——垃圾回收站
它是专门释放对象内存的一个程序。
(1)在底层,后台伴随当前程序同时运行;引擎会定时自动调用垃圾回收期;
(2)总有一个对象不再被任何变量引用时,才释放。
2.关于数据类型
基本类型:
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)
对象(Object)、数组(Array)、函数(Function)。
3.判断js中数据类型方法
判断js中的数据类型有一下几种方法:typeof、instanceof、 constructor、 prototype、 $.type()/jquery.type(),接下来主要比较一下这几种方法的异同
先举几个例子:
1.使用typeof
var bool = true
var num = 1
var str = 'abc'
var und = undefined
var nul = null
var arr = [1,2,3]
var obj = {name:'haoxl',age:18}
var fun = function(){console.log('I am a function')}
1.使用typeof
console.log(typeof bool); //boolean
console.log(typeof num);//number
console.log(typeof str);//string
console.log(typeof und);//undefined
console.log(typeof nul);//object
console.log(typeof arr);//object
console.log(typeof obj);//object
console.log(typeof fun);//function
由结果可知typeof可以测试出number、string、boolean、undefined及function,而对于null及数组、对象,typeof均检测出为object,不能进一步判断它们的类型。
2.使用instanceof
console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(arr instanceof Array);// true
console.log(nul instanceof Object);// false
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true
var bool2 = new Boolean()
console.log(bool2 instanceof Boolean);// true
var num2 = new Number()
console.log(num2 instanceof Number);// true
var str2 = new String()
console.log(str2 instanceof String);// true
function Person(){}
var per = new Person()
console.log(per instanceof Person);// true
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(haoxl instanceof Student);// true
console.log(haoxl instanceof Person);// true
从结果中看出instanceof不能区别undefined和null,而且对于基本类型如果不是用new声明的则也测试不出来,对于是使用new声明的类型,它还可以检测出多层继承关系。
3.使用constructor
undefined和null没有contructor属性
console.log(bool.constructor === Boolean);// true
console.log(num.constructor === Number);// true
console.log(str.constructor === String);// true
console.log(arr.constructor === Array);// true
console.log(obj.constructor === Object);// true
console.log(fun.constructor === Function);// true
console.log(haoxl.constructor === Student);// false
console.log(haoxl.constructor === Person);// true
constructor不能判断undefined和null,并且使用它是不安全的,因为contructor的指向是可以改变的
4.使用Object.prototype.toString.call
console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(Object.prototype.toString.call(haoxl));//[object Object]
在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。
但是它不能检测非原生构造函数的构造函数名。
5.使用jquery中的$.type
console.log($.type(bool));//boolean
console.log($.type(num));//number
console.log($.type(str));//string
console.log($.type(und));//undefined
console.log($.type(nul));//null
console.log($.type(arr));//array
console.log($.type(obj));//object
console.log($.type(fun));//function
function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log($.type(haoxl));//object
$.type()内部原理就是用的Object.prototype.toString.call()
通常情况下用typeof 判断就可以了,遇到预知Object类型的情况可以选用instanceof或constructor方法,实在没辙就使用$.type()方法。
前端bug排查工具有哪些
1.DebugMe
DebugMe可以可视化地跟踪Bug,并可以将代码嵌入到网站的元标记中,来解决跟踪的问题。客户端还可以在网站内保存通过任何类型的Web浏览器访问该网站的评价。
2.zipBoard
zipBoard是一个简单的Bug跟踪工具,它可以轻松地在不同类型的网页设计中识别出每个Bug。它也可以在不需要电子邮件协作的情况下处理大型、复杂的网站开发项目。
3.TrackDuck
TrackDuck是一个用户友好的Bug跟踪工具,它允许客户在网站上留下他们的反馈信息。它具有自动捕获动态屏幕分辨率和跨任何类型浏览器并同时执行可视化Bug跟踪的能力。TrackDuck使你能够根据具体为管理员、贡献者和报告者授予的权限级别进行Bug测试。它还为调试网站的开发人员提供了单独的链接和文档。
4.Usersnap
Usersnap是一个从大程度上集成了诸如JIRA、Trello、Slack、Intercom和Zendesk等项目管理工具的Bug跟踪工具。它为Web开发人员提供了一个挂载在云端的小部件,通过该部件可以在页面上方留下注释。Usersnap允许Java脚本响应,这使得它成为了一个可以从客户端接收Bug报告的强大的工具。
5.BugHerd
BugHerd工具栏从直观上看起来像是设计成了一个看板,可以在上面登记各种问题,可以指定优先级,附上屏幕截图。Web开发人员可以通过在BugHerd工具栏中输入网站URL来直接识别Bug。它非常容易使用,还提供了所有用于解决“临床”Bug的技术文档。
var let const区别,作用域
var声明变量可以重复声明,而let不可以重复声明
var是不受限于块级的,而let是受限于块级
var会与window相映射(会挂一个属性),而let不与window相映射
var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错
const声明之后必须赋值,否则会报错
const定义不可变的量,改变了就会报错
const和let一样不会与window相映射、支持块级作用域、在声明的上面访问变量会报错
深浅拷贝
关于http
关于响应式布局
响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套,手机端再开发一套,而使用响应式布局只要开发一套就够,缺点就是CSS比较重。下面是博客网站对不同设备适配后的结果,分别是iPhone5/SE,iphone6/7/8,iphone 6/7/8 plus,ipad pro,dell台式宽屏(1440 X 900)。
响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。
- 媒体查询
CSS3媒体查询可以让我们针对不同的媒体类型定义不同的样式,当重置浏览器窗口大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。
如何选择屏幕大小分割点
如何确定媒体查询的分割点也是一个开发中会遇到的问题,
选择600px,900px,1200px,1800px作为分割点、480px,800px,1400px,1400px
上面的分割方案不一定满足项目中的实际需求,我们可以先用跨度大的分割点进行分割,如果出现不适配的情况可以再根据实际情况增加新的分割点。
移动优先 OR PC优先
不管是移动优先还是PC优先,都是依据当随着屏幕宽度增大或减小的时候,后面的样式会覆盖前面的样式。因此,移动端优先首先使用的是min-width,PC端优先使用的max-width。
2.百分比布局
通过百分比单位,可以使得浏览器中组件的宽和高随着浏览器的高度的变化而变化,从而实现响应式的效果。Bootstrap里面的栅格系统就是利用百分比来定义元素的宽高,CSS3支持最大最小高,可以将百分比和max(min)一起结合使用来定义元素在不同设备下的宽高。
子元素的height或width中使用百分比,是相对于子元素的直接父元素,width相对于父元素的width,height相对于父元素的height;子元素的top和bottom如果设置百分比,则相对于直接非static定位(默认定位)的父元素的高度,同样子元素的left和right如果设置百分比,则相对于直接非static定位(默认定位的)父元素的宽度;子元素的padding如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的width,而与父元素的height无关。跟padding一样,margin也是如此,子元素的margin如果设置成百分比,不论是垂直方向还是水平方向,都相对于直接父元素的width;border-radius不一样,如果设置border-radius为百分比,则是相对于自身的宽度,除了border-radius外,还有比如translate、background-size等都是相对于自身的;
从上述对于百分比单位的介绍我们很容易看出如果全部使用百分比单位来实现响应式的布局,有明显的以下两个缺点:
计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。
各个属性中如果使用百分比,相对父元素的属性并不是唯一的。比如width和height相对于父元素的width和height,而margin、padding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,造成我们使用百分比单位容易使布局问题变得复杂。
3.rem布局
REM是CSS3新增的单位,并且移动端的支持度很高,Android2.x+,ios5+都支持。rem单位都是相对于根元素html的font-size来决定大小的,根元素的font-size相当于提供了一个基准,当页面的size发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。 因此,如果通过rem来实现响应式的布局,只需要根据视图容器的大小,动态的改变font-size即可(而em是相对于父元素的)。
rem响应式的布局思想:
一般不要给元素设置具体的宽度,但是对于一些小图标可以设定具体宽度值
高度值可以设置固定值,设计稿有多大,我们就严格有多大
所有设置的固定值都用rem做单位(首先在HTML总设置一个基准值:px和rem的对应比例,然后在效果图上获取px值,布局的时候转化为rem值)
js获取真实屏幕的宽度,让其除以设计稿的宽度,算出比例,把之前的基准值按照比例进行重新的设定,这样项目就可以在移动端自适应了
rem布局的缺点:
在响应式布局中,必须通过js来动态控制根元素font-size的大小,也就是说css样式和js代码有一定的耦合性,且必须将改变font-size的代码放在css样式之前
/上述代码中将视图容器分为10份,font-size用十分之一的宽度来表示,最后在header标签中执行这段代码,就可以动态定义font-size的大小,从而1rem在不同的视觉容器中表示不同的大小,用rem固定单位可以实现不同容器内布局的自适应。/
REM布局也是目前多屏幕适配的最佳方式。默认情况下我们html标签的font-size为16px,我们利用媒体查询,设置在不同设备下的字体大小。
4.视口单位
css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度,除了vw和vh外,还有vmin和vmax两个相关的单位。各个单位具体的含义如下:
vw 相对于视窗的宽度,1vw 等于视口宽度的1%,即视窗宽度是100vw
vh 相对于视窗的高度,1vh 等于视口高度的1%,即视窗高度是100vh
vmin vw和vh中的较小值
vmax vw和vh中的较大值
用视口单位度量,视口宽度为100vw,高度为100vh(左侧为竖屏情况,右侧为横屏情况)。例如,在桌面端浏览器视口尺寸为650px,那么 1vw = 650 * 1% = 6.5px(这是理论推算的出,如果浏览器不支持0.5px,那么实际渲染结果可能是7px)。
使用视口单位来实现响应式有两种做法:
1.仅使用vw作为CSS单位
2.搭配vw和rem
5.图片响应式
这里的图片响应式包括两个方面,一个就是大小自适应,这样能够保证图片在不同的屏幕分辨率下出现压缩、拉伸的情况;一个就是根据不同的屏幕分辨率和设备像素比来尽可能选择高分辨率的图片,也就是当在小屏幕上不需要高清图或大图,这样我们用小图代替,就可以减少网络带宽了。
1.使用max-width(图片自适应):
图片自适应意思就是图片能随着容器的大小进行缩放
2.使用srcset
3.使用background-image
4.使用picture标签
总结:
响应式布局的实现可以通过媒体查询+px,媒体查询+百分比,媒体查询+rem+js,vm/vh,vm/vh +rem这几种方式来实现。但每一种方式都是有缺点的,媒体查询需要选取主流设备宽度尺寸作为断点针对性写额外的样式进行适配,但这样做会比较麻烦,只能在选取的几个主流设备尺寸下呈现完美适配,另外用户体验也不友好,布局在响应断点范围内的分辨率下维持不变,而在响应断点切换的瞬间,布局带来断层式的切换变化,如同卡带的唱机般“咔咔咔”地一下又一下。通过百分比来适配首先是计算麻烦,第二各个属性中如果使用百分比,其相对的元素的属性并不是唯一的,这样就造成我们使用百分比单位容易使布局问题变得复杂。通过采用rem单位的动态计算的弹性布局,则是需要在头部内嵌一段脚本来进行监听分辨率的变化来动态改变根元素字体大小,使得CSS与JS 耦合了在一起。通过利用纯css视口单位实现适配的页面,是既能解决响应式断层问题,又能解决脚本依赖的问题的,但是兼容性还没有完全能结构接受。
响应式布局的成型方案
现在的css,UI框架等都已经考虑到了适配不同屏幕分辨率的问题,实际项目中我们可以直接使用这些新特性和框架来实现响应式布局。可以有以下选择方案:
利用上面的方法自己来实现,比如CSS3 Media Query,rem,vw等
Flex弹性布局,兼容性较差
Grid网格布局,兼容性较差
Columns栅格系统,往往需要依赖某个UI库,如Bootstrap
响应式布局的要点
在实际项目中,我们可能需要综合上面的方案,比如用rem来做字体的适配,用srcset来做图片的响应式,宽度可以用rem,flex,栅格系统等来实现响应式,然后可能还需要利用媒体查询来作为响应式布局的基础,因此综合上面的实现方案,项目中实现响应式布局需要注意下面几点:
设置viewport
媒体查询
字体的适配(字体单位)
百分比布局
图片的适配(图片的响应式)
结合flex,grid,BFC,栅格系统等已经成型的方案
高度自适应
关于定位
关于浮动
清除浮动的几种方式,各自的优缺点
1.使用空标签清除浮动clear:both。
原理:添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
优点:通俗易懂,容易掌握
缺点:会添加很多无意义的空标签,有违结构与表现的分离,在后期维护中将是噩梦
2.父级div定义overflow:hidden
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
优点:简单,代码少,浏览器支持好
缺点:不能和position配合使用,因为超出的尺寸的会被隐藏
3、父级div定义伪类:after和zoom(用于非IE浏览器)
原理:IE8以上和非IE浏览器才支持:after,原理和方法1有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题
优点:浏览器支持好,不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等)。
缺点:代码多,要两句代码结合使用,才能让主流浏览器都支持
4、父级div定义height
原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题。
优点:简单,代码少,容易掌握
缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题
5、父级div定义overflow:auto
原理:必须定义width或zoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度
优点:简单,代码少,浏览器支持好
缺点:内部宽高超过父级div时,会出现滚动条。
H5-1906-汪海波(363178598) 15:12:42
同源策略简单来说,就是一段脚本只能读取来自同一来源的窗口和文档的属性,这里同一来源指的是协议、域名和端口号的组合。
div居中的实现方式
https://www.cnblogs.com/zhangwenjiajessy/p/6130658.html
https://www.cnblogs.com/Julia-Yuan/p/6648816.html
margin 或者 定位 或者 弹性盒模型 来进行居中
1.知道宽高,margin+绝对定位
div{
width: 200px;
height: 200px;
background: green;
position:absolute;
left:0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
}
2.已知宽高,定位水平垂直居中【margin 负间距】
div{
width:200px;
height: 200px;
background:green;
position: absolute;
left:50%;
top:50%;
margin-left:-100px;
margin-top:-100px;
}
不需要知道宽高,
1.div绝对定位水平垂直居中【Transforms 变形】
绝对定位,定位的是左上角为原点
当使用:top: 50%;left: 50%;, 是以左上角为原点,故不处于中心位置
translate(-50%,-50%) 作用是,往上(x轴),左(y轴)移动自身长宽的 50%,以使其居于中心位置
div{
width: 200px;
height: 200px;
background: green;
position:absolute;
left:50%; /* 定位父级的50% */
top:50%;
transform: translate(-50%,-50%); /*自己的50% */
}
2.弹性盒子
.box{
height:600px;
display:flex;
justify-content:center;
align-items:center;
/* aa只要三句话就可以实现不定宽高水平垂直居中。 */
}
.box>div{
background: green;
width: 200px;
height: 200px;
}
3.display:table-cell
组合使用display:table-cell和vertical-align、text-align,使父元素内的所有行内元素水平垂直居中(内部div设置display:inline-block即可)。
这在子元素不确定宽高和数量时,特别实用!
关于适配各个浏览器
关于本地存储
cookie与本地存储、会话存储的区别
1. cookie特点: 小(~4k),会随着http发给服务器,浪费宽带,以文本形式存储在客户端,每次请求都会带上cookie,过期时间,完全兼容,用来和服务器端通信,时效:会话级,可以改
Cookie的优势是全系列浏览器全部支持,而且可以不传递参数的情况下与后台进行数据交互,最典型的例子就是自动登录。兼容性好
不能跨域
数量限制 每一个域名下最多建20个
用户可以清除cookie 客户端还可以禁用cookie
优点:1、访问比较方便 可通过request、cookie、header 中获取
2、可以设置path
3、可以设置secure属性 只能在https访问 防止XSS
4、可以说httponly属性 服务端可以设置 js无法设置
保存在浏览器端
保存时间
设置过期时间,浏览器关闭后不会清除,保存在硬盘中, 过期时间到期后失效
不设置过期时间, 保存在内存中, 浏览器关闭后消失
应用场景:
记住密码,下次自动登录
单个cookie大小不能超过4kb
安全性较低, cookie截获, cookie欺骗
购物车功能
记录用户浏览数据,进行商品广告推荐
判断用户是否登陆过网站, 以便下次登录时能够实现自动登录(或者记住密码)。如果我们删除cookie,则每次登录必须从新填写登录的相关信息。
保持上次登录的时间等信息
保存上次登录查看的页面
浏览计数
缺点
大小受限
用户可以禁用cookie, 使功能受限
安全性较低
有些状态不能保存在客户端
每次访问都要传送cookie给服务器,浪费带宽。
cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下。
2. localStorage特点: 大(~5M),不会发往服务器,没有过期时间,浏览器的本地存储,时效:永久,不能改,window身上的子对象
使用场景:
localStorage可以用来统计页面访问次数
长期登录+判断用户是否登录, 长期存储在本地的数据
做一些需要本地缓存的东西
比如一些网站提供的编辑器,自带草稿功能,每隔几秒钟或几分钟自动保存当前编辑的内容,刷新页面,或是把浏览器关掉重新打开编辑页面可以自动恢复之前编辑的内容的。
这种信息就适合存放在 localStorage 中
localStorage 是以字符串的形式来存储的
//存:转为字符串
let obj = {"name":"Lee","age":"20"}
localStorage.setItem("user",JSON.stringify(obj));
//取:转换成对象
let user = JSON.parse(localStorage.getItem("user"))
//清空:
localStorage.setItem("user","");
//删除:
localStorage.remove("user");
localStorage 储存的数字类型会自动转为字符串类型
//声明数字类型
let index = 1;
console.log(typeof index); // number
//直接储存
localStorage.setItem('currentPage', index);
//获取的是字符串类型
let getIndex = localStorage.getItem('currentPage');
console.log(getIndex); // 1
console.log(typeof getIndex); // string
3. sessionStorage特点: 大(~5M),不会发往服务器,时效:会话级,只有会话级,不能改,关闭浏览器自动清除缓存
使用场景:
sessionStorage: 敏感的一次性登录
sessionStorage可以用来统计当前页面元素的点击次数。
优点
储存空间大
节省网络流量
可在本地直接获取
不需要与服务器进行交互
获取速度块
安全性较高
共同点:不安全、不能跨域、不能跨浏览器,写入的都是字符
localStorage与sessionStroage区别
(1)localStroage是将信息存储在硬件设备中的,关闭浏览器或网页也不会消失;
(2)sessionStroage的有效期只是网页在浏览器打开到关闭的时间段
隐私模式下可以采用window.name模拟sessionStorage的方式处理,因为window.name是可做保存的,这个也是其解决跨域方案的原因。
区别:
1.cookie会随着http发给服务器,在浏览器和服务器进行通信,来回传递数据,浪费宽带,localstroage和sessionstroage不会自动把数据发给浏览器,是保存在本地
2.cookie可以设置过期日期,sessionstroage是会话级别的数据,窗口关闭清除,localstroage是永久性的数据,除非手动清除
3.cookie的存储大小不超过4k,localstroage和sessionstroage的存储大小都是不超过5m,提高了存储的体积
4.session不跨窗口,在另外一个窗口打开sessionstroage就不存在了,只在当前窗口有效,cookie和localstroage都是跨窗口的
关于移动端适配
关于闭包
闭包是什么,为什么会造成内存泄露
闭包函数:有权访问另一个函数作用域中的变量的函数,
创建闭包:就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量
内存泄露:是指用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来
特性:函数嵌套函数。函数内部可以引用外部,也就是父函数的参数和变量。参数变量不会被垃圾回收机制回收。
好处:希望一个变量长期存储在内存中。避免全局变量的污染。私有成员的存在。缺点:常驻内存,增加内存使用量。不当会很容易造成内存泄露。
为什么会造成内存泄露?=为什么不会被垃圾回收机制回收
正常来说外层函数内部的变量a,是在调用外层函数时创建,调用完销毁的,但是外层函数内有一个内层函数,也就是闭包函数,调用了外层函数的变量a,所以内存回收会认为a是被引用的,因此在回收的时候不会释放它,所以变量a会一直在内存中,外部却调用不到这个变量,就产生了内存泄露
什么是内存泄露
定义:一块被分配的内存,既不能使用,也不能回收,从而影响性能,导致程序崩溃
起因:js垃圾自动回收机制会按一定的策略找出不再继续使用的变量,释放占有的内存,但是由于一些原因导致在这种机制下内存管理器不能正确解读js变量的生命周期从而没有释放其内存,但也没有再使用
造成内存泄露的解决办法:
常用:在js代码运行完时将形成循环引用的js对象手动设置为空,切断引用
应用闭包场合主要是为了:设计私有的方法和变量。一般函数执行完毕后,局部活动对象就被销毁,内存中仅仅保存全局作用域。但闭包的情况不同!
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();}init();
displayName() 是定义在 init() 里的内部函数,仅在该函数体内可用。displayName() 内没有自己的局部变量,它可以访问到外部函数的变量,所
以 displayName() 可以使用父函数 init() 中声明的变量 name 。
闭包函数
function a(){
var b = 1;
//闭包
(function(){
b = 2;
})();
}
a();
跨域问题
在本地开发请求后端服务器接口的时候,都不可避免的会遇到跨域的问题。解决方法可以通过加一个node中间层或者nginx做反向代理。但是如果是用vue-cli搭建的项目,vue-cli在config中自带了一个proxyTable属性,可以配置这个属性解决跨域的问题
理解跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
出于安全考虑,服务器不允许ajax 跨域获取数据,但是可以跨域获取文件内容,所以基于这一点,可以动态创建script 标签,使用标签的src 属性访问js 文件的形式获取js脚本,并且这个js 脚本中的内容是函数调用,该函数调用的参数是服务器返回的数据,为了获取这里的参数数据,需要事先在页面中定义回调函数,在回调函数中处理服务器返回的数据,这就是解决跨域问题的主流解决方案(jsonp),反向代理
跨域通信的几种方式
JSONP
Hash
postMessage
WebSocket
CORS
Jsonp 反向代理
JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。
JSONP(适用于单项跨域请求)
原理:因为浏览器对script不存在同源策略,所以script可以跨域请求外部资源,返回的数据是json格式。
缺点:1、只能发送get请求,无法发送post请求
2、无法判断请求成功还是失败
反向代理
原理:让代理服务器请求目标地址,因为请求是在服务端进行的,在服务端不存在跨域,从而解决跨域问题
实现:将原地址绑定在代理服务器下,让代理服务器发送请求
这种方式可以解决所有跨域问题,也就是将后台作为代理,每次对其它域的请求转交给本域的后台,本域的后台通过模拟http请求去访问其它域,再将返回的结果返回给前台,这样做的好处是,无论访问的是文档,还是js文件都可以实现跨域
防抖函数与节流函数?
防抖函数:
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
节流函数:
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
关于异步请求
关于前后端交互同步异步
异步请求的几种方式,async & await
async 表示这是一个async函数,await只能用在这个函数里面。await表示在这里等待promise返回结果了,再继续执行。await 后面跟着的应该是一个promise对象(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)
异步函数可以包含await指令,该指令会暂停异步函数的执行,并等待Promise执行,然后继续执行异步函数,并返回结果。
1.async/await场景
这是一个用同步的思维来解决异步问题的方案,当前端接口调用需要等到接口返回值以后渲染页面时。
2.名词解释
async
async的用法,它作为一个关键字放到函数前面,用于表示函数是一个异步函数,因为async就是异步的意思, 异步函数也就意味着该函数的执行不会阻塞后面代码的执行,async 函数返回的是一个promise 对象。
await
await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果
axios和ajax在请求上有什么区别
简单请求和复杂请求
简单请求
满足一下两个条件的请求。
请求方法是以下三种方法之一:
HEAD
GET
POST
HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
复杂请求:
非简单请求就是复杂请求。
复杂请求在正式请求前都会有预检请求,在浏览器中都能看到有OPTIONS请求,用于向服务器请求权限信息的。
axios 都是复杂请求,ajax 可以是简单请求,axios.all处理并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
console.log('两个请求都完成了')
}));
请求数据和请求图片在请求上的一些区别
1、什么是懒加载
将图片src先赋值为一张默认图片,当用户滚动滚动条到可视区域图片的时候,再去加载后续真正的图片
如果用户只对第一张图片感兴趣,那剩余的图片请求就可以节省了
2、为什么要引入懒加载
懒加载(LazyLoad)是前端优化的一种有效方式,极大的提升用户体验。图片一直是页面加载的流浪大户,现在一张图片几兆已经是很正常的事,远远大于代码的大小。倘若一次ajax请求10张图片的地址,一次性把10张图片都加载出来,肯定是不合理的。
3、懒加载实现的原理
先将img标签中的src链接设置为空,将真正的图片链接放在自定义属性(data-src),当js监听到图片元素进入到可视窗口的时候,将自定义属性中的地址存储到src中,达到懒加载的效果。
4、懒加载中涉及的属性
1 、document.documentElement.clientHeight; //表示浏览器可见区域高度:
document.body.clientHeight //是整个页面内容的高度,而非浏览器可见区域的高度
2 、document.documentElement.scrollTop; //滚动条 已滚动的高度:
chrome 中 document.body.scrollTop //滚动条 滚过的高度
那么要得到滚动条的高度:有一个技巧:
var scrollTop=document.body.scrollTop || document.documentElement.scrollTop;
这两个值总会有一个恒为0,所以不用担心会对真正的scrollTop造成影响。一点小技巧,但很实用。
3、 offsetTop、offsetLeft
obj.offsetTop 指 obj 距离上方或上层控件的位置,整型,单位像素。
obj.offsetLeft 指 obj 距离左方或上层控件的位置,整型,单位像素。
obj.offsetWidth 指 obj 控件自身的宽度,整型,单位像素。
obj.offsetHeight 指 obj 控件自身的高度,整型,单位像素。
offsetParent 不同于parentNode ,offsetParent 返回的是在结构层次中与这个元素最近的position为absolute\relative\static的元素或者body
具体滚动时涉及的属性值,请参考https://blog.youkuaiyun.com/zh_rey/article/details/78967174非常详细
JWT中token在前端的所有操作
获取token
$.ajax({
url: "http://localhost:8080",
data: { data: "data" },
type: "POST",
dataType: "json",
async: false,
cache: false,
success: function(data,headers) {
console.log(data);
console.log(headers);//一般是在这里拿,要看后端是煮面封装的
},
error: function(data) {
console.log(data);
}
});
将token存入浏览器cookie
function setTokenToCookie(value) {
var Days = 1; //此 cookie 将被保存 30 天
var exp = new Date();
exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
document.cookie = "my_token =" + escape(value) + ";expires=" + exp.toGMTString();
}
将token从浏览器cookie中取出
function getCookie(name) {
var cookieValue = "啥也没有!!";
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = $.trim(cookies[i]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
发送ajax请求时添加token到请求头
$.ajax({
url: "http://localhost:8080",
data:{data:"data"},
type: "POST",
dataType: "json",
headers: {
Token: my_token //这里是Token
},
async: false,
cache: false,
success: function(data) {
console.log(data);
},
error: function(data) {
console.log(data);
}
});
前端ajax添加token到header的方法
Ajax添加Token到Header中的方法
1.方法一:
$.ajax({
type: "GET",
url: "/access/logout/" + userCode,
headers: {'Authorization': token}
});
2.方法二:
$.ajax({
type: "GET",
url: "/access/logout/" + userCode,
beforeSend: function(request) {
request.setRequestHeader("Authorization", token);
},
success: function(result) {
}
});
3.http request 请求拦截器,有token值则配置上token值
4.https://www.cnblogs.com/zhoubingyan/p/8623509.html
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error)
});
// http request 请求拦截器,有token值则配置上token值
axios.interceptors.request.use(
config => {
if (token) { // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
config.headers.Authorization = token;
}
// sratload();
return config;
},
err => {
return Promise.reject(err);
});
// http response 服务器响应拦截器,这里拦截401错误,并重新跳入登页重新获取token
axios.interceptors.response.use(
response => {
// if (response.status == 200 || response.status == 201){
// endload();
// }
return response;
},
error => {
if (error.response) {
console.log(error.response.status)
if(error.response.status == 401){
alt.error("登陆失效,请重新登录!");
localStorage.removeItem('token');
setTimeout(function () {
location.href = '/index.html';
}, 2000);
}
}
// return Promise.reject(error.response.data)
});
http工作流程
(1)客户与服务器建立连接;
(2)客户向服务器提出请求;
(3)服务器接受请求,并根据请求返回相应的文件作为应答;
(4)客户与服务器关闭连接。
回调函数
箭头函数
闭包