sort 作为数组的方法,被定义在 Array.prototype.sort,也即在 JavaScript 中所有数组都可以使用 sort 方法进行排序。虽然一般情况下,sort 甚至可以不用传递排序函数一样可以正常工作,但很多情况下,我们还是必须明确的定义排序函数,才能更好的按我们的需求来工作,这也是一般情况下建议的方式,因为不知道不同的 js 引擎在不传递排序函数的时候,会按照什么方案进行排序。
例如:

var colors = ['red', 'green', 'blue', 'yellow', 'white'];
console.log(colors.sort());    // ["blue", "green", "red", "white", "yellow"]
console.log(colors);           // ["blue", "green", "red", "white", "yellow"]

如果不传递排序函数,那么,对于字符串来说,其将按照字母顺序来进行排序,可是,如果这些字符串里面有大写小写字母混合呢?

var colors = ['red', 'green', 'blue', 'Yellow', 'White'];
console.log(colors.sort());    // ["White", "Yellow", "blue", "green", "red"]

怎么样,结果不一样了吧?这是因为此时按照 ASCII 编码的顺序进行排序了。

同时,另一个问题是,sort 函数作用于原数组,也即是排序的结果会覆盖排序前的数组。

然后,对于数字数组,不传递排序函数的话,会是什么结果呢?

var money = [12, 3, 7.4, 200];
console.log(money.sort());    // [12, 200, 3, 7.4]

咦?并没有得到预期的结果(除非你的预期不是按数字大小),那么为什么呢?

因为在 sort 排序的时候,如果不传递排序函数,那么会先将所有的元素转换为 字符串 ,然后才会一个字一个字(ASCII,对于 true 或者 false 这类型的值都是一样的)的排序,为什么都转换成字符串,因为 JavaScript 数组中可以是任意类型的数据,所以 JavaScript 无法推断到底转换为什么类型去排序。

那么我们看看不同的数据类型,排序函数的一些写法:

数组内都是数字,或者期望按数字为主的排序方式。

var money = [12, 3, 7.4, 200];
var compare = function(a, b) {return a - b;};
console.log(money.sort(compare)); // [3, 7.4, 12, 200]
//console.log(money.sort(function(a, b) {return a - b;})); // [3, 7.4, 12, 200]

这是最基础的排序函数,任何讲到 JavaScript 排序的地方,基本都会讲这个。首先取前两个元素赋值给 a b,返回 a-b 的值,如果返回负值则 a 在 b 前,等于 0 则无所谓,因为两个元素相等,返回正直,则 a 在 b 后。

对于字符串的元素来说,和数字的差不多,无非就是不同的排序函数,那如果是对象呢?

var people = [
    {
        name: 'Alice',
        id: 1234
    },
    {
        name: 'Bob',
        id: 567
    }
];
var compare = function(a, b) {return a.id - b.id;}
console.log(people.sort(compare)); // Bob is before Alice now

对于元素的排序函数传递的参数都一样,两个数组中的元素,然后此处主要比较两个对象元素的 id 的值,来进行排序的。

可是如果如下面这种情况呢?

var everything = [4, 'Red', '$200', 'white', 7.4, 12, true, 0.3, false];
var compare = function(a, b) {return a - b;};
console.log(everything.sort(compare));

当排序函数进行计算的时候,由于有减法运算的参与,所以这里都会先转成数字进行计算的,但是如果是字符串的话,此处就会转换为 NaN,因为在 ECMA 规范中没有明确定义这时候应该如何进行排序,所以各个平台,也就是各个浏览器(JavaScript环境)的不同,导致最终的结果会不一定相同。大家可以自己在不同的浏览器上测试下。

例子来源:http://zhangwenli.com/blog/2013/11/02/sorting-in-javascript/

一般情况下,我们都使用 JavaScript 的 console.log() 进行 debug 但是,对于 Object 来说,每次 console.log 之后,输出的都是不是十分有好的数据,例如:

var languages = [
    { name: "JavaScript", fileExtension: ".js" },
    { name: "TypeScript", fileExtension: ".ts" },
    { name: "CoffeeScript", fileExtension: ".coffee" }
];

console.log(languages);

输出的就如同下图所示(当然,会根据不同的浏览器以及不同的版本会有所差别):

logging_with_console_log.

然后呢,其实看起来还是那么回事,虽然麻烦点,但是还可以看的清楚,到底什么是什么东西。

再然后呢?如果我们使用这里介绍的 console.table 呢?

不过,聪明的人一眼就看出来其中的玄机了,或者,看到这里,直接就去浏览器的console里面,执行这句代码就完了。怎么样?很好用吧?

