0%

题目是这样的,啤酒2块钱一瓶,2个空瓶子或者4个瓶盖可以换一瓶新的,如果手上有10元钱,可以喝多少瓶啤酒。写了个 JS 脚本来计算,代码如下(demo):

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
var changing = function(money, price){
var count = parseInt(money/price),
bottle = count,
lid = count,
lidRate = 4,
bottleRate = 2;
(function change(){
// 兑换盖子
if(lid >= lidRate){
var lGet = parseInt(lid/lidRate);
count += lGet;
bottle += lGet;
lid -= lGet*(lidRate-1);
console.log('使用瓶盖'+ lGet*lidRate +'个,兑换:'+ lGet +'瓶');
console.log('已喝:'+ count + ', 剩余瓶盖:'+ lid +', 剩余空瓶:'+ bottle);
}
// 兑换空瓶
if(bottle >= bottleRate){
var bGet = parseInt(bottle/bottleRate);
count += bGet;
bottle -= bGet;
lid += bGet*(bottleRate-1);
console.log('使用空瓶'+ bGet*bottleRate +'个,兑换:'+ bGet +'瓶');
console.log('已喝:'+ count + ', 剩余瓶盖:'+ lid +', 剩余空瓶:'+ bottle);
}
// 判断剩余
if(bottle >= bottleRate || lid >= lidRate){
change();
} else {
console.log('总共喝:'+ count + ', 剩余瓶盖:'+ lid +', 剩余空瓶:'+ bottle);
}
})();
};
// 开始计算
changing(10, 2);

BTW:题目的答案是最终可以喝 15 瓶(计算过程如下图),你答对了吗?

基于 Promise 的 ajax 请求,可以实现链式调用,使代码结构更清晰,代码如下:

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
'use strict';
// 函数封装
var handleAjax = function handleAjax() {
var options = arguments.length <= 0 || arguments\[0\] === undefined ? {} : arguments\[0\],
opt = {
url: options.url || '',
data: options.data || 't=' + new Date().getTime(),
type: options.type || 'get',
dataType: options.dataType || 'json',
cache: options.cache || false,
async: options.async || true,
context: options.context || document.body,
beforeSend: options.beforeSend || undefined
};
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
if (typeof opt.beforeSend === 'function') {
opt.beforeSend();
}
req.open(opt.type, opt.url, opt.async);
req.onload = function () {
if (req.status === 200) {
var data = req.responseText;
if (opt.dataType === 'json') {
data = JSON.parse(data);
}
resolve(data);
} else {
reject(new Error(req.statusText || 'You can\\'t do this.'));
}
};
req.onerror = function () {
reject(new Error(req.statusText || 'Server is down.'));
};
req.send();
});
};
// 调用函数
var options = {
url: 'http://httpbin.org/get'
};
handleAjax(options).then(function (data) {
console.log(data);
})\['catch'\](function (error) {
console.log(error);
});

预览效果 | 源码 | 参考资料

当我们把一个多参数的函数,分解为若干个但参数的函数时,我们就在进行函数柯里化(Currying)。一个小例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var add = function(){
var args = arguments,
ret = 0;
[].forEach.call(args, function(item){
var num = +item || 0;
ret += num;
});
console.log('result: '+ ret);
return ret;
};
Function.prototype.currying = function(){
var args = [].slice.call(arguments),
self = this;
return function(){
var combinedArgs = args.concat([].slice.call(arguments));
return self.apply(null, combinedArgs);
};
};
var add123 = add.currying(1, 2, 3),
add456 = add123.currying(4, 5, 6);
// 运行
add456(7, 8, 9);
add456(1);
add456(2, 3);

参考文章:尾调用优化Thunk 函数的含义和用法 PS:柯里化的对偶是反柯里化(Uncurrying),且听下回分解吧。

当我们通过 tag 来选取页面元素(比如 p 元素)的时候,有两种方法,document.querySelectorAll(‘p’) 和 document.getElementsByTagName(‘p’)。他们在使用时有稍许不同,querySelectorAll 返回的是一个 Static Node List,而 getElementsBy 系列的返回的是一个 Live Node List(via)。大致可以理解为,getElementsByTagName 返回的是一个可变的对象,当 DOM 刷新的时候,这个对象里面的值也会发生改变,而 querySelectorAll 返回的是一个静态的对象,其值不随 DOM 刷新而改变,所以当页面动态刷新时,两个值是不同的。见代码:

original

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
document.addEventListener('DOMContentLoaded', function(){
var div = document.querySelector('div'),
result = document.querySelector('section'),
get = document.getElementsByTagName('p'),
query = document.querySelectorAll('p');
alert(get.length+ ', ' +query.length); // 1, 1
addElement(div);
addElement(div);
alert(get.length+ ', ' +query.length); // 3, 1
});
var addElement = function(elem){
var add = document.createElement('p');
add.innerHTML = 'new line';
elem.appendChild(add);
};

点击查看 DEMO

最近做个项目需要访问跳板机(堡垒机)中的 Oracle 数据库。需要 ssh 到某一个 IP,转发到本地 127.0.0.xxx IP 中的某一个端口。 Windows 下使用 SecureCRT 进行这个操作时溜溜的,到了 Mac(10.11.2) 下面就嗝屁了,具体表现为:

1. SecureCRT 中每次连接服务器都会提示输入密码,超级麻烦; 2. 全部设置好了以后依然无法连接到跳板机。

搜索之,翻了一大圈(使用中文关键词「mac securecrt 跳板机」),出来的结果都不甚理想。后来实在不甘心,在家大便的时候使用英文关键词搜索「mac securecrt port forwarding」,终于在官网找到了答案,现整理如下:

1. 打开 SecureCRT,按 ⌘ + , 进入偏好设置, General 中去除勾选「Use Keychain」,解决连接时保存密码不成功的问题; 2. 打开终端,输入下面的命令,绑定本地 IP(根据具体需求修改 xxx 部分);

sudo ifconfig lo0 alias 127.0.0.xxx

3. 选中当前连接,按 ⌘ + enter,进入 Property 设置,选中 Port Forwarding,添加相应的转发规则(方法); 4. 双击连接,成功。

PS:SecureCRT 与第三方输入法配合使用时,会出现 Console 中无法使用快捷键(比如 ⌃ + C 中断)的现象,切换为原生英文输入法就好了。