不定期更新 JavaScript技巧

JavaScript技巧,偶尔更新。

计算数组的极值

1
2
3
4
5
6
7
8
9
10
11
function smallest(array){
return Math.min.apply(Math, array);
}
function largest(array){
return Math.max.apply(Math, array);
}
smallest([0, 1, 2.2, 3.3]); // 0
largest([0, 1, 2.2, 3.3]); // 3.3

数组排序

1
2
3
4
5
6
7
[14.3, 8, 1, 64].sort(function(a, b) {
return a - b;
});
//[1, 8, 14.3, 64]
//从大到小排序就是 b - a

迭代arguments

1
2
3
4
5
6
7
8
9
10
11
function useCall() {
[].forEach.call(arguments, function(val, key) {
console.log(key, val)
});
}
useCall('Bob Dylan', 'Bob Marley', 'Steve Vai');
//0 "Bob Dylan"
//1 "Bob Marley"
//2 "Steve Vai"

将arguments转为数组

1
2
3
function transformToArray(arg){
return Array.prototype.slice.call(arg);
}

Array.prototype.forEach()第二个参数

参考:MDN

1
2
3
4
5
6
7
8
9
10
var coder = {
name: 'Freak',
friends: ['Rocky', 'Bob'],
logHiToFriends:function(){
'use static'
this.friends.forEach(function(friend){
console.log(this.name+ ' say hi to '+ friend);
},this)//注意这个this,如果不添加这个参数,你可以猜测会发生什么
}
}

随机生成字母和数字组合的字符串

1
2
3
4
Math.random().toString(36).substr(2);
//un80usvvsgcpi0rffskf39pb9
//02aoe605zgg5xqup6fdclnb3xr
//ydzr1swdxjg3yolkb95p14i

使用IIFE解决循环问题

unexpected:

1
2
3
4
5
6
7
8
9
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}
funcs.forEach(function(func) {
func(); // 输出数值 "10" 十次
});

expected:

1
2
3
4
5
6
7
8
9
10
11
12
13
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
funcs.forEach(function(func) {
func(); // 从 0 到 9 依次输出
});

使用let解决循环问题

这是let独有的特性(参考)

1
2
3
4
5
6
7
8
9
10
11
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 从 0 到 9 依次输出
})

判断两个小数是否相等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//因为javascript数字通常被输入为十进制的浮点数,但内部却被表示为二进制,所以计算结果会有偏差:
0.1 + 0.2 //0.30000000000000004
0.1 + 1 - 1 //0.10000000000000009
0.1 + 0.2 === 0.3 //false
//所以我们不应该直接比较非整数,而是取其上限,把误差计算进去
//这样一个上限称为 machine epsilon,双精度的标准epsilon值是2^-53
const EPSILON = Math.pow(2, -53); //1.1102230246251565e-16
function epsEqu(x,y) {
return Math.abs(x - y) < EPSILON;
}
epsEqu(0.1+0.2, 0.3) //true

Math.round函数的坑

1
2
3
4
5
6
7
8
Math.round(-3.2) //-3
Math.round(-3.5) //-3(这个就奇怪了)
Math.round(-3.8) //-4
//其实,Math.round(x)等同于:
Math.floor(x + 0.5)

巧用||和&&

1
2
3
4
5
var bar = $ || 233;
//如果$存在,则把$赋值给bar;如果$不存在,则把233赋值给bar
$ === undefined && (window.$ = jQuery);
//如果$不存在,则把jQuery赋值给window.$;如果$存在,则不执行后面的表达式

使用break + labels退出循环

1
2
3
4
5
6
7
8
9
10
11
12
function findNumber(arr){
loop:{
for (var i = 0; i < arr.length; i++) {
if(arr[i]%2 == 0){
break loop;//表示退出loop区块
}
}
console.log(arr);//这句代码是不会执行的,如果上面只是break,for循环之后的代码还是会执行
}
}
findNumber([1,3,5,6]);

