解决setTimeout中的this指向问题
在setInterval和setTimeout中传入函数时,函数中的this会指向window对象。
解决办法:
推荐用下面两种写法:
- 将bind换成call,apply也会导致立即执行,延迟效果会失效
window.setTimeout(this.declare.bind(this), 2000);
- 使用es6中的箭头函数,因为在箭头函数中this是固定的.箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域
对象字面量vs构造函数创建对象对比
- 字面量的优势
- 它的代码量更少,更易读;
- 它可以强调对象就是一个简单的可变的散列表,而不必一定派生自某个类
- 对象字面量运行速度更快,因为它们可以在解析的时候被优化,它们不需要"作用域解析(scope resolution)";因为存在我们创建了一个同名的构造函数Object()的可能,当我们调用Object()的时候,解析器需要顺着作用域链从当前作用域开始查找,如果在当前作用域找到了名为Object()的函数就执行,如果没找到,就继续顺着作用域链往上照,直到找到全局Object()构造函数为止
- Object()构造函数可以接收参数,通过这个参数可以把对象实例的创建过程委托给另一个内置构造函数,并返回另外一个对象实例,而这往往不是你想要的。Object()构造函数的这种特性会导致一些意想不到的结果,特别是当参数不确定的时候
Content-Type
互联网媒体类型,在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
- application/x-www-form-urlencoded
HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/“、”,“、“:” 等会自动进行URL转码。不支持文件,一般用于表单提交。
- multipart/form-data
与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。
- application/json
以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(约定好的情况下)。
- application/xml 和 text/xml
与application/json类似,这里用的是xml格式的数据,text/xml的话,将忽略xml数据里的编码格式。
vue-router
两种模式
- hash —— 即地址栏 URL 中的 # 符号:它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
- history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。hash 模式和 history 模式都属于浏览器自身的特性,
钩子函数
- **全局钩子:主要包括
beforeEach
(前置守卫)和aftrEach
(后置钩子),一般用来判断权限,**以及以及页面丢失时候需要执行的操作 - 单个路由里面的钩子:主要用于写某个指定路由跳转时需要执行的逻辑
- 组件路由:主要包括
beforeRouteEnter
和beforeRouteUpdate
,beforeRouteLeave
,这几个钩子是路由导航守卫,都是写在组件里面
vuex的原理
Vuex:可以理解为Vue的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- State:数据仓库。代表数据的唯一来源,一般Vuex所有的数据都会存储在State中。State本身是一种json对象。
- getter:用来获取数据的。
- Mutation:用来修改数据的。通过commit Mutation修改。Mutation里面的操作要同步的方式。
- Action:用来提交Mutation的。可以进行异步操作。
- State由Mutations驱动变化
- 通过Actions与后端交互
- 通过State渲染前端
- 前端触发Actions来提交Mutations
闭包
闭包可以理解为“定义在一个函数内部的函数”,本质上,闭包是将函数内部和外部连接起来的一座桥梁。
父函数内部定义的子函数,如果没有引用父函数作用域中的变量,那么这个子函数不是闭包。也就是说,闭包是由函数和它所在的环境构成的,缺一不可。
闭包会让函数中的变量都被保存在内存中,内存消耗大,所以不能滥用闭包,可以在不使用该变量的时候将其delete
Promise
1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
在JavaScript的世界中,所有代码都是**单线程执行的。**由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现.异步操作会在将来的某个时间点触发一个函数调用.
避免 回调地域问题(嵌套层次深)。
promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了.
- resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
- reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)
promise有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
job1.then(job2).then(job3).catch(handleError);//其中,job1、job2和job3都是Promise对象。
Object.toString和Object.prototype.toString的区别
Object构造函数
本身没有toString
方法。
依照原型链关系,Object构造函数
的上游原型链是Function.prototype
。调用Object.toString.call(param)
本质上是调用Function.prototype.toString.call(param)
,
原型链终端Object.prototype对象上的toString()确实可以被继承下来,可以用来判断数据类型, 但是并不能满足所有的需求,作为子代的包装类和数组就重写了自己的toString(), 因此当我们调用toString()时,会调用自身原型上重写的toString(),重写后的toString()可以把对象转换成字符串,还可以把number类型的数值转换成不同进制的数。当我们需要知道一个变量或值是什么类型的话就可以通/过调用Object.prototype.toString() 来实现 需要用到call().
- Object.toString()是Object构造函数上的方法,返回的是对应的函数
- Object.prototype.toString()是Object原型对象上的方法,返回的是代表该对象的字符串
var obj = {}; Object.toString(obj);//"function Object() { [native code] }" Object.prototype.toString.call(obj);//"[object Object]"
- 为什么Array、String、Number、Boolean等不能直接调用toString()
因为Array、String、Number、Boolean、RegExp、Date等类型都重写了toString(),如果直接调用则因为自身的原型对象上已有toString()方法,就不会调用到Object原型对象上的toString()方法了。
实现弹幕
播放时,设置其translateX
和transform
。
暂停时,把当前的位置写为translateX
,transform
为0,这个时候弹幕就保持在那个位置不动了。
再次播放时,重新设置translateX和transform,当然,transform-duration肯定是依据弹幕长度,当前位置和终点位置(播放器宽度)计算出来的。
播放和暂停的逻辑全都由js处理。
弹幕到位了以后,dom会被移除。
再加上will-change
的GPU加速
B站另外还做了一个操作就是复用dom,弹幕走到头以后不会移除,而是在有下一个新弹幕的时候把原来的dom节点复用,修改style,使其重新播放一次,这个也是性能提高的一个处理办法
https://blog.csdn.net/qq2712193/article/details/51725705
含对象的数组怎么排序
var str=[ {name:"a",age:50}, {name:"b",age:20}, {name:"c",age:40}, {name:"d",age:30}, ]; function compare(key){ return function(value1,value2){ var val1=value1[key]; var val2=value2[key]; return val1-val2; } } str.sort(compare('age')); console.log(str);
请求报文&响应报文
- 请求报文:请求行:请求方法,HTTP协议版本;请求头部:Content-Type;空行;请求体
- 响应报文:状态行:状态码;响应头部;空行;响应体;
引入css方式
- 在test.html引入test.css文件
导入式
@import(url(demo.css))
1.基本不使用,因为页面会先加载html,然后再去加载css,这样就会造成页面样式的延迟。
深拷贝及实现深拷贝的三种方法
- 递归
//使用递归实现深拷贝函数 function deepClone(obj) { var objClone = Array.isArray(obj) ? [] : {} if (obj && typeof obj === 'object') { for (key in obj) { if (obj.hasOwnProperty(key)) { //判断obj的子元素是否为object对象,如果是则就递归拷贝 if (obj[key] && typeof obj[key] === 'object') { objClone[key] = deepClone(obj[key]) } else { //如果不为对象就直接拷贝 objClone[key] = obj[key] }}}} return objClone }
obj1 = JSON.stringify(obj) + JSON.parse(obj1)
- Jquery:
$.extend(true,[],object)
- 第三方函数库 lodsh
数组和链表的区别
链表通过指针来连接元素与元素,数组则是把所有元素按次序依次存储。
链表的插入删除元素相对数组较为简单,不需要移动元素,且较为容易实现长度扩充,但是寻找某个元素较为困难;
数组寻找某个元素较为简单,但插入与删除比较复杂,由于最大长度需要再编程一开始时指定,故当达到最大长度时,扩充长度不如链表方便。
(1) 从逻辑结构角度来看
- 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。
- 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)
(2) 从内存存储角度来看
- (静态)数组从栈中分配空间, 对于程序员方便快速,但自由度小。
- 链表从堆中分配空间, 自由度大但申请管理比较麻烦.
Array.push原理
- 逐个复制元素
- 修改数组长度
function ArrayPush () { var n = TO_UNIT32(this.length); var m = %_ArgumentsLength(); for (var i = 0; i < m; i++) { // 逐个复制元素 this[i + n ] = %_Arguments(i); } this.length = n + m; // 修改数组的length return this.length; }
关系型数据库 & 非关系型数据库区别
- 1.成本:Nosql数据库简单易部署,基本都是开源软件,不需要像使用Oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
- 2.查询速度:Nosql数据库将数据存储于缓存之中,而且不需要经过SQL层的解析,关系型数据库将数据存储在硬盘中,自然查询速度远不及Nosql数据库。
- 3.存储数据的格式:Nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
- 4.扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。Nosql基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
- 5.持久存储:Nosql不使用于持久存储,海量数据的持久存储,还是需要关系型数据库
- 6.数据一致性:非关系型数据库一般强调的是数据最终一致性,不像关系型数据库一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处于一个中间态的数据,Nosql不提供对事务的处理。
数据可脏读、幻读、不可重复读
- 脏读: 读取未提交数据.A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。就好像原本的数据比较干净、纯粹,此时由于B事务更改了它,这个数据变得不再纯粹。这种情况常发生于转账与取款操作中
- 幻读:前后多次读取,数据总量不一致。事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。读取了其他事务新增的数据。
- 不可重复读: 前后多次读取,数据内容不一致。不可重复读是读取了其他事务更改的数据
一个数组很多数,找出/判断两个数相加等于10
public static void findSumNum(int[] a,int sum){ Arrays.sort(a); int i=0,j=a.length-1; while(i<=j){ if(a[i]+a[j]<sum) i++; else if(a[i]+a[j]>sum) j--; else { System.out.println(a[i]+","+a[j]); i++; } } }
数组去重
if (!Array.prototype.unique) { Array.prototype.unique = function () { var hash = {}, result = [], type = '', item; for (var i = 0; i < this.length; i++) { item = this[i]; type = Object.prototype.toString.call(item); if ( !hash[item + type] ) { hash[item + type] = true; result.push(item); } } return result; }; }
后代选择器,子选择器,相邻兄弟选择器
- 后代选择器(包含子选择器,且包含子选择器的子孙选择器):
p em
- 子选择器(父选择器的一级子元素):
h1 > strong
- 相邻兄弟选择器:
h1+p
sessionID
session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识------------称为session id,如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。
保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
SQL:Drop、truncate、delete
- 当你不再需要该表时, 用 drop;
- 当你仍要保留该表,但要删除所有记录时, 用 truncate;
- 当你要删除部分记录时(always with a WHERE clause), 用 delete.
前端 怎么做到一个屏幕分辨率的自适应
https://www.cnblogs.com/HCJJ/p/6408363.html
- em:是一种相对单位,它相对于父元素的字体大小。浏览器默认的字体大小是16px,因此 1em 也就等于 16px。
- rem是一种相对单位,它相对于根元素
html
的字体大小。REM会让页面根据不同的显示设备进行适配缩放,那么必然就会有一个 标准页面尺寸,就目前而言,整个前端开发界使用最多的标准页面尺寸则是根据iphone4或者 iPhone5为依据的640px*1366px
,也有以iphone6为基准的750px。这个标准的页面尺寸,我们可以将其定义为1,如果当前的显示设备尺寸小于标准页面尺寸(640px或者750px)那么便让页面尺寸缩小,使其小于1。而当显示设备尺寸大于标准页面尺寸,我们即可以做一些其它的适配,也可以将页面整个居中显示在显示设备中然后不进行任何缩放操作。实际上rem布局与px布局并没有什么本质的区别,这个我们可以代入实例去理解,比如现在html
的font-size
的大小是100px,即 1rem = 100px,如果现在页面中要放入一个200*200的盒子,那么按照等比关系:
div{ width:2rem; height:2rem; background:gray; }
- REM 实现的页面缩放适配原理, rem 是依据
html
标记的font-size
大小的相对单位,对于使用rem为单位的页面,在被载入到显示设备显示的时候,会根据显示设备的尺寸,然后对应的修改html标签的font-size值,这样便可以一处修改,整个页面内容都会发生改变,即实现根据设备尺寸进行缩放的效果。REM方式进行移动端布局的原理都是相同的,但是不同的在与对于设备尺寸的检测上,就目前而言分为两种,一种是通过CSS meida查询,另一种则是通过JS检测。
- CSS Media
@media screen and (min-width:320px) and (max-width:359px) { html { font-size: 50px; } } @media screen and (min-width:360px) and (max-width:374px) { html { font-size: 56.25px; } } @media screen and (min-width:375px) and (max-width:383px) { html { font-size: 58.59375px; } } @media screen and (min-width:384px) and (max-width:399px) { html { font-size: 60px; } } @media screen and (min-width:400px) and (max-width:413px) { html { font-size: 62.5px; } } @media screen and (min-width:414px) and (max-width:431px) { html { font-size: 64.6875px; } } @media screen and (min-width:432px) and (max-width:479px) { html { font-size: 67.5px; } } @media screen and (min-width:480px) and (max-width:539px) { html { font-size: 75px; } } @media screen and (min-width:540px) and (max-width:639px) { html { font-size: 84.375px; } } @media screen and (min-width:640px) { html { font-size: 100px; } body { max-width: 640px !important; margin: 0px auto !important; } }
- 响应式REM布局的优点在于可以根据设计稿的特点,自定义的对某些设备进行单独适配,而缺点是检测规则固定不可变,这一点相比于“JS自动换算”更为明显。
- JS检测
(function(win,doc){ var timer = null, html = doc.documentElement, baseWidth = html.dataset.basewidth*1 || 640, metaEl = document.querySelector('meta[name="viewport"]'), event = 'onorientationchange' in win ? 'onorientationchange' : 'resize'; if(!metaEl){ metaEl = document.createElement('meta'); metaEl.setAttribute('name','viewport'); metaEl.setAttribute('content','initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0'); html.firstElementChild.appendChild(metaEl); } function layoutCalc(){ var width = html.getBoundingClientRect().width, ratio = width / baseWidth * 100, devicePixelRatio = window.devicePixelRatio, rem = ratio < 100 ? ratio < 50 ? 50 : ratio : 100; if(!/\.\d+/.test(devicePixelRatio.toString())){ html.dataset.dpr = devicePixelRatio; } html.style.fontSize = rem + 'px'; } win.addEventListener(event,function(){ clearTimeout(timer); timer = setTimeout(layoutCalc,300); },false); win.addEventListener('pageShow',function(e){ if(e.persisted){ clearTimeout(timer); timer = setTimeout(layoutCalc,300); } },false); layoutCalc(); }(window,document));
- 自定义基准页面尺寸:通过为 html 标签添加
data-basewidth
属性来自定义指定基准页面的尺寸。
<html data-basewidth="750" > </html>
- 定义页面内容的字体大小:对于一些符合标准的dpr(设备像素比https://blog.csdn.net/a419419/article/details/79295799)值(只要是整数,例如:1,2,3),都会为
html
标签再附加一个data-dpr
属性,然后开发者便可以根据这个属性为条件,实现在不同dpr情况下,对内容字体的大小的调整
html[data-dpr="1"] .dpr-text{ font-size:12px; } html[data-dpr="2"] .dpr-text{ font-size:24px; } html[data-dpr="3"] .dpr-text{ font-size:36px; }
<p class="dpr-text">测试文字</p>
- 相比“响应式方式”JS自动换算无需添加规则,适合于各类型的显示设备。
- vh/vw都是相对于视口的单位,浏览器视口的区域就是通过
window.innerWidth
以及window.innerHeigth
度量得到的范围。浏览器会将整个视口的宽度或者高度划分为100等份,因此1vw或者1wh就是相对视口宽度或者高度的1%。例如浏览器视口的宽度是1920,那么 1920/100 每等份即19.2px。
一行三列排版
contain & cover
- contain: 此时会保持图像的纵横比并将图像缩放成将适合背景定位区域的最大大小。等比例缩放图象到垂直或者水平其中一项填满区域。
- cover: 此时会保持图像的纵横比并将图像缩放成将完全覆盖背景定位区域的最小大小。等比例缩放图象到垂直和水平两项均填满区域。
Vue watch,computed和method区别
- computed:计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意如果你为一个计算属性使用了箭头函数,则this
不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。 - methods: methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的
this
自动绑定为 Vue 实例。注意,不应该使用箭头函数来定义 method 函数 (例如plus: () => this.a++
)。理由是箭头函数绑定了父级作用域的上下文,所以this
将不会按照期望指向 Vue 实例,this.a
将是 undefined。 - watch: 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用
$watch()
,遍历 watch 对象的每一个属性。注意,不应该使用箭头函数来定义 watcher 函数 (例如searchQuery: newValue => this.updateAutocomplete(newValue)
)。理由是箭头函数绑定了父级作用域的上下文,所以this
将不会按照期望指向 Vue 实例,this.updateAutocomplete
将是 undefined。
能使用watch属性的场景基本上都可以使用computed属性,而且computed属性开销小,性能高,因此能使用computed就尽量使用computed属性.当执行异步操作的时候你可能就必须用watch而不是computed了
Vue不能检测到对象属性的添加或删除:三种解决方法
- 方案一:利用Vue.set(object,key,value)
- 方案二:利用this.$set(this.object,key,value)
- 方案三:利用Object.assign({},this.obj)
手写找出数组重复最多的元素
function findNum(a){ var result = [0,0]; for (var i = 0; i < a.length; i++) { for (var j = 0,count = 0; j < a.length; j++) { if (a[i]==a[j]) { ++count; }; }; if(count>result[0]) { result[0] = count; result[1] = a[i]; }else if(count==result[0]&&result[1]<a[i]) { result[1] = a[i]; } } alert("数"+result[1]+"重复了最多次,为"+result[0]); } var arr = [2,2,3,3,3,4,4,4,4,4,4,4,4,43,3]; findNum(arr);
Document.write()与innerHtml()区别
- document.write是直接将内容写入页面的内容流,会导致页面全部重绘
- innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
实现http长连接
- 先创建http请求方法,如图
- 然后设置请求地址
- 在然后需要设置下请求参数的编码格式一般设置成utf8
- 然后就开始设置长连接了,这个主要是再header中设置Connection=keep-alive
- 如果需要设置长连接的有效时间就在添加Keep-Alive:timeout=60
- 完成长连接的header设置后就开始设置请求参数了
- 最后就是执行者http的长连接请求了
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
https://www.cnblogs.com/blogtech/p/10981606.html
Websocket
允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
var Socket = new WebSocket(url, [protocol] );
etag标签(实体标签)
ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证。
的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag 返回给浏览器,浏览器把"3f80f-1b6-3e1cb03b" 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: "3f80f-1b6-3e1cb03b"
的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。
ETag`HTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。
如果给定URL中的资源更改,则一定要生成新的Etag值。 因此Etags类似于指纹,也可能被某些服务器用于跟踪。 比较etags能快速确定此资源是否变化,但也可能被跟踪服务器永久存留。
css动画 transform,transition ,animation
- transform:描述了元素的静态样式,本身不会呈现动画效果,可以对元素进行 旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix.
transform常常配合transition和animation使用 - transition样式过渡,从一种效果逐渐改变为另一种效果。transition是一个合写属性:
transition:transition-property transition-duration transition-timing-function transition-delay//从左到右分别是:css属性、过渡效果花费时间、速度曲线、过渡开始的延迟时间
- animation动画 由@keyframes来描述每一帧的样式
div{ animation:myAnimation 5s infinite } @keyframes myAnimation { 0%{left:0;transform:rotate(0);} 100%{left:200px;transform:rotate(180deg);} }
- (1)transform仅描述元素的静态样式,常常配合transition和animation使用
(2)transition通常和hover等事件配合使用,animation是自发的,立即播放
(3)animation可设置循环次数
(4)animation可设置每一帧的样式和时间,transition只能设置头尾
(5)transition可与js配合使用,js设定要变化的样式,transition负责动画效果
/*css:*/ div{ width:100px; height:100px; transition:all 1s; } //js divEle.onclick = function(){ divEle.style.width = "200px"; divEle.style.height = "200px"; }
浏览器兼容性问题与解决方案
https://blog.csdn.net/weixin_38536027/article/details/79375411
typeof 类型判断
- 使用typeof()或者typeof进行基本数据类型检测,null是Null类型,属于基本类型,但是typeof null 返回的是字符串’object’;
console.log(typeof undefined);//未定义undefined console.log(typeof null);//空值,对象类型
- 引用类型只能使用 instanceof,基本数据类型无法使用instanceof 进行检测数据类型,因为基本数据类型使用instanceof进行检测,结果都是返回false
css中什么属性让字体更清晰
将-webkit-font-smoothing设置为antialiased,变得非常平滑,效果非常不错。
其默认可以支持6个值(如图),暂时我能看到效果的就是三个:
none(用于小像素文本) | subpixel-antialiased(默认) | antialiased(反锯齿)
this的指向问题
在`非严格模式`下,函数中的this指向window对象,因为此时函数fn是window的一个属性,所以运行fn时,fn中的this指向window。其实this的指向就是指向函数的`运行时`环境。
在`严格模式`下,若不使用window调用函数,函数中的this指向undefined;使用window调用时,指向的时window对象。
var fn = function () { 'use strict' console.log(this); console.log(this === window) } fn(); //undfined //false window.fn(); //Window对象 //true
在`严格模式`下有一种例外的情况,就是在定时器中的this,此时无论使用window调用还是不使用window调用,this都指向window。
- 在ES6中箭头函数this的指向:在ES6中箭头函数this的指向取决于
定义时
环境中的this指向一致
var fun = () => { console.log(this); console.log(this === window); } fun(); //Window对象 //true //定义箭头函数时,就是这个过程:()=>{...}所在的环境是window,所以运行fun()时,箭头函数内部的this指向window
var obj = { name:'Jay', age:25, fn:()=>{console.log(this)}, fun:function(){ console.log(this) } }; //在定义fn时,fn内部this的指向就是定义obj对象时所在的环境,obj所在的环境是window,所以调用obj.fn()时,返回的this就是Window对象 obj.fn(); //Window对象 obj.fun();//{name: "Jay", age: 25, fn: ƒ, fun: ƒ}
DOM事件处理函数中this的指向是触发该事件的对象
<div id='app'>App</div> <script> var $id = document.querySelector('#app'); $id.onclick = function () { console.log(this); } </script> //当点击App时,console.log(this),打印出来的值时 <div id='app'>App</div>
function Person (){ this.name = 'Jay', this.age = 25; console.log(this); } var p1 = new Person(); //Person {name: "Jay", age: 25}
- 改变this的指向
可以使用call()、apply()、bind()改变函数内部this的指向(ES6中的箭头函数除外)。其中call()和apply()在传入要绑定的this指向时,立即执行。bind()在传入要绑定的this指向时,并不执行,需要再次调用才会执行。
使用bind()改变this的指向
var obj = { name:'Jay', age:25 }; function fn(){ console.log(this===obj); console.log(this); } //fn.bind(obj);不会立即执行,需要再次调用才会执行。 var fn1 = fn.bind(obj); fn1(); //true //{name: "Jay", age: 25}
- 需要注意的是,当使用call()、apply()、bind()改变函数内部this的指向时,如果传入的不是一个对象,会调用相对的构造函数,进行隐式类型装换。
function fn(){ console.log(typeof this === 'object'); console.log(this); } fn.apply('I am a string'); //true //String{"I am a string"}
CSS行内和块状元素的区别?
HTML可以将元素分类方式分为行内元素、块状元素和行内块状元素三种。首先需要说明的是,这三者是可以互相转换的,使用display属性能够将三者任意转换:
(1)display:inline;转换为行内元素
(2)display:block;转换为块状元素
(3)display:inline-block;转换为行内块状元素
行内元素特征:
(1)设置宽高无效
(2)对margin仅设置左右方向有效,上下无效;padding设置上下左右都有效,即会撑大空间
(3)不会自动进行换行
块状元素特征:
(1)能够识别宽高
(2)margin和padding的上下左右均对其有效
(3)可以自动换行
(4)多个块状元素标签写在一起,默认排列方式为从上至下
行内块状元素特征:
(1)不自动换行
(2)能够识别宽高
(3)默认排列方式为从左到右
scrollHeight、scrollTop、clientHeight、offsetHeight区别
- scrollHeight:返回当前整个元素的高度(包括带滚动条的隐蔽的地方)
- scrollTop:clientHeight的顶部到scrollHeight顶部的高度
- offsetTop :指当前元素距离上方或上层元素的距离
- clientHeight: 返回当前元素在页面上的可视高度(包括padding;不包括border、margin、滚动条高度)
- offsetHeight:返回当前元素在页面上的可视高度(包括padding、border、滚动条高度;不包括margin)
对HTML语义化标签的理解
HTML标签可以分为有语义的标签,和无语义的标签。比如table表示表格,form表示表单,a标签表示超链接,strong标签表强调。无语义标签典型的有div,span等。
- 为什么要进行语义化?
1,现在的开发基本上都是一个团队合作进行开发。这种情况下,我们写的代码不仅要让我们自己能看懂,而且也应该让别人也容易理解和阅读,要保证代码的可维护性,这一点很重要。但是在实际开发中,由于HTML的灵活性,以及CSS的强大,以至于实现同一种界面样式,不同的人写出来的代码可能实现方式都不太一样。实现糟糕的,可能全是div套div,这样的代码到时候维护的话可能就是一场灾难。这一点,个人觉得是最主要的因素。
2,和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息
3,考虑到代码的可复用性,可移植性,方便其他设备的解析执行。移动设备、盲人阅读器等。 - 使用HTML语义化好处
html语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;
即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;
搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;
使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。