最后更新于2019年1月13日
前端常用代码片段(一) 点这里
前端常用代码片段(二) 点这里
前端常用代码片段(三) 点这里
前端常用代码片段(四) 点这里
前端常用代码片段(五) 点这里
前端常用代码片段(六) 点这里
1.打乱数组中元素顺序(类似音乐随机播放)
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
export function shuffle(arr) {
let _arr = arr.slice()
for (let i = 0; i < _arr.length; i++) {
let j = getRandomInt(0, i)
let t = _arr[i]
_arr[i] = _arr[j]
_arr[j] = t
}
return _arr
}
扩展:
1.取[10,100) 的随机整数方法
Math.floor(Math.random()*90+10);
2.取[10,100] 的随机整数方法
function randomBy(under, over){
switch(arguments.length){
case 1: return parseInt(Math.random()*under+1);
case 2: return parseInt(Math.random()*(over-under+1) + under);
default: return 0;
}
}
randomBy(10, 100);
//随机返回一个范围的数字
randomNumber(n1, n2) {
//randomNumber(5,10)
//返回5-10的随机整数,包括5,10
if (arguments.length === 2) {
return Math.round(n1 + Math.random() * (n2 - n1));
}
//randomNumber(10)
//返回0-10的随机整数,包括0,10
else if (arguments.length === 1) {
return Math.round(Math.random() * n1)
}
//randomNumber()
//返回0-255的随机整数,包括0,255
else {
return Math.round(Math.random() * 255)
}
}
3.利用sort()
我们先产生个数组
var arr=[];
for(var i=0;i<10;i++){
arr.push(i)
}
console.log(arr) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
我们以前的正常排序是这样的:
arr.sort(function(a,b){
return b-a
});
接下来我们来打乱它:
arr.sort(()=>{
return Math.random() - 0.5
}) // [1, 0, 2, 3, 4, 6, 8, 5, 7, 9]
第二种打乱方法:
arr.sort((a,b)=>{
return a > Math.random()*10;
}) // [1, 2, 0, 6, 4, 3, 8, 9, 7, 5]
解析:
先说正常的排序:
a,b表示数组中的任意两个元素,若return > 0 ,b前a后;若reutrn < 0 则a前b后;当a=b时,则存在浏览器兼容 ;
a-b输出从小到大排序,b-a输出从大到小排序。
然后再说我们打乱的方法:
创建数组不用说,接下来就是用js的sort方法 来实现,Math.random()实现一个随机0-1之间的小数 然后再减去0.5,这时就会根据return比较后得到的值排序,所以说就会生成不是正常从大到小或者从小到大的排序。
2.函数节流(throttle)和 函数去抖(debounce)
函数节流 和 函数去抖 都是为了项目优化而出现的,官方是没有具体定义的,他们的出现主要是为了解决一些短时间内连续执行的事件带来性能上的不佳和内存的消耗巨大等问题;像这类事件一般像 scroll keyup mousemove resize等等,短时间内不断的触发,在性能上消耗是非常大的,尤其是一些改变DOM结构的操作;
节流[throttle]与防抖[debounce]非常相似,都是让上述这类事件里定义的代码 从不断的执行 更改成为 规定的时间内执行多少次;
函数节流(throttle) 应用场景
函数节流(throttle),例如实现一个拖拽功能,需要一路监听 mousemove 事件,在回调中获取元素当前位置,然后重置 dom 的位置(样式改变)。如果我们不加以控制,每移动一定像素而触发的回调数量是会非常惊人的,回调中又伴随着 DOM 操作,继而引发浏览器的重排与重绘,性能差的浏览器可能就会直接假死,这样的用户体验是非常糟糕的。我们需要做的是降低触发回调的频率,比如让它 500ms 触发一次,或者 1000ms,这个阈值不能太大,太大了拖拽就会失真,也不能太小,太小了低版本浏览器可能就会假死,这样的解决方案就是函数节流。函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流
。
函数节流有哪些应用场景?哪些时候我们需要间隔一定时间触发回调来控制函数调用频率?
- DOM 元素的拖拽功能实现(mousemove)
- 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
- 计算鼠标移动的距离(mousemove)
- Canvas 模拟画板功能(mousemove)
- 搜索联想(keyup)
- 监听滚动事件判断是否到页面底部自动加载更多:给 scroll 加了 debounce 后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle 的话,只要页面滚动就会间隔一段时间判断一次
节流通俗来解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,这个秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴,这,,,好吧这就是我们节流的概念;换成函数来说,使用setTimeout方法,给定两个时间,后面的时间减去前面的时间,到达我们给定的时间就去触发一次这个事件,这么说太笼统的,我们看下面的函数,这里我们以【scroll】为例;
/** 样式我就顺便写了 **/
<style>
*{padding:0;margin:0;}
.scroll-box{
width : 100%;
height : 500px;
background:blue;
overflow : auto;
}
.scroll-item{
height:1000px;
width:100%;
}
</style>
------------------------
/** 先给定DOM结构;**/
<div class="scroll-box">
<div class="scroll-item"></div>
</div>
------------------------
/**主要看js,为了简单我用JQ去写了**/
<script>
$(document).ready(function(){
var scrollBox = $('.scroll-box');
//调用throttle函数,传入相应的方法和规定的时间;
var thro = throttle(throFun,300);
//触发事件;
scrollBox.on('scroll' , function(){
//调用执行函数;
thro();
})
// 封装函数;
function throttle(method,time){
var timer = null;
var startTime = new Date();
return function(){
var context = this;
var endTime = new Date();
var resTime = endTime - startTime;
//判断大于等于我们给的时间采取执行函数;
if(resTime >= time){
method.call(context);
//执行完函数之后重置初始时间,等于最后一次触发的时间
startTime = endTime;
}
}
}
function throFun(){
console.log('success');
}
})
</script>
或
export function throttle(delay, action){
let last = return function(){
let curr = +new Date()
if (curr - last > delay){
action.apply(this, arguments)
last = curr
}
}
}
函数去抖(debounce) 应用场景
写代码之前,我们先清楚一下防抖的概念,不知道大家有没有做过电脑端两边悬浮广告窗口的这么一个东西,当我们拖动滚动条的时候,两边的广告窗口会因为滚动条的拖动,而不断的尝试着去居于中间,然后你就会看到这两个窗口,不停的抖啊抖;
一般这种就叫抖动了,我们要做的就是防止这种抖动,称为防抖[debounce ];
那这里防抖思想就是当我们拖动完成之后,两边的窗口位置再重新去计算,这样,就会显得很平滑,看着很舒服了,最主要的操作DOM结构的次数就大大减少了;
优化了页面性能,降低了内存消耗,不然你像IE这种比较老点版本的浏览器,说不定就直接给你蹦了
用书面一点的说法就是,在某个事件没有结束之前,函数不会执行,当结束之后,我们给定延时时间,然他在给定的延时时间之后再去执行这个函数,这就是防抖函数;
来看代码:
//将上面案例的throttle函数替换为debounce函数;
function debounce(method,time){
var timer = null ;
return function(){
var context = this;
//在函数执行的时候先清除timer定时器;
clearTimeout(timer);
timer = setTimeout(function(){
method.call(context);
},time);
}
}
思路就是在函数执行之前,我们先清除定时器,如果函数一直执行,就会不断的去清除定时器中的方法,知道我们操作结束之后,函数才会执行;
或
export function debounce(func, delay) {
let timer
return function(...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func.apply(this, args)
}, delay)
}
}
用途
- 当我们做keyup像后台请求检验的时候,可以使用防抖函数,不然我们每按一次键盘就请求一次,请求太频繁,这样当我们结束按键盘的时候再去请求,请求少很多了,性能自然不用说;
- resize 窗口大小调整的时候,我们可以采用防抖技术也可以使用节流;
- mousemove 鼠标移动事件我们既可以采用防抖也可以使用节流;
- scroll 滚动条触发的事件,当然既可以采用防抖也可以采用节流;
- 连续高频发的事件都可以采用这两种方式去解决,优化页面性能;
具体的采用哪一种更较为合适,主要还是看你的业务需求
区分
节流说白了就是每ms执行一次函数,防抖就是 最后一次触发后ms后执行一次回调函数。
节流就是拧紧水龙头,让水滴一滴一滴流,而去抖则是按压一个弹簧,不松手则弹簧不会触发函数节流和去抖都是限制基于DOM事件执行的javascript数量的方法,都是为了提高JS性能,但是两者是有区别的。
推荐阅读
函数节流和去抖之间的区别
本小节引用
avaScript 函数节流...
JavaScript 高级系列...
3.img宽高一样,border-radius: 50%,为什么不是正圆
这个是网上一个网友提的问题,自己未曾遇到也为实验,先保存在这
源代码:
<div>
<img style="width: 60px;height:60px;border-radius: 50%" src="~@/asset/person.jpg">
</div>
原因:
图片的比例不是1:1(图片纵横比不为1)
解决方法:(待验证)
<img width="60" height="60" style="border-radius: 50%" src="~@/asset/person.jpg">
或
border-radius:100%
4.如何优雅的实现金钱格式化:1234567890 --> 1,234,567,890
用正则魔法实现:
var test1 = '1234567890'
var format = test1.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
console.log(format) // 1,234,567,890
非正则的优雅实现:
function formatCash(str) {
return str.split('').reverse().reduce((prev, next, index) => {
return ((index % 3) ? next : (next + ',')) + prev
})
}
console.log(formatCash('1234567890')) // 1,234,567,890
5.如何最佳的让两个整数交换数值
常规办法:
var a=1,b=2;
a += b;
b = a - b;
a -= b;
缺点也很明显,整型数据溢出,对于32位字符最大表示数字是2147483647,如果是2147483645和2147483646交换就失败了。
黑科技办法:
a ^= b;
b ^= a;
a ^= b;
es6:
[b,a] = [a,b]
6.实现标准JSON的深拷贝
var a = {
a: 1,
b: { c: 1, d: 2 }
}
var b=JSON.parse(JSON.stringify(a))
不考虑IE的情况下,标准JSON格式的对象蛮实用,不过对于undefined和function的会忽略掉。
7.在str前添加一个➕号,+str会强制转Number
不用Number、parseInt和parseFloat和方法把"88"
字符串转换成数字
var str="88";
console.log(+str) // 88
//或者
console.log(str - 0) // 88
//但是如果是混合类型的字符串,则会转为NaN
var b="1606e";
console.log(+b) // NaN
8.数组去重
方法1:最短的代码实现es6
[...new Set([1, "1", 2, 1, 1, 3])]
function uniqueArray(arr){
return Array.from(new Set(arr));
}
方法2:使用filter + indexOf
如下代码所示:
removeRepeatArray(arr) {
return arr.filter(function (item, index, self) {
return self.indexOf(item) === index;
});
}
方法3:使用splice
如下代码所示:
function uniqueArray(arr){
for(var i = 0; i < arr.length - 1; i++){
for(var j = i + 1; j < arr.length; j++){
if(arr[j] === arr[i]){
arr.splice(j--, 1);
}
}
}
return arr;
}
方法4:只用Array
如下代码所示:
function uniqueArray(arr){
var retArray = [];
for(var i = 0; i < arr.length; i++){
if(retArray.indexOf(arr[i]) < 0){
retArray.push(arr[i]);
}
}
return retArray;
}
方法5:Object.keys(对象)
let a = ['1', '2', '3', 1,NaN,NaN,undefined,undefined,null,null, 'a', 'b', 'b'];
const unique = arr => {
var obj = {}
arr.forEach(value => {
obj[value] = 0;//这步新添加一个属性,并赋值,如果不赋值的话,属性会添加不上去
})
return Object.keys(obj);//`Object.keys(对象)`返回这个对象可枚举属性组成的数组,这个数组就是去重后的数组
}
console.log(unique(a));//["1", "2", "3", "NaN", "undefined", "null", "a", "b"]
注意:
这个方法会将 number,NaN,undefined,null,变为字符串形式,因为对象的属性名就是一个字符串
9.用最短的代码实现一个长度为m(6)且值都n(8)的数组
Array(6).fill(8)
10.取出一个数组中的最大值和最小值
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(Math, numbers); // 或 Math.max(...arr)
var minInNumbers = Math.min.apply(Math, numbers); // 或 Math.min(...arr)
11.将argruments对象转换成数组
var argArray = Array.prototype.slice.call(arguments);
或者ES6:
var argArray = Array.from(arguments)
12.短路表达式
条件判断
var a = b && 1
// 相当于
if (b) {
a = 1
} else {
a = b
}
var a = b || 1
// 相当于
if (b) {
a = b
} else {
a = 1
}
13.RGB to Hex
function toHEX(rgb){
return ((1<<24) + (rgb.r<<16) + (rgb.g<<8) + rgb.b).toString(16).substr(1);
}
14.JSON.stringify()妙用
1 语法
JSON.stringify(value[, replacer[, space]])
一般用法:
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user);
"{"name":"andy","isDead":false,"age":11,"addr":"shanghai"}"
2 扩展用法
2.1 replacer
replacer可以是函数或者是数组。
功能1: 改变属性值
将isDead属性的值翻译成0或1,0对应false,1对应true
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, function(key, value){
if(key === 'isDead'){
return value === true ? 1 : 0;
}
return value;
});
//"{"name":"andy","isDead":0,"age":11,"addr":"shanghai"}"
功能2:删除某个属性
将isDead属性删除,如果replacer的返回值是undefined,那么该属性会被删除。
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, function(key, value){
if(key === 'isDead'){
return undefined;
}
return value;
});
//"{"name":"andy","age":11,"addr":"shanghai"}"
功能3: 通过数组过滤某些属性
只需要name属性和addr属性,其他不要。
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, ['name', 'addr']);
//"{"name":"andy","addr":"shanghai"}"
2.2 space
space可以是数字或者是字符串, 如果是数字则表示属性名前加上空格符号的数量,如果是字符串,则直接在属性名前加上该字符串。
功能1: 给输出属性前加上n个空格
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, null, 4);
"{
"name": "andy",
"isDead": false,
"age": 11,
"addr": "shanghai"
}"
功能2: tab格式化输出
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, null, '\t');
"{
"name": "andy",
"isDead": false,
"age": 11,
"addr": "shanghai"
}"
功能3: 搞笑
JSON.stringify(user, null, 'good');
"{
good"name": "andy",
good"isDead": false,
good"age": 11,
good"addr": "shanghai"
}"
2.3 深拷贝
var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
var temp = JSON.stringify(user);
var user2 = JSON.parse(temp);
3 其他JSON.parse()
其实也是支持第二个参数的。功能类似于JSON.stringify
的第二个参数的功能。
15.获取jquery版本号
console.log('$',$.fn.jquery)
//$ 3.2.1
16.img异步加载图片
在开发中,我们经常有异步加载图片的请求,然后在图片加载成功后做一些操作,一般我们通过onload方法来实现.网上有两种写法,大家可以先看一下(注:logo.jpg是张本地图片):
例子1:
var img = new Image();
img.src = "logo.jpg";
img.onload = function () {
alert("image is loaded");
};
document.body.appendChild(img);
例子2:
var img = new Image();
img.onload = function () {
alert("image is loaded");
};
img.src = "logo.jpg";
document.body.appendChild(img);
发现什么了没有?上面两个例子最大的差别就在于onload和src赋值的先后顺序.那么onload和src赋值的先后顺序会在实际中产生什么差别呢?
产生这个问题的原因很简单,就是因为logo.jpg是本地图片,导致浏览器加载起来非常快,几乎在给img赋值src的时候,图片就已经加载完成,同时触发了onload事件,代码中为onload赋值的语句就相当于在onload事件发生后,这时候已经晚了.
将src写到了onload的前面,会导致onload来不及赋值就被执行了,所以正确的写法应该是第2个例子.既在给图片分配地址前,先绑定好它的onload事件,这样就不用担心错过时机的问题了.
正确的例子:
var img = new Image();
// 如果文档装入完成后加载用window load
//window.addEventListener("load" , function(){
// document.body.appendChild(img);
//} , false);
// 如果图片加载完毕用 img load
img.addEventListener('load', function(){
document.body.appendChild(img);
} , false);
img.src = 'test.png';
17.几个常用的console用法
1.console.log(): 进行标准输出流的输出(stdout)
console.group('mounted 挂载结束状态===============》');
console.log("%c%s", "color:green","data : " + this.$data)
2.console.error(): 进行标准错误流的输出用法与console.log()一样.
3.console.dir(): 查看一个对象的内容,并把对象信息输出到控制台.
// a.js
var person = {
age: 38,
name: 'kobe',
job: function(){
return 'player'
}
};
console.log(person);
// node a.js
{ age: 38, name: 'kobe', job: [Function: job] }
4.console.time()与console.timeEnd() : 可以用来统计一段代码的执行时间
// a.js
console.time('loop');
for(var i =0;i < 10000;i++){
;
}
console.timeEnd('loop');
// node a.js
loop: 0.283ms
好玩的console.log()
console.log("%c3"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:6em;line-height:60px;")
console.log("%c2"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:4em;line-height:60px;")
console.log("%c1"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:2em;line-height:60px;")
console.log('%c南京热还是东京热.', 'color: #fff; background: #f40; font-size: 24px;border-radius:0 15px 15px 0;padding:10px;');
console.log("%c ","background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;width:1px;height:40px;padding:2px;")
console.log("%c 热 热 热", "color:red;font-size:30px;font-weight:bolder;padding:50px 420px;line-height:10px;background:url('http://img.zcool.cn/community/0127c0577e00620000012e7e12da0e.gif') repeat-x;background-size:contain;");
18. !!强制转布尔值boolean
根据当前需要判断的值是真值还是假值来判断,真值返回true,假肢返回false,那么这样的话,除了假值,剩下的也都是真值了。
假值有:0 、 “” 、 null 、 undefined 、 false 、NaN
除了这 6 个外,其它均为“真” ,包括对象、数组、正则、函数等。
注意: '0'、'null'、'false'、{}、[]也都是真值 。
那么下面我们来看看!!是如何转布尔值的。
例如:
首先我们声明3个变量,x为null,y为空字符串,str为字符串,下面看看他们添加了"!!"后会有什么结果。
var x=null;
var y="";
var str="abcd";
console.log(!!x) // false;
console.log(!!y) // false;
console.log(!!str) // true;
如上所说,假值返回false,真值返回true。
19. 不可靠的undefined 可靠的void 0
在JavaScript中,假设我们想判断一个是否是 undefined,那么我们通常会这样写:
if(a === undefined){
dosomething.....
}
因为在javascript中,undefined是不可靠的
例如:
当undefined被放在在function函数内,我们把它当成一个局部变量,它是可以赋上值的,下面我们来试试。
function foo2(){
var undefined=1;
console.log(undefined)
}
foo2(); // 1;
但是当在函数内定义一个全局变量,并不能给赋上值
var undefined;
function foo2(){
undefined=1;
console.log(undefined)
}
foo2() // undefined
那么我们试试用void 0或者 void (0)来代替:
先声明一个变量a,赋值为undefined,接下来我们用void 0来判断一下。
var a=undefined;
//用void 0来判断一下
if(a===void 0){
console.log('true')
} // true
//再用void (0)来判断一下
if(a===void (0)){
console.log('true')
} // true
//最后我们打印一下这两个的返回值
console.log(void 0,void (0)) // undefined undefined
我们现在可以通过void 0 运算来获得 undefined;那在以后需要判断值为undefined的时候,可以直接用void 0或者void (0),而且这两个值的直接返回值就是undefined,所以说非常可靠哦!
20.用typeof来判断对象的潜在陷阱
问:使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱?
尽管 typeof bar === "object" 是检查 bar 是否对象的可靠方法,令人惊讶的是在JavaScript中 null 也被认为是对象!
因此,令大多数开发人员惊讶的是,下面的代码将输出 true 控制台:
var bar = null;
console.log(typeof bar === "object");
// logs true!
只要清楚这一点,同时检查 bar 是否为 null,就可以很容易地避免问题:
console.log(
(bar !== null) && (typeof bar === "object")
);
// logs false
要答全问题,还有其他两件事情值得注意:
首先,上述解决方案将返回 false,当 bar 是一个函数的时候。在大多数情况下,这是期望行为,但当你也想对函数返回 true 的话,你可以修改上面的解决方案为:
console.log(
(bar !== null) && ((typeof bar === "object") || (typeof bar === "function"))
);
第二,上述解决方案将返回 true,当 bar 是一个数组(例如,当 var bar = [];)的时候。
在大多数情况下,这是期望行为,因为数组是真正的对象,但当你也想对数组返回 false 时,你可以修改上面的解决方案为:
console.log(
(bar !== null)&& (typeof bar === "object") && (toString.call(bar) !== "[object Array]")
);
或者,如果你使用jQuery的话:
console.log(
(bar !== null)&& (typeof bar === "object") && (! $.isArray(bar))
);
或者 数组和函数返回false,但对于对象则为true:
console.log((bar !== null) && (bar.constructor === Object));
参考:
1.这些JavaScript编程黑科技...
2.图片的异步加载与onload函数
3.原生js的常用方法整理
4.ec-do-2.0.0.js
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。