用devicePixelRatio判断当前浏览器是否处于缩放状态
1
2
3
4
5var a={n:1};
var b=a;
a.x=a.y=a={n:2}; //a.x={n:2},a.y={n:2},此时a还是{n:1},a={n:2}
console.log(a); // {n: 2}
console.log(b); //{n: 1, y: {…}, x: {…}}
ES6模块是编译时加载是什么意思
1 | JS的“编译”可能指三种流程:transform、bundle、uglify。 |
原生JS API
1 | 一、节点 |
setTimeout(fn, 0) 的作用
setTimeout(0)单线程和异步队列
setTimeout和setInterval是JS内置的两个定时器,使用很简单,但这两个方法背后的原理却不简单。
我们知道,JS是单线程语言,在浏览器中,当JS代码被加载时,浏览器会为其分配一个主线程来执行任务(函数),
主线程会形成一个全局执行环境,执行环境采用栈的方式将待执行任务按顺序依次来执行。
但在浏览器中有一些任务是非常耗时的,比如http请求、定时器、事件回调等,为了保证其他任务的执行效率不被影响,
JS在执行环境中维护了一个异步队列(也叫工作线程),并将这些任务放入队列中进行等待,这些任务的执行时机并不确定,
只有当主线程的任务执行完成以后,才会去检查异步队列中的任务是否需要开始执行。这就是为什么setTimeout(fn,0)
始终要等到最后执行的原因。关于单线程和异步队列问题请参考:setTimeout(0)
深拷贝
1 | function deepCopy(p, c) { |
POST和GET的区别,HTTP状态码
1
2
3
4
5
6
7
8
9
10POST和GET的区别
GET在浏览器回退时是无害的,而POST会再次提交请求
GET产生的URL地址可以被收藏,而POST不可以
GET请求会被浏览器主动缓存,而POST不会,除非手动设置
GET请求只能进行URL编码,而POST支持多种编码方式
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
GET请求在URL中传送的参数是有长度限制的,而POST没有长度限制
对参数的数据类型,GET只能请求ASCII字符,而POST没有限制
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传敏感信息
GET参数通过URL传递,POST放在Request body中
Post,Get接口傻傻分不清?
1 | HTTP状态码 |
301和302
301与302:二者都是进行重定向,前者为永久重定向,后者为临时重定向。301,302对用户来说没有区别,他们看到效果只是一个跳转,浏览器中旧的URL变成了新的URL。实际工作中,当我们的前一个域名被永久性停止使用,并且不希望用户还能访问以前的域名时,我们会用到301。
301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。他们的不同在于:301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了), 搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问), 这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。
301重定向和302重定向的区别:
- 302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,因为服务器返回302,所以,搜索搜索引擎认为新的网址是暂时的。
- 而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址。
1 | 301适合永久重定向 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18301—永久移动。被请求的资源已被永久移动位置;
【永久重定向】
302—请求的资源现在临时从不同的 URI 响应请求;
【临时重定向】
305—使用代理。被请求的资源必须通过指定的代理才能被访问;
307—临时跳转。被请求的资源在临时从不同的URL响应请求;
400—错误请求;
402—需要付款。该状态码是为了将来可能的需求而预留的,用于一些数字货币或者是微支付;
403—禁止访问。服务器已经理解请求,但是拒绝执行它;
404—找不到对象。请求失败,资源不存在;
406—不可接受的。请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体;
408—请求超时;
409—冲突。由于和被请求的资源的当前状态之间存在冲突,请求无法完成;
410—遗失的。被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址;
413—响应实体太大。服务器拒绝处理当前请求,请求超过服务器所能处理和允许的最大值。
417—期望失败。在请求头 Expect 中指定的预期内容无法被服务器满足;
418—我是一个茶壶。超文本咖啡罐控制协议,但是并没有被实际的HTTP服务器实现;
420—方法失效。
422—不可处理的实体。请求格式正确,但是由于含有语义错误,无法响应;
500—服务器内部错误。服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理;
JS返回所有子节点对象childNodes
1 | var mylist = document.getElementById('myid'); |
insertBefore()插入节点(父节点内容的最前面)
注意:insertBefore()有两个参数,第一个是插入的节点,第二个是插入的位置
例子:1
2
3var list = document.getElementById('myList');
list.insertBefore(newItem,list.childNodes[1]);
//插入新节点newItem到list的第二个子节点
Element.matches 精确匹配
1 | document.getElementById('list').addEventListener('click', function (e) { |
移动端touch事件(区分webkit 和 winphone)
当用户手指放在移动设备在屏幕上滑动会触发的touch事件,以下支持webkit
1
2
3
4
5
6
7
8
9
10 touchstart——当手指触碰屏幕时候发生。不管当前有多少只手指
touchmove——当手指在屏幕上滑动时连续触发。通常我们再滑屏页面,会调用event的preventDefault()可以阻止默认情况的发生:阻止页面滚动
touchend——当手指离开屏幕时触发
touchcancel——系统停止跟踪触摸时候会触发。例如在触摸过程中突然页面alert()一个提示框,此时会触发该事件,这个事件比较少用TouchEvent
touches:屏幕上所有手指的信息
targetTouches:手指在目标区域的手指信息
changedTouches:最近一次触发该事件的手指信息
touchend时,touches与targetTouches信息会被删除,changedTouches保存的最后一次的信息,最好用于计算手指信息参数信息(changedTouches[0])
clientX、clientY在显示区的坐标
target:当前元素
全局错误监控
监听window上的error事件,过滤事件代理的error。
手动触发一个dom事件,需要3步,如果你对document.createEvent,�不是很熟悉,可以点击查看。
创建一个事件对象 document.createEvent(event)
初始化事件对象 event.initEvent(type, bubbles, true)
分发事件 dom.dispatchEvent(event)
1 | Object.preventExtensions(obj) 让一个对象变的不可扩展,也就是永远不能再添加新的属性。 |
获取元素的绝对位置
1 | function getPosition(node) { |
动画结束时事件
1 | o.addEventListener("webkitAnimationEnd", function() { |
解决键盘弹出遮挡:
1 | // 解决键盘弹出后挡表单的问题 |
1 | /** |
单个for循环实现排序:
1 | var a = [12, 13, 65, 54, 86, 21, 37, 1, 95, 4]; |
Object.assign实现:
1 | if (!Object.assign) { |
JavaScript中巧用位运算
1 | 日常前端开发中我们很少用到位运算,容易让人遗忘,让我们一起回顾下一下js中的位运算。 |
将颜色从RGA转换为Hex格式
1 | var color = {r: 186, g: 218, b: 85}; |
常用函数:
1 | /*========================常用函数========================*/ |
performance
1 | ; |
Cookie
1 | export default class Cookie { |
jsonp
1 | function jsonp(objects){ |
js判断DOM是否包含另一个DOM
1 | <!DOCTYPE html> |
回到顶部带动画
1 | /* 滚动条动画: |
使用js唤起Native下的App
1 | /** |
高阶函数
1 | <script type="text/javascript"> |
add(2)(3)(),add(2,3)()输出5
1 | <script type="text/javascript"> |
获取CSS样式
1 | function getStyle(obj, attr) { |
Colors
1 | function rgbToRgba(rgbValue) { |
750rem
1 | (function(doc, win) { |
表单验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static checkType = (str, type) => {
switch(type) {
case 'email':
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'phone':
return /^1[3|4|5|7|8][0-9]{9}$/.test(str);
case 'tel':
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'number':
return /^[0-9]$/.test(str);
case 'english':
return /^[a-zA-Z]+$/.test(str);
case 'chinese':
return /^[\u4E00-\u9FA5]+$/.test(str);
case 'lower':
return /^[a-z]+$/.test(str);
case 'upper':
return /^[A-Z]+$/.test(str);
default:
return true;
}
}
navigator帮助类
1 | class navigatorUtil { |
promise
1 | function Promise(task) { |
ES6 promise
1 | class es6Promise { |
使用promise手动封装ajax函数
跨浏览器实现Ajax兼容
1 | var createXMLHttpRequest = function () { |
Ajax的xhr对象有如下常用API
1 | onloadstart 开始send触发 |
readyState上面都是静态函数。而readyState表示了请求的状态:
- value=0,open()方法还未被调用
- value=1,open()调用,send()方法还未被调用
- value=2,send()方法已经被调用,响应头和响应状态已经返回
- value=3,响应体下载中,responseText中已经获取了部分数据
- value=4,请求完成,整个请求过程已经完毕。
GET
1 | function getJSON (url) { |
POST
1 | function postJSON(url, data) { |
1 | // ajax函数的默认参数 |
二分查找 【二分查找也称折半查找 ,时间复杂度:O(log2n)】
非递归算法
1 | function binary_search(arr,key){ |
递归算法
1 | function binary_search(arr,low,high,key){ |
排序
冒泡排序
1 | function bubbleSort(arr) { |
1 | function bubble_sort(arr){ |
快速排序
1 | function quick_sort(arr){ |
1 | function qSort(arr) { |
当我们 new 一个类的时候 都发生了什么
1 | /** |
new操作符的工作原理
1 | 废话不多说,直接上代码 |
Object.create 兼容实现
1 | let obj1 = {id: 1}; |
curry 将多参数函数转换为接收单一参数的函数
1 | let fn = function(a, b, c) { // 多参数函数 |
函数节流
throttle 策略的电梯。保证如果电梯第一个人进来后,50毫秒后准时运送一次,不等待。如果没有人,则待机。
1 | let throttle = (fn, delay = 50) => { // 节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove |
防抖动
debounce 策略的电梯。如果电梯里有人进来,等待50毫秒。如果又人进来,50毫秒等待重新计时,直到50毫秒超时,开始运送。
1 | let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间 用户输入频繁 |
Function的bind实现
1 | Function.prototype._bind = function(context) { |
函数组合串联compose(koa reduce中间件)
1 | // 组合串联 |
co函数
1 | function* fn(a) { |
如何主动中止Promise调用链
1 | const p1 = new Promise((resolve, reject) => { |
window.requestAnimationFrame兼容性处理
1 | window._requestAnimationFrame = (function(){ |
字符串是否符合回文规则
1 | let str = 'My age is 0, 0 si ega ym.'; |
解构:将 destructuringArray([1, [2, 3], 4], “[a, [b], c]”) => {a: 1, b: 2, c: 4}
1 | // 将 destructuringArray([1, [2, 3], 4], "[a, [b], c]") => {a: 1, b: 2, c: 4} |
数组展平
1 | 将[[1, 2], 3, [[[4], 5]]] 展平为 [1, 2, 3, 4, 5] |
找出数组中重复出现过的元素
1 | // 例如:[1,2,4,4,3,3,1,5,3] |
将数组中按照数字重复出现的次数进行排序
1 | // 如果次数相同 则按照值排序 比如 2, 2, 2和 1, 1, 1 应排序为 [1, 1, 1, 2, 2, 2] |
移动端关闭虚拟键盘
1 | document.activeElement.blur(); |
解决setInterval在浏览器切换中的问题
1 | document.onvisibilitychange=function(){ |
Promise 透传
1 | Promise.resolve(1).then(2).then((a)=>console.log(a)) |
不用循环,创建一个长度为 100 的数组,并且每个元素的值等于它的下标
1 | es6版: |
箭头函数
1 | (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 |
异步加载的区别
- defer是在HTML解析完之后才会执行,如果是多个,按照加载的顺序依次执行
- async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关
async和defer
html 触底的条件是:
1 | document.documentElement.scrollHeight === |
雅虎十四条优化
1 | 1. 尽可能的减少 HTTP 的请求数 content |
微任务有两种 nextTick和then 那么这两个谁快呢?
1 | Promise.resolve('123').then(res=>{ |
setTimeout第三个参数
1 | setTimeout(function(...list){ |
Object和Function之间最让人琢磨不透的
1 | Object instanceof Object // true |
文件上传进度提示使用Javascript的XMLHttpRequest的progress事件
1 | 使用Javascript的XMLHttpRequest的progress事件,实现示例代码为: |
面试题
1 | <script type="text/javascript"> |
LESS和SASS
语言 | 实现 | 特性 | 赋值 | 缩进 |
---|---|---|---|---|
Sass | Ruby | 变量$开头 | $var: value | 不需要 |
Less | JavaSript | 变量@开头 | @var: value | 不需要 |
Stylus | NodeJs | 不能使用@开头 | var:10 | 都可以 |
创造纯净的对象
1 | 你可以创造100%纯净的对象,它不会从Object类继承任何方法(例如:构造函数、toString() 等)。 |
将一个任意长的数字变成逗号分割的格式
1 | 例子: |
检测对象中属性的存在
使用in关键字。
该方法可以判断对象的自有属性和继承来的属性是否存在。1
2
3
4var o={x:1};
"x" in o; //true,自有属性存在
"y" in o; //false
"toString" in o; //true,是一个继承属性
使用对象的hasOwnProperty()方法。
该方法只能判断自有属性是否存在,对于继承属性会返回false。1
2
3
4var o={x:1};
o.hasOwnProperty("x"); //true,自有属性中有x
o.hasOwnProperty("y"); //false,自有属性中不存在y
o.hasOwnProperty("toString"); //false,这是一个继承属性,但不是自有属性
n!
1 | functionfactorial(number){ |
斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, … 求第n个数是多少
1 | functionfibonacci(number) { |
服务端推送的几种方式
服务端推送是现今Web
开发过程中最常见的需求。例如:
- 即时聊天工具
- H5网络游戏
- 消息通知
一般的服务器推送包括:
- 最简单的是客户端轮询的方式,在客户端创建一个定时器,每隔一定的时间去请求服务端,每次请求检查状态变化以判断服务端是否有新数据更新。
- 基于 AJAX 的长轮询(
long-polling
)方式,服务器在一段时间后再返回信息; HTTP Streaming
,通过iframe
和<script>
标签完成数据的传输;TCP
长连接/WebSocket
,可以实现服务器主动发送数据至网页端,它和HTTP
一样,是一个基于HTTP
的应用层协议,跑的是TCP
,所以本质上还是个长连接,双向通信,意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP
的请求和响应SSE: Server-Sent Events
,【webpack】这是通过http
协议变通实现的,通过服务端向客户端声明,接下来是要发送的是流信息,本质上就是完成一次耗时长的下载。
JavaScript进阶提高必读
JavaScript常用七种继承方案
JS 面试原生常用api 方法大全
JS代码手写题
PM2来部署nodejs服务器永久开启
JavaScript设计模式
URL 解析
JavaScript专题
数据结构
轻松理解JavaScript原型及原型链
H5 移动调试全攻略
JS 面试原生常用api 方法大全
javascript 原生常用API大全
preload、prefetch
现在的网络情况虽然很乐观,但是
defer和async
当浏览器碰到 script 脚本的时候:
<script src="script.js"></script>
没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
<script async src="script.js"></script>
有 async,加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步)。
<script defer src="myscript.js"></script>
有 defer,加载后续文档元素的过程将和 script.js 的加载并行进行(异步),但是 script.js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。
然后从实用角度来说呢,首先把所有脚本都丢到 之前是最佳实践,因为对于旧浏览器来说这是唯一的优化选择,此法可保证非脚本的其他一切元素能够以最快的速度得到加载和解析。
接着,我们来看一张图咯:
此图告诉我们以下几个要点:
defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
它俩的差别在于脚本下载完之后何时执行,显然 defer 是最接近我们对于应用脚本加载和执行的要求的
关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行
仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,
preload和refetch
preload
通常在页面中,我们需要加载一些脚本和样式,而使用 preload 可以对当前页面所需的脚本、样式等资源进行预加载,而无需等到解析到 script 和 link 标签时才进行加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。
使用方式
将 link 标签的 rel 属性的值设为 preload,as 属性的值为资源类型(如脚本为 script,样式表为 style)
1 | <head> |
prefetch
与 preload
一样,都是对资源进行预加载,但是 prefetch 加载的资源一般不是用于当前页面的,即未来很可能用到的这样一些资源,简单点说就是其他页面会用到的资源。当然,prefetch 不会像 preload 一样,在页面渲染的时候加载资源,而是利用浏览器空闲时间来下载。当进入下一页面,就可直接从 disk cache 里面取,既不影响当前页面的渲染,又提高了其他页面加载渲染的速度。
使用方式
同 preload
很相似,无需指定 as 属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 <head>
<meta charset="utf-8">
<title>
preload example
</title>
<!-- 对 style.css 和 index.js 进行 preload 预加载 -->
<link rel="preload" href="style.css" as="style">
<link rel="preload" href="index.js" as="script">
<!-- 对资源进行 prefetch 预加载 -->
<link rel="prefetch" href="next.css">
<link rel="prefetch" href="next.js">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app"></div>
<script src="index.js"></script>
</body>
总结:对当前页面需要的资源,使用 preload 进行预加载,对其它页面需要的资源进行 prefetch 预加载。 |
Subresource和Prerender
subresource
可以用来指定资源是最高优先级的。比如,在Chrome和Opera中我们可以加上下面的代码:
<link rel="subresource" href="styles.css">
Chromium的文档这么解释:
和 “Link rel=prefetch”的语义不同,”Link rel=subresource”是一种新的连接关系。rel=prefetch指定了下载后续页面用到资源的低优先级,而rel=subresource则是指定当前页面资源的提前加载。
所以,如果资源是在当前页面需要,或者马上就会用到,则推荐用subresource,否则还是用prefetch。
prerender
是一个重量级的选项,它可以让浏览器提前加载指定页面的所有资源。
<link rel="prerender" href="/thenextpage.html" />
Steve Souders的文章详细解释了这个技术:
prerender就像是在后台打开了一个隐藏的tab,会下载所有的资源、创建DOM、渲染页面、执行JS等等。如果用户进入指定的链接,隐藏的这个页面就会进入马上进入用户的视线。Google Search多年前就利用了这个特性实现了Instant Pages功能。微软最近也宣布会让Bing在IE11上用类似prerender的技术。
Axios拦截器
1 | import axios from 'axios' |
*JavaScript的值传递和引用传递
1 | function changeAgeAndReference(person) { |
JSONP 【JSONP百度搜索框】
1 | <!DOCTYPE html> |
Math.round(),Math.ceil(),Math.floor()的区别
1.Math.round():根据“round”的字面意思“附近、周围”,可以猜测该函数是求一个附近的整数,看下面几个例子就明白。1
2
3
4
5
6
7
8
9
10
11
12小数点后第一位<5
正数:Math.round(11.46)=11
负数:Math.round(-11.46)=-11
小数点后第一位>5
正数:Math.round(11.68)=12
负数:Math.round(-11.68)=-12
小数点后第一位=5
正数:Math.round(11.5)=12
负数:Math.round(-11.5)=-11
总结:(小数点后第一位)大于五全部加,等于五正数加,小于五全不加。
2.Math.ceil():根据“ceil”的字面意思“天花板”去理解;
例如:1
2Math.ceil(11.46)=Math.ceil(11.68)=Math.ceil(11.5)=12
Math.ceil(-11.46)=Math.ceil(-11.68)=Math.ceil(-11.5)=-11
3.Math.floor():根据“floor”的字面意思“地板”去理解;
例如:1
2Math.ceil(11.46)=Math.ceil(11.68)=Math.ceil(11.5)=11
Math.ceil(-11.46)=Math.ceil(-11.68)=Math.ceil(-11.5)=-12
Math.random()函数生成n到m间的随机数字
Math.random()函数返回0和1之间的伪随机数,可能为0,但总是小于1,[0,1)
生成n-m,包含n但不包含m的整数:
1 | 第一步算出 m-n的值,假设等于w |
生成n-m,不包含n但包含m的整数:
1 | 第一步算出 m-n的值,假设等于w |
生成n-m,不包含n和m的整数:
1 | 第一步算出 m-n-2的值,假设等于w |
生成n-m,包含n和m的随机数:
1 | 第一步算出 m-n的值,假设等于w |
ES6事件总线 EventBus
1 |
|
1 |
|
JS全排列 【全排列是一种时间复杂度为:O(n!)的算法】
1 | <!DOCTYPE html> |
一年半经验,百度、有赞、阿里面试总结
2018 大厂高级前端面试题汇总
Google Chrome可跨域模式
1 | open -a 'Google Chrome' --args --disable-web-security --user-data-dir |
v-for 循环 index的传值问题
1 | <el-submenu :index="index" v-for="(item,index) in menuList"> |
发现子组件获取到的index一直都是undefined。
修改办法:1
2
3
4<el-menu-item :index="''+index"
v-for="(subItem,subindex) in item.subMenuList">
{{index}}-{{subItem.subMenuName}}
</el-menu-item>
将 :index 的制改为’’+index,一定是单引号’’ ,子组件获取的到的就变成字符串”0,””1”…..
将字符串”0”变成整数 +”0” 即可!
.vue文件的一个小细节
top.vue1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70<template>
<div class="ds">
<div class="left">
<p>SX</p>
</div>
<div class="right">
<p>SB</p>
</div>
</div>
</template>
<script>
console.log("-------------------------"); //只执行一次
export default {
props: [],
data() {
return {}
},
components: {
},
methods: {
},
created() {
},
mounted() {
console.log("$$$$$$$$$$$$$$$$$$$$$$$"); //执行多次
}
};
</script>
<style lang="scss" scoped="scoped">
.guize {
box-sizing: border-box;
padding: 0 0.4rem;
margin-top: -0.3rem;
width: 100%;
height: 1.2rem;
font-size: 0.24rem;
color: white;
position: relative;
.left {
color: #abc4ed;
float: left;
transform:scale(0.85);
transform-origin:0 0;
p {
font-size: 0.24rem;
line-height: 2;
}
}
.right {
float: left;
width: 1.6rem;
height: 0.44rem;
line-height: 0.44rem;
border: 1px solid white;
color: white;
border-radius: 0.24rem;
text-align: center;
position: absolute;
right: 0.4rem;
bottom: 0.04rem;
}
}
</style>
由浏览器端判断是否支持WebP格式
1 | if(document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0){ |
src转img
function srctoimg(src){
return new Promise((reslove,reject)=>{
let img = new Image()
img.onload = function(){
reslove(img)
}
img.onerror = function(err) {
reject(err)
}
img.src = src
})
}
img转canvas
function imgtocanvas(img){
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d')
canvas.width = img.width
canvas.height = img.height
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
return canvas
}
ImageData转canvas
function ImageDatetocanvas(imgData){
let canvas = document.createElement("canvas");
let ctx = canvas.getContext('2d')
canvas.width = imgData.width
canvas.height = imgData.height
ctx.putImageData(imgData,canvas.width, canvas.height);
return canvas
}
canvas转ImageData
function canvastoImageDate(canvas){
let ctx = canvas.getContext('2d')
return ctx.createImageData(canvas.width,canvas.height)
}
canvas像素操作
function canvaspixel(canvas,deal) {
let ctx = canvas.getContext('2d')
var imgData = ctx.createImageData(canvas.width, canvas.height);
for (var i = 0; i < imgData.data.length; i += 4) {
deal(r,g,b,a)
}
ctx.putImageData(imgData, canvas.width, canvas.height);
return canvas
}
canava转DataURL(base64)
canvas.toDataURL()
DataURL(base64)转blob
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
file转arrayBuffer
function filetoblob(file){
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
resolve(reader.result)
}
})
}
file转blob
function filetoblob(file){
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (e) {
resolve(new Blob([reader.result],{type:file.type}))
}
})
}
(blob,arraybuffer)转file
function blobtofile(blob,name){
return new File([blob], name ,{type:blob.type})
}
file(blob)转DataURL(base64)
function filetoblob(file) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
resolve(reader.result)
}
reader.onerror = function (e) {
resolve(reader.result)
}
})
}
dataURL转File
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
blob转objectURL
window.URL.createObjectURL(blob)
objectURL转img
srctoimg(src)
objectURL(url)转blob
functionURLtoblob(){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', input)
xhr.responseType = 'blob'
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.onerror = () => reject(xhr.statusText)
xhr.send()
})
}
}
objectURL(url)转arraybuffer,当服务端传递二级制数据时使用
functionURLtoblob(){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', input)
xhr.responseType = 'arraybuffer'
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject(xhr.statusText)
}
}
xhr.onerror = () => reject(xhr.statusText)
xhr.send()
})
}
}
FormData设置blob
function appendBlob(blob){
var fd = new FormData();
fd.append("image", blob, "image.png");
return fd
}
Uint8ClampedArray Uint8Array 区别
Uint8ClampedArray
1 ,它会将负数归入0,大于255的数归入255,所以取模就不用了。
2 ,小数取整
Uint8Array
1,Uint8Array([-23]) 等价于 new Uint8Array([ 233 ])
2,四舍五入
在处理0-255无区别
arraybuffer,视图(Uint8Array、Float64Array等)之slice
buf返回buf
视图返回视图
1,分配内存
2,拷贝数据
数据
1,new ArrayBuffer(40)
2,new Uint8Array( [ 1, 2, 3, 4 ] )
3,Array.from(uint8Array);
视图参数
var v3 = new Int16Array(buf, 2, 2);
第一个参数:视图对应的底层ArrayBuffer对象,该参数是必需的。
第二个参数:视图开始的字节序号,默认从0开始。
第三个参数:视图包含的数据个数,默认直到本段内存区域结束。
视图.buffer 获取缓冲区
视图对象DataView
var buffer = new ArrayBuffer(24);
var dv = new DataView(buffer);
// 从第1个字节读取一个8位无符号整数
var v1 = dv.getUint8(0);
// 从第2个字节读取一个16位无符号整数
var v2 = dv.getUint16(1);
// 从第4个字节读取一个16位无符号整数
var v3 = dv.getUint16(3);
setInt8:写入1个字节的8位整数。
setUint8:写入1个字节的8位无符号整数。
setInt16:写入2个字节的16位整数。
setUint16:写入2个字节的16位无符号整数。
setInt32:写入4个字节的32位整数。
setUint32:写入4个字节的32位无符号整数。
setFloat32:写入4个字节的32位浮点数。
setFloat64:写入8个字节的64位浮点数。
// 在第1个字节,以大端字节序写入值为25的32位整数
dv.setInt32(0, 25, false);
// 在第5个字节,以大端字节序写入值为25的32位整数
dv.setInt32(4, 25);
// 在第9个字节,以小端字节序写入值为2.5的32位浮点数
dv.setFloat32(8, 2.5, true);
实现atob(string 转 base64) window.atob
function _atob(s) {
var base64hash = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
s = s.replace(/\s|=/g, '');
var cur,
prev,
mod,
i = 0,
result = [];
while (i < s.length) {
cur = base64hash.indexOf(s.charAt(i));
mod = i % 4;
switch (mod) {
case 0:
//TODO
break;
case 1:
result.push(String.fromCharCode(prev << 2 | cur >> 4));
break;
case 2:
result.push(String.fromCharCode((prev & 0x0f) << 4 | cur >> 2));
break;
case 3:
result.push(String.fromCharCode((prev & 3) << 6 | cur));
break;
}
prev = cur;
i++;
}
return result.join('');
}
实现btoa(base64 转 string) window.btoa
function _btoa(s) {
var base64hash = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
if (/([^\u0000-\u00ff])/.test(s)) {
throw new Error('INVALID_CHARACTER_ERR');
}
var i = 0,
prev,
ascii,
mod,
result = [];
while (i < s.length) {
ascii = s.charCodeAt(i);
mod = i % 3;
switch (mod) {
// 第一个6位只需要让8位二进制右移两位
case 0:
result.push(base64hash.charAt(ascii >> 2));
break;
//第二个6位 = 第一个8位的后两位 + 第二个8位的前4位
case 1:
result.push(base64hash.charAt((prev & 3) << 4 | (ascii >> 4)));
break;
//第三个6位 = 第二个8位的后4位 + 第三个8位的前2位
//第4个6位 = 第三个8位的后6位
case 2:
result.push(base64hash.charAt((prev & 0x0f) << 2 | (ascii >> 6)));
result.push(base64hash.charAt(ascii & 0x3f));
break;
}
prev = ascii;
i++;
}
// 循环结束后看mod, 为0 证明需补3个6位,第一个为最后一个8位的最后两位后面补4个0。另外两个6位对应的是异常的“=”;
// mod为1,证明还需补两个6位,一个是最后一个8位的后4位补两个0,另一个对应异常的“=”
if (mod == 0) {
result.push(base64hash.charAt((prev & 3) << 4));
result.push('==');
} elseif (mod == 1) {
result.push(base64hash.charAt((prev & 0x0f) << 2));
result.push('=');
}
return result.join('');
}
atob,btoa 不能编码解码中文
var str = "China,中国";
window.btoa(window.encodeURIComponent(str))
//"Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ="
window.decodeURIComponent(window.atob('Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ='))
//"China,中国"
编码含义
1,区分数据部分和参数部分
2,解决中文乱码(服务端和客户端编码不一致)
escape不编码字符有69个:*,+,-,.,/,@,_,0-9,a-z,A-Z
encodeURI不编码字符有82个:!,#,$,&,',(,),*,+,,,-,.,/,:,;,=,?,@,_,~,0-9,a-z,A-Z
encodeURIComponent不编码字符有71个:!, ',(,),*,-,.,_,~,0-9,a-z,A-Z
内存模型
JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。 其中栈存放变量,堆存放复杂对象,池存放常量。
内存的生命周期
内存分配 — 内存使用 — 内存回收
内存回收算法
- 引用计数算法
存在一个致命的问题:循环引用。如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露。
- 标记清除算法
标记清除算法将“不再使用的对象”定义为“无法达到的对象”。从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,都是还需要使用的。那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。
内存泄漏
内存泄漏的识别方法
- 浏览器方法
- 命令行方法
- WeakMap(ES6)
判断字节长度
破解循环引用
深拷贝的终极探索,破解循环引用(99%的人都不知道)1
2
3
4
5Uncaught TypeError: Converting circular structure to JSON
at JSON.stringify (<anonymous>)
at mainctrl.js:234
at Object.getUser (api.js:247)
at mainctrl.js:228
1 | // Demo: Circular reference |
JPG、GIF、PNG和BMP格式的图片各有什么优点和缺点
都说 WebP 厉害,究竟厉害在哪里?
1 | BMP:优点(无损压缩,图质最好),缺点(文件太大,不利于网络传输) |
BMP
BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。
GIF
GIF文件的数据,是一种基于LZW算法的连续色调的无损压缩格式。其压缩率一般在50%左右,它不属于任何应用程序。目前几乎所有相关软件都支持它,公共领域有大量的软件在使用GIF图像文件。GIF图像文件的数据是经过压缩的,而且是采用了可变长度等压缩算法。GIF格式的另一个特点是其在一个GIF文件中可以存多幅彩色图像,如果把存于一个文件中的多幅图像数据逐幅读出并显示到屏幕上,就可构成一种最简单的动画。
PNG
PNG图像文件存储格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且还可存储多到16位的α通道数据。PNG使用从LZ77派生的无损数据压缩算法,一般应用于JAVA程序、网页或S60程序中,原因是它压缩比高,生成文件体积小。
JPG
JPG全名是JPEG。JPEG图片以 24 位颜色存储单个位图。JPEG 是与平台无关的格式,支持最高级别的压缩,不过,这种压缩是有损耗的。渐近式 JPEG 文件支持交错。
URL.createObjectURL,FileReader上传图片预览
js图片前端预览之 filereader 和 window.URL.createObjectURL
URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
URL.createObjectURL(blob)和FileReader.readAsDataURL(file)很相似:
区别
- 通过FileReader.readAsDataURL(file)可以获取一段data:base64的字符串
- 通过URL.createObjectURL(blob)可以获取当前文件的一个内存URL
执行时机
- createObjectURL是同步执行(立即的)
- FileReader.readAsDataURL是异步执行(过一段时间)
内存使用
- createObjectURL返回一段带hash的url,并且一直存储在内存中,直到document触发了unload事件(例如:document close)或者执行revokeObjectURL来释放。
- FileReader.readAsDataURL则返回包含很多字符的base64,并会比blob url消耗更多内存,但是在不用的时候会自动从内存中清除(通过垃圾回收机制)
- 兼容性方面两个属性都兼容ie10以上的浏览器。
优劣对比:
- 使用createObjectURL可以节省性能并更快速,只不过需要在不使用的情况下手动释放内存
- 如果不太在意设备性能问题,并想获取图片的base64,则推荐使用FileReader.readAsDataURL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<input type="file" name="" id="imgFile1" value="" />
<div class="preview_wrap1"></div>
<input type="file" name="" id="imgFile2" value="" />
<div class="preview_wrap2"></div>
</body>
<script type="text/javascript">
document.getElementById('imgFile1').onchange = function(e) {
var ele = document.getElementById('imgFile1').files[0];
var fr = new FileReader();
fr.onload = function(ele) {
var pvImg = new Image();
pvImg.src = ele.target.result;
pvImg.setAttribute('id', 'previewImg1');
$('.preview_wrap1').html('').append(pvImg);
}
fr.readAsDataURL(ele);
}
</script>
<script type="text/javascript">
document.getElementById('imgFile2').onchange = function(e) {
var ele = document.getElementById('imgFile2').files[0];
var createObjectURL = function(blob) {
return window[window.webkitURL ? 'webkitURL' : 'URL']['createObjectURL'](blob);
};
var newimgdata = createObjectURL(ele);
var pvImg = new Image();
pvImg.src = newimgdata;
pvImg.setAttribute('id', 'previewImg2');
$('.preview_wrap2').html('').append(pvImg);
}
</script>
</html>
字符串混淆处理
- 加强密码等敏感数据传输安全性
- 客户端加密,服务器端解密
1 | var softdog = require("softdog"); |
- 特别提示
加密|解密方法参数如果数据类型非字符串或者为空字符串,返回结果均为空字符串
Code
softdog
1 | /*** |
DEMO
判断是否为整数
Number.isInteger()
1 | 以前,没想过小数取余数会怎样,比如 JS 中 3.5%2 。 |
css、js实现网页内容禁止选中
css1
2
3
4
5
6
7
8
9*{
moz-user-select: -moz-none;
-moz-user-select: none;
-o-user-select:none;
-khtml-user-select:none;
-webkit-user-select:none;
-ms-user-select:none;
user-select:none;
}
通过body标签1
2<body oncontextmenu="return false;" onselectstart="return false">
//前面一句是禁止右键,后面一句是禁止复制。
通过js1
2
3//禁止页面选择以及鼠标右键
document.oncontextmenu=function(){return false;};
document.onselectstart=function(){return false;};