JavaScript编码习惯和技巧

JavaScript编码习惯和技巧

运用 || 和&&运算符

1
2
3
var foo = 10;
foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething();
foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething();

运用 | 运算符

在js整数操作的时候,相当于去除小数点(取整),parseInt。在正数的时候相当于Math.floor(),负数的时候相当于Math.ceil() [REF]

1
2
3
4
5
6
7
8
9
Math.ceil()  用作向上取整。
Math.floor() 用作向下取整。
Math.round() 我们数学中常用到的四舍五入取整。

console.log(0.6|0)//0
console.log(1.1|0)//1
console.log(3.65555|0)//3
console.log(5.99999|0)//5
console.log(-7.777|0)//-7

同理有:

1
2
3
n<<0
n>>0
~~n

用map遍历处理数组

1
2
3
4
var squares = [1,2,3,4].map(function (val) {
return val * val;
});
// squares will be equal to [1, 4, 9, 16]

浮点数处理

1
2
var num = 2.443242342;
num = num.toFixed(4); // num will be equal to 2.4432
1
2
3
4
5
6
0.1 + 0.2 === 0.3 // is false, 0.30000000000000004 instead.
9007199254740992 + 1 // is equal to 9007199254740992
9007199254740992 + 2 // is equal to 9007199254740994

//use toFixed() or toPrecision() to solve this problem
//NOTE : the toFixed() and toPrecision() function returns a string, not a number.

用'==='而不是'=='

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[10] === 10    // is false
[10] == 10 // is true
'10' == 10 // is true
'10' === 10 // is false
[] == 0 // is true
[] === 0 // is false
'' == false // is true but true == "a" is false
'' === false // is false

"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true

有趣的现象: "" == "0" 且 0 == "0",但是 "" == 0 为false,当然这是js隐式转换的问题

布尔型转换

通过使用 否 操作符两次,可以把一个值转换为布尔型。

1
2
3
4
5
6
7
!!'foo';   // true
!!''; // false
!!'0'; // true
!!'1'; // true
!!'-1' // true
!!{}; // true
!!true; // true

用switch处理判断(true/false)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getCategory(age) {
var category = "";
switch (true) {
case isNaN(age):
category = "not an age";
break;
case (age >= 50):
category = "Old";
break;
case (age <= 20):
category = "Baby";
break;
default:
category = "Young";
break;
};
return category;
}
getCategory(5); // will return "Baby"

尽量用原生表达式而不是函数调用

1
2
3
4
5
6
7
var min = Math.min(a,b);
A.push(v);

//below is better

var min = a < b ? a : b;
A[A.length] = v;

数组连接

1
2
3
4
5
6
7
8
var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];

// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']

将arguments转换为数组

1
var argArray = Array.prototype.slice.call(arguments);

判断是否为数组

1
2
3
4
5
6
7
function isArray(obj){
return Object.prototype.toString.call(obj) === '[object Array]' ;
}

// or use...

Array.isArray(obj); // its a new Array method

判断是否为数字

1
2
3
function isNumber(n){
return !isNaN(parseFloat(n)) && isFinite(n);
}

打散字符串为单个字符(数组)

1
str.split('');

创建自调用函数

1
2
3
4
5
6
7
(function(){
// some private code that will be executed automatically
})();
(function(a,b){
var result = a + b;
return result;
})(10, 20)

随机获取数组中元素

1
2
var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];
var randomItem = items[Math.floor(Math.random() * items.length)];

生成固定范围内的数组

1
2
3
var numbersArray = [], max = 100;

for( var i=1; numbersArray.push(i++) < max;); // numbersArray = [1,2,3 ... 100]

打乱数组顺序

1
2
3
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
numbers = numbers.sort(function(){ return Math.random() - 0.5});
/* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205] */

取得数组中最大或最小值

1
2
3
var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
var maxInNumbers = Math.max.apply(null, numbers);
var minInNumbers = Math.min.apply(null, numbers);