不过还是给个例子比较好,因为大部分都比较懒嘛。
还是上边的对象,然后使用 console.table(language) 输出看看。

logging_with_console_table

看到了吧,多么的一目了然!

然后点击各个表头试试看,还可以排序哦。

logging_with_console_table_sorted

好了,上面是数组,但是其实对于对象也是可以使用的哦。

var languages = {
    csharp: { name: "C#", paradigm: "object-oriented" },
    fsharp: { name: "F#", paradigm: "functional" }
};

console.table(languages);

然后看看结果,看到了吧?

logging_with_console_table_object

可是,如果就这么点,那么除了更好的阅读方式之外,就没什么意思。

那么,它还可以过滤,哈哈。

这么:

console.table(languages, ["name", "paradigm"]); //多个 key 组成的数组

或者这么:

console.table(languages, "name”); //单个 key

很多内容来自:http://blog.mariusschulz.com/2013/11/13/advanced-javascript-debugging-with-consoletable

前几天,在 Twitter 看到一句非常整洁的代码:

var bind = Function.prototype.call.bind(Function.prototype.bind);

第一次看的时候,我可以知道这段代码想干嘛,它让 x.y(z) 变成 y(x,z). 带着非常愉快的心情,我把这段代码给我的学生们看,但是,他们问我这段代码干嘛用呢。然后我就开始解释,但是我不知道从何说起,然后我就转身走开了。

应该明白的是,大部分比较好的代码,应该直接告诉我们它们是用来做什么的,带着这些在函数式 JavaScript 领域的经验,并且也在不断的阅读函数式 JavaScript 相关的书籍,在读的时候,我觉得是没有任何问题的,但是解释,将这些函数式程序解释给别人来说,还是没有太多经验。

但是,我还是想尝试下,通过我的方式,一些简单的示例,还有大量的注释,来解释一下这段代码的意思。

定义一个简单的对象 context

var context = {foo : “bar”};

定义一个函数,使用了一个在 this 上下文中,被命名为 foo 的变量,

function returnFoo(){
	return this.foo;
}

这个变量不存在于作用域中,因此,其返回 undefined。
(具体解释为,此时, this 指代全局的 window,而 window.foo 没有定义,所以返回 undefined)

returnFoo(); // undefined

但是,如果我们将此函数绑定到某个上下文。

var bound = returnFoo.bind(context);

现在变量 foo 存在于作用域中了.
(即,在 context 这个上下文中,是有定义 foo 变量的)

bound(); // bar

这就是 Function.prototype.bind 的作用,因为 returnFoo 是个函数,所以其继承了 function 的 prototype。

除了这种方式,还有另外其他方式来改变一个函数的上下文。例如 call 和 apply。

returnFoo.call(content); // bar
returnFoo.apply(content); // bar

还有就是将函数附加给某个对象,作为某个对象的一个方法。

content.returnFoo = returnFoo;
content.returnFoo();  // bar

让我们再来看看其他一些使用方法

Array.prototype 有一个特别好用的方法,叫做 slice。

在数组上调用此方法,它会返回一个从开始到结束的这个数组的一个拷贝,例如:

[1,2,3].slice(0,1);  // [1]

现在将,slice 赋值给一个本地变量。

var slice = Array.prototype.slice;

slice 现在未被绑定到任何对象,所以它和 Array.prototype.slice 比起来,对提供给它的上下文,或者 this,是不能正常的工作。

slice(0,1); //typeError
slice([1,2,3],0,1); //TypeError

但是,如果我们通过 call 或者 apply 来调用它,并且给它提供一个上下文。

slice.call([1,2,3],0,1);   // [1]
slice.apply([1,2,3],[0,1]);  //[1]

那么对于 bind 呢?我们来试试。

slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1,2,3],0,1);  //[1]

很酷吧,那么我们对 bind 使用和 slice 一样的方式。

var bind = Function.prototype.call.bind(Function.prototype.bind);

var content = {foo : ”bar”};
function returnFoo(){
	return this.foo;
}

var amazing = bind(returnFoo, content);
amazing();   //bar

这样,就明白了 这段代码的意图。

这个bind 的解释是来源于 MDN 的,但是不明白为什么 Google 对 MDN 的东西这么低的评价,所以要翻页才能找到的。

翻译原文:Bind, Call and Apply in JavaScript

方法一:
该方法是将外部容器的显示模式设置成display:table,img标签外部再嵌套一个span标签,并设置span的显示模式为display:table-cell,这样就可以很方便的使用vertical-align象表格元素那样对齐了,当然这只是在标准浏览器下,IE6/IE7还得使用定位。
HTML结构部分:

