Javascript 代码片段笔记

千位分隔符

1
2
3
4
5
6
7
8
9
10
11
12
function commafy(num) {
num = num + '';
var reg = /(-?\d+)(\d{3})/;
while(reg.test(num)) {
num = num.replace(reg, '$1,$2');
}
return num;
}

jQuery 实现简单 Router

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
(function($) {
var pathname = location.pathname;
$.route = function() {
$.each(arguments, function(index) {
var path = this["path"];
var func = this["func"];
if(path && func) {
if(pathname.match(path)) {
$(function() {
func.apply(this);
});
}
}
});
};
})(jQuery);
// Example
$.route(
{
// always match
// http://example.com/foo/bar/baz.html
path: /./,
func: function() {
console.log("always match!");
}
},
{
// url contains /sample/index.html
// http://example.com/foo/bar/sample/index.html
path: /\/sample\/index\.html/,
func: function() {
console.log("sample page!");
}
}
);

中文输入法截断解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 利用 compositionstart 和 compositionend 来捕获 IME (input method editor) 的启动和关闭事件
$('#text').on('input', function(e){
if($(this).prop('comStart')) return;
var value = $(this).val();
console.log('当前输入:' + value);
// ....
})
.on('compositionstart', function(e){
$(this).prop('comStart', true);
console.log('中文输入,开始');
})
.on('compositionend', function(e){
$(this).prop('comStart', false);
console.log('中文输入,结束');
});

jQuery pub/sub 简单实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(function($) {
var o = $({});
$.subscribe = function() {
o.on.apply(o, arguments);
};
$.unsubscribe = function() {
o.off.apply(o, arguments);
};
$.publish = function() {
o.trigger.apply(o, arguments);
};
}(jQuery));

观察者模式

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
var eventSplitter = /\s+/;
var Events = {
/**
* _callback = {
* tail: [Object],
* next: {
* callback: [Function],
* context: [Object],
* next: {
* callback: [Function],
* context: [Object],
* next: [Object]
* }
* }
* }
*
* 1. 事件列表最顶层存储了一个 tail 对象,它是最后一次绑定的回调事件的 next 的引用;
* 2. evts 允许指定多个事件名,通过空白字符进行分隔(如空格, 制表符等);
* 3. 当事件名称为"all"时, 在调用 fire 方法触发任何事件时,
* 均会调用"all"事件中绑定的所有回调函数;
*/
on: function(evts, callback, context) {
var evt, calls, node, tail, list;
if(!callback) return this;
evts = evts.split(eventSpliter);
calls = this._callbacks || (this._callbacks = {});
while(evt = evts.shift()) {
list = calls[evt];
node = list ? list.tail : {};
node.next = tail = {};
node.callback = callback;
node.context = context;
calls[evt] = {
tail: tail,
next: list ? list.next : node;
}
}
return this;
},
off: function(evts, callback, context) {
var evt, calls, node, tail, cb, ctx;
if(!(calls = this._callbacks)) return this;
if(!(evts || callback || context)) {
delete this._callbacks;
return this;
}
evts = evts ? evts.split(eventSpliter) : Object.key(calls);
while(evt = evts.shift()) {
node = calls[evt];
delete calls[evt];
if(!node || !(callback || context)) continue;
tail = node.tail;
while((node = node.next) !== tail) {
cb = node.callback;
ctx = node.context;
if((callback && cb !== callback) || (context && ctx !== context)) {
this.on(evt, cb, ctx);
}
}
}
return this;
},
fire: function(evts) {
var evt, node, calls, tail, args, all, rest;
if(!(calls = this._callbacks)) return this;
all = calls.all;
evts = evts.split(eventSpliter);
rest = Array.prototype.slice.call(arguments, 1);
while(evt = evts.shift()) {
if(node = calls[evt]) {
tail = node.tail;
while((node = node.next) !== tail) {
node.callback.apply(node.context || this, rest);
}
}
if(node = all) {
tail = node.tail;
args = [evt].concat(rest);
while((node = node.next) !== tail) {
node.callback.apply(node.context || this, args);
}
}
}
return this;
}
}

短小强悍的 Javascript 异步调用库

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
var queue = function(funcs, scope) {
(function next() {
if(funcs.length > 0) {
funcs.shift().apply(scope, [next].concat(Array.prototype.slice.call(arguments, 0)));
}
})();
}
// Example
var obj = { value: null };
queue([
function(callback){
var me = this;
setTimeout(function(){
me.value = 10;
callback(20);
});
},
function(callback, add){
console.log(this.value + add);
callback();
},
function(){
console.log(obj.value);
}
], obj);

干掉鼠标右键菜单

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
function NoRightClick(pid) { // pid: flash's parentNode id
var el = document.getElementById(pid);
if(el.addEventListener) {
el.addEventListener('mousedown',function(event){
if(event.button == 2){
event.stopPropagation(); // for firefox
event.preventDefault(); // for chrome
}
},true);
}
else {
el.attachEvent('onmousedown', function() {
if(event.button == 2) {
el.setCapture();
}
});
el.attachEvent('onmouseup', function() {
el.releaseCapture();
});
el.oncontextmenu = function() {
return false;
};
}
};

判断是否是素数

function isPrime(num) {
    return n < 2 ? false : !/^(11+?)\1+$/.test(Array(num+1).join(1));
}

Babel 的 polyfill 和 runtime 的区别

  • babel-plugin-transform-runtime: 适用于 JavaScript 库和工具包的实现,避免 babel 编译的工具函数在每个模块里重复出现,减小库和工具包的体积

  • babel-polyfill: 转译 javascript 新的对象和方法,为当前环境提供一个垫片

总结:

  • 具体项目还是需要使用 babel-polyfill,只使用 babel-runtime 的话,实例方法不能正常工作(例如 “foobar”.includes(“foo”))

  • JavaScript 库和工具可以使用 babel-runtime,在实际项目中使用这些库和工具,需要该项目本身提供 polyfill