不要用delete删除数组中的元素

1
2
3
4
5
6
7
8
9
10
11
12
var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
delete items[3]; // return true
items.length; // return 11
/* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */
// below is better

var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ];
items.length; // return 11
items.splice(3,1) ;
items.length; // return 10
/* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */

缩减数组

1
2
3
var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ];
myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124].
//The array length is not a read only property.

去除字符串前后空白

1
2
3
4
5
6
7
//如果浏览器本身不支持String对象的trim方法,那么运行下面的代码可以兼容这些环境.

if(!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g,'');
};
}

注意区分布尔值true/false 与 布尔对象的值true/false

1
2
3
var b = new Boolean(false);
if (b) // this condition evaluates to true
// NOTE:

[闭包]利用闭包模拟私有方法

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
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
alert(Counter1.value()); /* 提示 0 */
Counter1.increment();
Counter1.increment();
alert(Counter1.value()); /* 提示 2 */
Counter1.decrement();
alert(Counter1.value()); /* 提示 1 */
alert(Counter2.value()); /* 提示 0 */

数组排序函数

1
2
3
list.sort(function(a, b) {
return +(a.value > b.value) || +(a.value === b.value) - 1;
});

将数组所有项累加

1
2
3
4
var total = [0, 1, 2, 3].reduce(function(a, b) {
return a + b;
});
// total == 6

数组扁平化

1
2
3
4
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
return a.concat(b);
});
// flattened is [0, 1, 2, 3, 4, 5]

点击其他(空白)地方执行操作,如关闭等

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
$(document).on('click', function(e){
var tarExts = [
$ele1,
$ele2
];

for (var i = 0, l = tarExts.length; i < l; i++) {
if (tarExts[i].is(e.target) || tarExts[i].has(e.target).length !== 0) {
return;
}
}

//do something when click on others
});

//封装后

function attachBlankTap(targetsExcluded, callback){
var tarExts = targetsExcluded;
// convert to jQuery object
if ($.isArray(tarExts)) {
for (var i = 0, l = tarExts.length; i < l; i++) {
if ('string' === typeof tarExts[i] || ('object' === typeof tarExts[i] && !tarExts[i] instanceof jQuery))
tarExts[i] = $(tarExts[i]);
}
} else if ('string' === typeof tarExts || ('object' === typeof tarExts && !tarExts instanceof jQuery)) {
tarExts = [ $(tarExts) ];
}
//add event
$(document).on('click', function(e){
if ($.isArray(tarExts)) {
for (var j = 0, m = tarExts.length; j < m; j++) {
if (tarExts[j].is(e.target) || tarExts[j].has(e.target).length !== 0) {
return;
}
}
}
//do something when click on others
if (callback && 'function' === typeof callback) callback();
});
}

复制对象

1
2
3
4
5
6
7
8
9
10
Object.prototype.clone = function(){
var copy;
copy = this.constructor == Object ? new this.constructor() : new this.constructor(this.valueOf());
for(var key in this){
if(copy[key] != this[key]){
copy[key] = 'object' === this[key] ? this[key].clone() : this[key];
}
}
return copy;
}

Firefox下设置或获取scrollTop需特定写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getScrollXY(){
var x,y;
if(document.body.scrollTop){ //非标准写法,chrome能识别
x = document.body.scrollLeft;
y = document.body.scrollTop;
} else { //标准写法
x = document.documentElement.scrollLeft;
y = document.documentElement.scrollTop;
}
return {x:x, y:y};
}

//jQuery写法
$("html, body").scrollTop()

时间

1
2
//获取时间数值
+new Date()

关闭打开窗口

1
2
3
4
5
6
7
8
9
var browserName = navigator.appName;
if (browserName == "Netscape") {
window.open('', '_self', '');
window.close();
} else if (browserName == "Microsoft Internet Explorer") {
window.opener = null;
window.open('', '_top');
window.top.close();
}