<div id="box">
    &nbsp;&nbsp;&nbsp;&nbsp;<span><img src="images/demo.jpg" alt="" /></span>
</div>

CSS样式部分:

<style type="text/css">
#box {
    width:500px;height:400px;
    display:table;
    text-align:center;
    border:1px solid #d3d3d3;background:#fff;
}
#box span {
    display:table-cell;
    vertical-align:middle;
}
#box img {
    border:1px solid #ccc;
}
</style>
<!--[if lte IE 7]>
<style type="text/css">
#box {
    position:relative;
    overflow:hidden;
}
#box span {
    position:absolute;
    left:50%;top:50%;
}
#box img {
    position:relative;
    left:-50%;top:-50%;
}
</style>
<![endif]-->

方法二:
标准浏览器还是将外部容器#box的显示模式设置为display:table-cell,IE6/IE7是利用在img标签的前面插入一对空标签的办法。
HTML结构部分:

<div id="box">
    &nbsp;&nbsp;&nbsp;&nbsp;<i></i><img src="images/demo.jpg" alt="" />
</div>
 
<style type="text/css">
#box{
    width:500px;height:400px;
    display:table-cell;
    text-align:center;
    vertical-align:middle;
    border:1px solid #d3d3d3;background:#fff;
}
#box img {
    border:1px solid #ccc;
}
</style>
<!--[if IE]>
<style type="text/css">
#box i {
    display:inline-block;
    height:100%;
    vertical-align:middle
}
#box img {
    vertical-align:middle
}
</style>
<![endif]-->

方法三:
该方法针对IE6/IE7,将图片外部容器的字体大小设置成高度的0.873倍就可以实现居中,标准浏览器还是使用上面的方法来实现兼容,并且结构也是比较优雅。
HTML结构部分:

<div id="box">
    &nbsp;&nbsp;&nbsp;&nbsp;<img src="images/demo.jpg" alt="" />
</div>

CSS样式部分:

#box {
    width:500px;height:400px;
    text-align:center;
    border:1px solid #d3d3d3;background:#fff;
    
    /* 兼容标准浏览器 */
    display: table-cell;
    vertical-align:middle;
	
    /* 兼容IE6/IE7 */
    *display:block;
    *font-size:349px; /* 字体大小约为容器高度的0.873倍 400*0.873 = 349 */
    *font-family:Arial; /* 防止非utf-8引起的hack失效问题,如gbk编码 */
}

#box img {
    vertical-align:middle;
}

以上方法来源于:雨夜带刀’s Blog

另一篇关于这个问题解决方案的文章,请看 大小不固定的图片、多行文字的水平垂直居中

主要出现了两个问题,第一个问题是,无法分区。表现的问题就是到 boot camp 助理最后一步的时候,分区老是不成功。

解决方法:重启按住 Command + R 选择 磁盘工具,然后选择系统盘,检查错误,修复错误。然后重启再次使用 Boot Camp 就可以正常分区了。

第二个问题就是,安装程序无法创建新的系统分区,也无法定位现有系统分区。

苹果也给了解决方案,http://support.apple.com/kb/TS4599?viewlocale=zh_CN。

但是我的问题是,我把移动硬盘插在了 左侧 的 USB 接口上,并且 USB 的格式是 EXFAT 格式。

最后把移动硬盘去掉,顺利安装成功。

对于 IE6 也可以使用纯 CSS 来实现 position:fixed 的效果。直接上代码吧。
先是结构。

    <div class="container">
        我是IE6,使用 absolute 模拟 fixed.</br>
        这里多多复制几个,效果明显。
    </div>
    <div class="fixed"></div>

然后是 CSS。

        body {
            height:100%;
            overflow-y:auto;
            padding:0px;
            margin:0px;
        }
        .container {
            height:1800px;
            background:#CCC;
        }
        .fixed {
            position:fixed;
            top:50px;
            left:50px;
            background:red;
            height:50px;
            width:50px;
        }

还有对于 IE6 来说,加一个单独的样式

   <!--[if lte IE 6]>
        <style type="text/css">
            html {overflow-x:auto; overflow-y:hidden;}
            .fixed {
                position:absolute;
            }
        </style>
    <![endif]-->

原理就是对于 body 设置高度 100%,html 垂直方向上,超出高度给隐藏掉。然后里面的内容自己滚动,而 absolute 的相对于浏览器窗口的话,因为浏览器窗口就那么大,又不滚动,所以 absolute 看起来就 fixed 了。

但是这个有个问题,就是 所有设置了 absolute 和 relative 的元素,都会表现为 fixed 的,所以还是有副作用的。不过可以用来做遮罩层。

例子可以使用 IE6 浏览器访问。