简单实现合并对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function merge(root){
for (var i = 1; i < arguments.length; i++) {
for (var key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
root[key] = arguments[i][key];
}
}
}
return root;
}
var merged = merge(
{name:'Freak'},
{city:'Shenzhen'}
)//{name:'Freak',city:'Shenzhen'}

理解map和parseInt

1
2
3
4
5
['1','2','3'].map(parseInt);
//[1, NaN, NaN]
['1','2','3'].map(function(x){return parseInt(x,10)});
//[1, 2, 3]

上传图片预览功能

1
2
<input type="file" name="file" onchange="showPreview(this)" />
<img id="portrait" src="" width="70" height="75">
1
2
3
4
5
6
7
8
9
10
function showPreview(source) {
var file = source.files[0];
if(window.FileReader) {
var fr = new FileReader();
fr.onloadend = function(e) {
document.getElementById("portrait").src = e.target.result;
};
fr.readAsDataURL(file);
}
}

微信内部修改document.title

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function setTitle(title) {
document.title = title;
if (/ip(hone|od|ad)/i.test(navigator.userAgent)) {
var i = document.createElement('iframe');
i.src = '/favicon.ico';
i.style.display = 'none';
i.onload = function() {
setTimeout(function(){
i.remove();
}, 9)
}
document.body.appendChild(i);
}
}
setTitle("要修改的标题");

快速克隆一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var Rocker = function(name, age){
this.name = name,
this.age = age
}
var Freak = new Rocker('Freak', 24);
Freak.age = 99;
var cloneFreak = Object.create(Freak);
cloneFreak.name // "Freak"
cloneFreak.age // 99
//在不支持ES5的浏览器下,实现create方法如下:
Object.create = Object.create || function(obj){
var F = function(){};
F.prototype = obj;
return new F();
}

判断一个值是否是对象

1
2
3
4
5
6
function isObject(value){
return value === Object(value);
}
isObject({}); // true
isObject(123); // false

为构造器模拟apply功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if(!Function.prototype.construct){
Function.prototype.construct = function(argArray){
if(!Array.isArray(argArray)){
throw new TypeError("Arguments must be an array");
}
var constr = this;
var nullaryFunc = Function.prototype.bind.apply(
constr,[null].concat(argArray));
return new nullaryFunc();
}
}
//使用:
Date.construct([2017, 02, 14]); // Tue Mar 14 2017 00:00:00 GMT+0800 (CST)

防止高频调用的debounce函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//immediate参数判断是否立即执行
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if(!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if(callNow) func.apply(context, args);
};
};
//使用
var myEfficientFn = debounce(function() {
//你要做的事
}, 250);
window.addEventListener('resize', myEfficientFn);

设定时间/频率循环检测函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function poll(fn, callback, err, timeout, interval) {
var startTime = (new Date()).getTime();
var pi = window.setInterval(function() {
if(Math.floor(((new Date()).getTime() - startTime) / 1000) <= timeout) {
if(fn()) {
callback();
}
} else {
window.clearInterval(pi);
err();
}
}, interval)
}

禁止重复调用、只允许执行一次的once 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
}
}
//使用
var canOnlyFireOnce = once(function() {
console.log('只触发一次!');
})
canOnlyFireOnce(); // "只触发一次"
canOnlyFireOnce(); // undefined

获取一个链接的绝对地址

1
2
3
4
5
6
7
8
9
10
11
12
13
var getAbsoluteUrl = (function() {
var a;
return function(url) {
if(!a) a = document.createElement('a');
a.href = url;
return a.href;
};
})();
//使用
getAbsoluteUrl("/something"); //https://rockjins.github.io/something

uncurring实现方法之一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function.prototype.uncurring = function() {
var self = this;
return function() {
var obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
};
};
//使用
var push = Array.prototype.push.uncurring();
(function() {
push(arguments, 4);
console.log(arguments); //输出:[1, 2, 3, 4]
})(1, 2, 3)

本文作者:余震(Freak)
本文出处:Rockjins Blog
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN许可协议。转载请注明出处!

坚持,您的支持将鼓励我继续爬下去!