Sibling elements

1
2
3
4
5
6
7
// jQuery
$el.siblings();

// Native
[].filter.call(el.parentNode.children, function(child) {
return child !== el;
});

Iframe Contents

1
2
3
4
5
// jQuery
$iframe.contents();

// Native
iframe.contentDocument;

Get style

1
2
3
4
5
6
7
8
// jQuery
$el.css("color");

// Native
// NOTE: Known bug, will return 'auto' if style value is 'auto'
const win = el.ownerDocument.defaultView;
// null means not return pseudo styles
win.getComputedStyle(el, null).color;

DOM - remove

1
2
3
4
5
// jQuery
$el.remove();

// Native
el.parentNode.removeChild(el);

创建重复字符串

1
2
3
var count = 3;
var stringToRepeat = 'a';
var repeatStr = new Array(count + 1).join(stringToRepeat); // aaa

& (按位与)

1
2
3
4
// 判断一个数是否为2的n次幂,可以将其与自身减一相与

var number = 4
(number & number -1) === 0 // true

^ (按位异或)

1
2
3
4
5
6
7
// 不用第三个变量,就可以交换两个变量的值
var a = 4,
b = 3;

a = a ^ b; // 7
b = a ^ b; // 4
a = a ^ b; // 3

Object.prototype.toString()

在toString()方法被调用时,会执行下面的操作步骤:

如果this的值为undefined,则返回"[object Undefined]". 如果this的值为null,则返回"[object Null]". 让O成为调用ToObject(this)的结果. 让class成为O的内部属性[[Class]]的值. 返回三个字符串"[object ", class, 以及 "]"连接后的新字符串.

由于 JavaScript 中一切都是对象,任何都不例外,对所有值类型应用Object.prototype.toString.call()

方法结果如下:

1
2
3
4
5
6
7
console.log(Object.prototype.toString.call(123));          //[object Number]
console.log(Object.prototype.toString.call('123')); //[object String]
console.log(Object.prototype.toString.call(undefined)); //[object Undefined]
console.log(Object.prototype.toString.call(true)); //[object Boolean]
console.log(Object.prototype.toString.call({})); //[object Object]
console.log(Object.prototype.toString.call([])); //[object Array]
console.log(Object.prototype.toString.call(function(){})); //[object Function]

所有类型都会得到不同的字符串,几乎完美。 在JavaScript中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过 Object.prototype.toString() 方法.

判断对象是否为空对象,即不包含任何原始属性

1
2
3
4
5
6
function isEmpty(obj){
for (var p in obj) {
return false;
}
return true;
}

显示网页所有元素轮廓

控制台中输入:

1
[].forEach.call($$("*"),function(a){ a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16) })

利用a标签自动解析URL

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
function parseURL(url) {
var a = document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':', ''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function () {
var ret = {},
seg = a.search.replace(/^\?/, '').split('&'),
len = seg.length, i = 0, s;
for (; i < len; i++) {
if (!seg[i]) {
continue;
}
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [, ''])[1],
hash: a.hash.replace('#', ''),
path: a.pathname.replace(/^([^\/])/, '/$1'),
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [, ''])[1],
segments: a.pathname.replace(/^\//, '').split('/')
};
}

参考: Parsing URLs with the DOM!

利用toString()方法生成随机字符串

1
2
3
4
5
function generateRandomAlphaNum(len) {
var rdmString = "";
for (; rdmString.length < len; rdmString += Math.random().toString(36).substr(2));
return rdmString.substr(0, len);
}

禁止别人以iframe加载你的页面

1
if (window.location != window.parent.location) window.parent.location = window.location;

参考

45 useful javascript tips tricks and best practices You Don't Need jQuery JavaScript 秘密花园 盘点JavaScript里好用的原生API ꒰・◡・๑꒱ 关于原生js的一些研究

晓月风尘 wechat
扫描二维码与我相识
你我共同创造价值,记得支持一下哦~