青龙湖畔赏海棠
清明节来到青龙湖畔,寻找春的气息,拍了些海棠花。
清明节来到青龙湖畔,寻找春的气息,拍了些海棠花。
检测设备是否是触屏设备的方法,Modernizr是这样实现的:
// Modernizr现在使用的方法
('ontouchstart' in window)
|| window.TouchEvent
|| window.DocumentTouch && document instanceof DocumentTouch
// Modernizr早期使用的方法
function isTouchDevice() {
try {
document.createEvent('TouchEvent');
return true;
} catch (e) {
return false;
}
}
但是随便在Mac上的Chrome78.0中验证了一下,发现是存在window.TouchEvent的,所以所谓的触屏检测方法其实并不可靠,可以看一下这篇You Can't Detect A Touchscreen。
参考链接:Modernizr源码
下面这道js面试题目,主要考察对闭包概念的理解,用了好几年,在一面中能完全答对的面试者寥寥。这几天恰巧又在面试,想起这道题目,贴出来分析一下。
var a = 0, b = 0;
function A(a) {
A = function B(b) {
alert(a+b++);
}
alert(a++);
}
A(1);
A(2);
把代码粘到浏览器控制台执行,很容易得出输出结果是1和4。
首先,这段代码只有两次输出,说明每次调用函数A
,只执行了一次alert
。很多同学会认为有四次输出,这里涉及的考点是函数声明和命名函数表达式。第3行的赋值语句,使用函数表达式更新了函数A
为函数B
,于是第二次调用函数A
,实际执行的是函数B
中的代码,所以每次调用只有一个alert
执行。
其次是本道题目的重点,闭包变量a
。第一次调用函数A
,第6行的alert
输出1,参数a
在函数执行结束后的值是2,而这个a
此时作为闭包变量留在了命名函数表达式中。第二次调用函数A
,传入的2实际对应函数B
的参数b
,而此时函数B
中的变量a
的值也是2,于是第4行的alert
执行,输出4。
最后,考察对i++
和++i
的理解,还有一元运算符与二元运算符的运算顺序,这里就不细说了。
计算机中的字符串排序算法是直接比较字符的ASCII顺序,这样得出的排序结果有时候并不符合人类思维。比如下面这个文件名排序的例子。
一组文件1.jpg 2.jpg 10.jpg 100.jpg
,排序后会得到这样的结果1.jpg 10.jpg 100.jpg 2.jpg
,显然2没有10和100大,应该排在它们的前面才对。Windows资源管理器中的按名称排序就是这样实现的(Mac修正了这个问题)。
对字符串排序时能够智能地识别出其中的数字,归属于自然排序问题。对于自然排序问题,大多数编程语言都没有原生实现。PHP中有原生方法natsort()
和strnatcmp()
提供支持,但是JavaScript却无能为力。
localeCompare
方法可以按照本地语言习惯对字符串进行比较,能够实现汉字按音序排序,但是直接使用依然无法解决包含数字的字符串的自然排序问题。幸好,新的localeCompare
标准增加了numeric
属性,用于指定是否启用数字排序。虽然这一标准目前还没有得到所有浏览器的支持,但前景是好的,语法如下:
strA.localeCompare(strB, undefined, {numeric: true})
利用localeCompare
这个新特性,我们可以很容易实现包含数字的字符串的自然排序,代码如下。
function naturalCmp(a, b) {
return a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'});
}
var a = ["1.a", "100.a", "10.a", "2.a.10.b", "2.a.2.b"];
a.sort(naturalCmp);
// ["1.a", "2.a.2.b", "2.a.10.b", "10.a", "100.a"]
这种方法的局限性是,它只能分段识别字符串中的独立数字并进行比较,如果想更智能地区分浮点数、科学计数法或者日期的话,则可以使用这个javascript-natural-sort。
在收集资料的过程中发现,早在1997年,David Koelle实现了Alphanum
算法,解决了字母数字组合字符串的自然排序问题,相比上文localeCompare
的实现方式,该算法把点号无条件当做数字中的小数点来参与数值比较,而不是智能地适时当做分隔符来处理,最终的效果不尽完美。毕竟是20多年前的实现嘛,但该算法的思想还是很值得我们借鉴的。Brian Huisman基于该算法的JS实现代码摘录如下。
Array.prototype.alphanumSort = function(caseInsensitive) {
for (var z = 0, t; t = this[z]; z++) {
this[z] = new Array();
var x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >=48 && i <= 57));
if (m !== n) {
this[z][++y] = "";
n = m;
}
this[z][y] += j;
}
}
this.sort(function(a, b) {
for (var x = 0, aa, bb; (aa = a[x]) && (bb = b[x]); x++) {
if (caseInsensitive) {
aa = aa.toLowerCase();
bb = bb.toLowerCase();
}
if (aa !== bb) {
var c = Number(aa), d = Number(bb);
if (c == aa && d == bb) {
return c - d;
} else return (aa > bb) ? 1 : -1;
}
}
return a.length - b.length;
});
for (var z = 0; z < this.length; z++)
this[z] = this[z].join("");
}
最近写了个目录直读的相册程序,用于展示日常拍摄的照片,直接通过FTP
上传,免去后台开发和维护的成本,使用起来也很方便。
大图展示采用lightbox
灯箱插件,效果很不错。但是索引页的图片怎么布局好看呢,参考图虫网的实现方式,每行图片数目固定,行内图片左右对齐,行高固定,单张图片的宽度根据实际比例计算得出。做出来的效果确实不错,计算过程也不复杂。效果图如下。
程序是用PHP
实现的,后端直接计算好尺寸输出HTML
,但实际上这个布局实现过程由前端来实现更科学,于是用js
改写了计算方法,代码如下。
const containerWidth = 1200;
const column = 4;
const imagesRow = [
{width: 1200, height: 750, info: {}},
{width: 801, height: 1200, info: {}},
{width: 1200, height: 1200, info: {}},
{width: 1200, height: 675, info: {}}
];
function fixImageSize(imagesRow, containerWidth, column) {
let heights = imagesRow.map(image => image.height);
let minHeight = Math.min.apply(null, heights);
let minWidth = containerWidth / column;
// 第一次循环,统一高度
for (let i = 0; i < imagesRow.length; i++) {
if (imagesRow[i].height === minHeight) {
minWidth = imagesRow[i].width;
} else if (imagesRow[i].height > minHeight) {
imagesRow[i].width = imagesRow[i].width * minHeight / imagesRow[i].height;
imagesRow[i].height = minHeight;
}
}
containerWidth = containerWidth * imagesRow.length / column;
let widths = imagesRow.map(image => image.width);
let zoom = widths.reduce((prev, next) => prev + next) / containerWidth;
let fixedHeight = minHeight / zoom;
// 第二次循环,压缩宽度
for (let i = 0; i < imagesRow.length; i++) {
imagesRow[i].width = parseInt(imagesRow[i].width / zoom, 10);
imagesRow[i].height = parseInt(fixedHeight, 10);
}
return imagesRow;
}
let ret = JSON.stringify(fixImageSize(imagesRow, containerWidth, column), null ,2);
/*[
{
"width": 380,
"height": 237,
"info": {}
},
{
"width": 158,
"height": 237,
"info": {}
},
{
"width": 237,
"height": 237,
"info": {}
},
{
"width": 422,
"height": 237,
"info": {}
}
]*/
相册写好后,先把大学期间上传到人人网的照片备份了一下,说不定哪天人人网又不行了,还能留个怀念,地址