ES6 快速上手:初探

es6-small

最新版的 JavaScript 标准已经发布了,正式的名称叫做 ECMAScript 2015,也就是我们常说的 ES6,或者还有个更老的名字叫 ES Harmony。因为制订标准的是 ECMA 组织所以叫做 ECMAScript 。 JavaScript 其实就是对 ECMAScript 的实现,或者说是 ECMAScript 的一种方言。

所以,前端领域的新知识真是源源不断,层出不穷……时时刻刻都不能停止学习啊。准备写成一个系列,这些内容都是我自己整理的。

第一篇还是先讲一些比较简短的特性吧。

参数默认值

在 ES6 中,函数参数可以设置默认值了。上例子:

function increment(n = 1) {
  return n + 100;
}

在以前我们需要这样:

function increment(n) {
  n = n || 1; // foo的默认值设为1
  return n + 100;
}

如果没有传入 n,那么 n 的值就是 1。注意,如果你传入 undefinedn 的值还会是 1

可以只给某一个参数设置默认值:

function sum(a, b = 2, c) {
  return a + b + c;
}

可以执行函数来得到默认值:

function foo( bar = getBar() ) {
  return foo + 10;
}

剩余参数

这个特性也叫做“rest”,操作符是三个点 ...,用来包含剩余参数。例子:

function foo(x, ...y) {
  console.log(y);
}
foo(1, "hello", true); // ["hello", true]

可以看到,除了 x 之外剩下的所有参数都被放入数组中传给了 y,这就是“rest”的作用。

y 总是一个数组,里面包含了剩余的所有参数。上例中,如果只传入一个参数,那么 y 就是空数组。

注意这个特性只能用在最后一个参数上,下面是错误的:

// 错误
function foo(x, ...y, z) {
  console.log(y);
}

数组拆分

又叫“spread”,也是三个点,但是用在数组之前,例如 ...[a, b, c]

作用是可以把数组拆分成 a, b, c 的形式。拆分后,有两个用处:第一,是给函数传参:

function sum(a, b, c) {
  return a + b + c;
}
sum(...[1, 2, 3]); // 等于sum(1,2,3)

数组被拆成了三个参数传入了 sum 函数。在 ES5 中,我们就需要这样写:

sum.apply(undefined, [1, 2, 3]);

第二个用处,是用在数组字面量里:

var foo = ['b', 'c'];
var combined = ['a', ...foo]; // 等于['a', 'b', 'c']

对象字面量扩展

ES6 还对对象字面量进行了一些扩展,比如一些简写,下面是简写前的代码:

var obj = {
  foo: foo,
  toString: function() {
    return this.foo;
  }
}

使用 ES6 可以简写成为:

var obj = {
  // 两个foo简写成一个foo
  foo,
  // 省略function关键字
  toString() {
    return this.foo;
  }
}

还有一些扩展:

var obj = {
  //设置原型对象
  __proto__: theProtoObj,

  //属性名可以动态计算
  [ "prop_" + 42 ]: 42
}

动态计算的属性名,使用中括号,里面可以放入任何表达式,包括调用函数。

let

JavaScript 一直都没有局部作用域,这是跟其他语言相比一个奇葩的地方。比如,想要在条件语句中声明变量:

if(isBlack) {
  var black = true;
} else {
  var white = true;
}

你希望在 isBlack=true 时才定义变量 black,否则就定义一个变量 white。结果在 JavaScript 中并不是这样,两个变量都会被定义。只不过其中一个是 undefined

现在 ES6 中引入了 let 以后就不一样了。let 的作用和 var 一样,都是用来定义变量,但一个重要区别是,let 定义的变量只在局部作用域中有效。比如下面:

if(a === 1) {
  let b = 2;
}

for(let c = 0; c < 3; c++) {
  ...
}

function foo() {
  let d = 4;
}

b, c, d 变量都只在相应的代码块中有效,在其他地方,这些变量都是未声明的。如果访问,就抛出 ReferenceError。也就是变量的有效范围仅限于花括号内。当然了,也包括 for 后面的圆括号。
阅读全文 »

文件上传插件:Uploadify 和 Dropzone

上传文件的功能,一般用一个 <input type="file"> 就能够工作了,但如果有更细致需求,比如显示上传进度等,就需要用 JavaScript 进行更多控制,使用插件是一个很好的办法,介绍两个常用插件:Uploadify 和 Dropzone。

Uploadify 兼容性好,支持IE6+,所以使用的人很多。但为了兼容 IE6 等,使用的是 Flash,方法显得比较落伍。Dropzone 使用的是新 API,支持通过 Ajax 传输文件,兼容性就差一点,需要 IE10+。从名字也能看出来后者支持拖拽文件上传。

Uploadify

Uploadify 是一个 jQuery 插件,需要 jQuery 1.4 以上。先从官网下载压缩包,把以下必要文件释放到网站目录:

  • jquery.uploadify.min.js  插件
  • uploadify.css  样式
  • uploadify.swf  主要功能Flash
  • uploadify.php  后端接收文件
  • uploadify-cancel.png  按钮背景图(一个叉)
  • check-exists.php  用来检测文件是否已存在

还需要单独下载一份 jQuery。上面的 uploadify.php 是后端对上传文件的处理,可以换成自己的 php 代码。

部署

然后就开始编写 HTML 了,先添加好 JS 以及 CSS 文件引用,然后添加一个 <input> 控件例如

<input type="file" name="file_upload" id="file_upload">

用 Uploadify 初始化:

$('#file_upload').uploadify({
  swf: 'uploadify.swf',
  uploader: 'uploadify.php'
  // 其他选项
});

就可以了,默认的样式如下

uploadify

可以通过其他配置项修改样式等等:

  • height, width:(integer) 控件的宽和高
  • buttonText:设置按钮文字,替换上图“SELECT FILES”
  • buttonClass:给按钮添加的类。然后可以在 CSS 中自定义样式
  • auto:(boolean) 默认 true,选择文件以后自动开始上传。false 则不自动,需要自己调用方法上传
  • checkExisting:(string) 如果需要在后端检测文件是否已存在,将此值设为 check-exists.php 的路径
  • fileObjName:默认是 "Filedata",即后端需要通过 $_FILES['Filedata']
  • progressData:默认 "percentage",即显示进度百分比,也可以设为 "speed" 显示上传速度
  • formData:(Object) 可以向后端传入额外的数据,如 formData: {"someKey": "someValue"}。后端可以通过 $_POST['someKey'] 读取
  • onUploadSuccess:回调函数 function(file, data, response)file 是一个文件对象,可以读取 file.name 等属性,data 为后端返回的数据(即 echo 的内容),response 是一个布尔值,后端如果有数据返回就是 true

以及一些方法可以调用:

  • upload:手动上传文件,调用方式 $('#file').uploadify('upload');
  • cancel:取消一个或全部文件的上传
  • destroy:销毁 Uploadify 实例,卸载功能

更详细的配置可以查看官网

汉化

uploadify2

默认情况下,文件上传成功会显示“Complete”字样,如果想要自定义,可以在插件 JS 中搜索“ – Complete”,改成“ – 已完成”等等,就可以了。如果上传文件已存在,弹出的提示也是英文,可以搜索“already exists”找到那段字符修改一下。

后端处理

一个后端 php 的例子:

<?php
if (!empty($_FILES)) {
    $tempFile = $_FILES['Filedata']['tmp_name'];
    $targetFile = 'uploads/' . $_FILES['Filedata']['name'];

    $fileTypes = array('jpg','jpeg','gif','png');
    $fileParts = pathinfo($_FILES['Filedata']['name']);

    if (in_array($fileParts['extension'],$fileTypes)) {
        move_uploaded_file($tempFile,$targetFile);
        echo '1';
    } else {
        echo '0';
    }
}
?>

Uploadify 默认的文件字段是 $_FILES['Filedata']。以上例子会限制上传文件类型为图片,然后保存在“uploads”子目录。要提前创建好“uploads”子目录否则无法正常保存。

Dropzone

Dropzone由于使用了 XMLHttpRequest 2,所以需要现代浏览器的支持,但是配置更方便,也不依赖其他库。

首先下载压缩包,实际需要的文件只有 dropzone.js 和 dropzone.css。部署起来也非常简单:

<form action="upload.php" class="dropzone" id="my-upload"></form>

在 HTML 中添加以上 <form> 就可以了。只要添加了 "dropzone" 类,Dropzone 就会自动添加功能。action 属性对应后端文件,字段是 $_FILES['file']。默认界面:

dropzone

Dropzone 也有很多的配置项,要进行配置需要先取得 Dropzone 对象实例,这就是上例 id="my-upload" 的作用,可以通过 Dropzone.options.myUpload 访问实例,注意是驼峰形式。例如绑定一个 success 事件:

Dropzone.options.myUpload = {
  init: function() {
    this.on("success", function(file,response) {
      ...
    });
  }
}

更多的配置参考:Dropzone

Dropzone 界面的文字也是可以修改的,在 JS 中搜索 "Drop files here to upload" 就能找到,可以看出 Dropzone 在自定义方面其实考虑很周到,相关的提示文字都放在一起,可以很方便地进行汉化。

Written with StackEdit.

Sublime Text 实用快捷键汇总

Sublime Text 是个十分好用的编辑器,众多的快捷键是一大亮点能很大地提高效率。但是快捷键实在太多,我搜集汇总了一下方便查阅,都是我觉得非常有用的快捷键。其实不需要刻意去记住,用得多了自然就熟了。

以下快捷键基于 Win 平台。

Ctrl + Shift + P

首先介绍一下这个,按下之后打开一个命令框,绝大部分的命令都可以在这里找到,并且在后面附有快捷键。包括插件的命令也包含在此。

Ctrl + R

跳转到函数定义、CSS 选择器的定义等。

F12

如果当前光标所在位置是函数名或 CSS 选择器,按下 F12 可以直接跳转到其定义。

Ctrl + ;

跳转到变量定义所在处。比如,输入 foo 会找到 var foo = ... 在哪。

Ctrl + G

跳转到指定行。

Ctrl + P

快速导航。可以快速定位项目中的文件并打开。(前提是要把目录先添加进 Sublime Text 的项目中。点击 “Project” -> “Add Folder to Projet” 添加以后,按 Ctrl + KB 看看侧边栏,如果你的目录在里面,那么就可以使用了。再次按 Ctrl + KB 关闭侧边栏。)

例如:在 Ctrl + P 中输入 style.css 可以直接打开 style.css 文件。

在此处也可以使用冒号来跳转到行,如 style.css:123 会直接打开并定位到 123 行。Ctrl + G 其实就是冒号的一个快捷用法。

使用 @ 来跳转到函数或选择器定义,如 style.css@.search 会直接打开并定位到 .search 选择器所在的位置。Ctrl + R 是冒号的快捷方式。

要跳转到变量定义可以使用 #,如 script.js#foo。其实 Ctrl + ; 就是使用 # 的另一种方式。

由于 Ctrl + P 有如此多的功能,故而得名“Go To Anything”。

Ctrl + Alt + Up/Down

多行编辑。用于在多行的同一个位置放置光标。也可以按住 Shift,然后按着右键往上/下拉,就可以同时创建多个光标。

Ctrl + 鼠标左键

可以放置多个光标,同时编辑。

Ctrl + L

选中当前行。多次按下可以连续选中多行。

Ctrl + Shift + L

假如有多个长短不一的行,要在每行都放置一个光标,如何做?按住 Ctrl 一个个点吗?太费事了,可以这么做:先 Ctrl + L 选中这些行,然后 Ctrl + Shift + L 就可以了。

Ctrl + Shift + K

删除当前行。

Ctrl + X

剪切当前行。注意你不需要选中再按 Ctrl + X,只要光标定位到本行就可以了。

Ctrl + KK

删除从光标到行尾的内容。

Ctrl + J

删除行末的换行符。效果就是下一行跑到了当前行的行尾。如果同时选中多行以后按 Ctrl + J,就是多行合并。

Ctrl + F2

在当前光标位置做标记。然后可以随时按下 F2 回到这个位置。可以同时做多个标记,按 F2 则是在各个标记间跳转。

Ctrl + Tab

切换文件。打开了多个文件以后用这个快捷键来回切换。也可以用右键 + 滚轮。或者 Alt + 数字 可以直接跳到该窗口。

Ctrl + Enter

在下方插入一行。对应的:

Ctrl + Shift + Enter

在上方插入一行。这两个非常好用,你不需要先把光标移到行尾再按回车建立新行了。

阅读全文 »

Sublime Text 的代码片段功能

很多人都和我一样喜欢用 Sublime Text,非常好用的一款编辑器,今天主要探索一下里面自带的代码片段功能。对于程序员来说代码复用是很常见的事,总有那么几段代码会在各个项目中反复地用,这种情况下,除了给它保存起来随时粘贴,还可以用一个代码片段管理工具,建立起自己的代码库。代码库的管理工具很多,不过编辑器自带的一般已经够用。

创建代码片段

打开“Tools” > “New Snippet” 会弹出如下的新文件:

<snippet>
    <content><![CDATA[
Hello, ${1:this} is a ${2:snippet}.
]]></content>
    <!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
    <!-- <tabTrigger>hello</tabTrigger> -->
    <!-- Optional: Set a scope to limit where the snippet will trigger -->
    <!-- <scope>source.python</scope> -->
</snippet>

这就是创建代码片段所用的模板,把第三行内容换成自己的代码就可以了。后面几行是配置项,使用前先去除注释符号。其中 <tabTrigger> 用来设置快捷键。

比如,设置 <tabTrigger>hello</tabTrigger>,在编辑器里输入 hello 然后按 Tab,代码就出来了。

编辑完要保存文件到 /Packages/User 目录(你也可以在这新建一个子目录专门存放),扩展名用 .sublime-snippet,代码片段就创建成功了。

配置项详解

<content>

这是代码的主要部分,必须放在 <![CDATA[…]]> 里。如果代码中某些字段你想手动填入,就需要用到 $,比如一个 HTML5 的例子:

<snippet>
    <content><![CDATA[
<!doctype html>
<html lang="zh-cmn-Hans">
    <head>
        <meta charset="utf-8">
        <title>$1</title>
    </head>
    <body>
        $2
    </body>
</html>
]]></content>
    <tabTrigger>html5</tabTrigger>
</snippet>

输入 html5 按下 Tab,代码出现,并且光标处于 $1 的位置。还可以指定更多 $2$3 等,按 Tab 键光标会依次跳转。按下 Esc 终止跳转过程。

还可以指定默认值,比如上例,如果用 <title>${1:Demo}</title>,按下 Tab 后,“Demo”会处于自动选中状态:

snap1

可以直接编辑,也可以按 Tab 保留。

所以 $ 在这里是一个特殊字符,如果你得代码出现了 $,需要转义成 \$

<tabTrigger>

这是触发代码片段的快捷键。

<scope>

定义代码片段可以在什么地方使用,比如 <scope>source.html</scope> 定义片段可以在 html 文件中使用,或者指定多个文件格式 <scope>source.html,source.js</scope>source 是个固定用法,记住这么用就行了,也可以写成 text.html)。Scope 在 Sublime Text 中是一个重要概念,指的是光标所在的上下文,不光可以指示所在的文件类型,还可以指示光标是否处在一对双引号之间等等,都可以用来更细致地限制在何处触发代码片段。具体可以参考文档

<descriptiom>

给片段拟一个描述信息,用以显示在提示框中:

snap2

例子

这是两个我所用的代码片段,第一个 clearfix:

<snippet>
    <content><![CDATA[
/* clearfix */
.clearfix:before, .clearfix:after {
    content: " ";
    display: table;
}
.clearfix:after {clear: both;}
.clearfix {zoom: 1;}

]]></content>
    <tabTrigger>clearfix</tabTrigger>
    <scope>source.html,source.css</scope>
</snippet>

第二个是 JS 中常用的闭包,或者叫 IIFE:

<snippet>
    <content><![CDATA[
;(function() {
    $1
})();
]]></content>
    <tabTrigger>iife</tabTrigger>
    <scope>source.html,source.js</scope>
    <description>闭包</description>
</snippet>

使用闭包避免了污染全局环境。前面的分号如果觉得奇怪也可以去掉,但有时可以防止错误的出现,比如下面例子,前一行漏加了分号,后面的闭包就导致报错了:

var a = [1, 2]
(function() {})(
  ...
)();

这时分号的作用就体现出来了。加分号,保平安。

脚本监听文本框输入

要实现监听文本框的输入,一般我们会用 keydownkeypress 或者 keyup

keydown,keypress,keyup

这三个事件中,keydownkeypress 发生在文本框 value 更新以前,并且可以调用 e.preventDefault() 来撤销键入,keyup 发生在文本框内容更新以后。keydownkeypress 的区别是 keypress 只在按下字符键时触发,而 keydown 也可以捕获 CtrlBackSpace 等不产生输入的键。

但是用这些事件会有一些缺陷,比如 keypress 在删除时不触发,所以就无法监听到文本框内容的所有改变。另外,改变文本框内容的方式多种多样,除了直接键入或者 Ctrl+V 粘贴,用户还可以不用键盘,比如通过右键菜单剪切、粘贴、删除,或者选中一段文字拖放进来,或者拖出去,这些行为用上面三个事件监听不到。所以为了更全面,要用 input 事件替代 keypress

input 事件

input 事件属于 HTML5,在文本框内容发生改变时就会触发,比如键入、剪切、粘贴、删除、右键菜单或者拖放,但是只有通过用户界面改变文本框的值才可以,所以用脚本来修改 value 时不会触发。现代浏览器和 IE9+ 中支持。用法和 keypress 类似。input 事件发生在 keypress 之后,并且也在 value 更新以后,所以不用 setTimeout(0) 就可以直接获取输入后的值。

Tips

除了 <textarea><input:text>input 事件还可以用来监听 <input:password> 和 HTML5 的 <input:search>

IE9 支持 input 事件,需要用 addEventListener 来注册,不能用 attachEvent 注册此事件。而且在 IE9 中有 bug,删除字符时不触发事件(也包括剪切、拖拽)。

Safari5 以及更早版本中,在 <textarea> 上无法触发 input 事件,可以用下面的 textInput 代替。

textInput 事件

textInput 事件和 input 类似,但 textInput 在剪切、删除、粘贴、拖放时不触发(在 chrome 中测试粘贴和拖放可以触发)。

Tips

Firefox 和 Opera 不支持 textInput 事件。IE9+ 支持,事件名称为小写:textinput

event.data 返回新输入的文本(在 chrome 中测试未实现)。

change 事件

change 事件也可以用来监听文本框的改变,但是只有在失去焦点时触发。IE 支持。

Tips

change 事件在 <select><input:checkbox><input:file> 发生改变时也可以触发。

阅读全文 »

Sass命令行指南

sass 或 scss 格式的样式表要编译成 CSS,需要安装 Sass 命令行:

安装 Ruby

Sass 运行需要 Ruby 环境,先安装 Ruby,出现安装选项时勾选后两个。

安装成功后,由于墙的原因,同样建议安装个淘宝镜像。在命令行依次运行

gem sources --remove https://rubygems.org/
gem sources -a https://ruby.taobao.org/
gem sources –l

确保输出的列表中只有淘宝镜像地址,就表明 OK 了。

安装 Sass

在命令行运行 gem install sass。Mac 下如果遇到权限问题,改为 sudo gem install sass

运行 sass -v 查看是否安装成功。要查看 Sass 的帮助,运行 sass --help

编译

编译 .scss 或 .sass 文件:sass input.scss output.css

监视

Sass 可以监视 .scss 或 .sass 文件的改变,一旦保存就执行编译:

sass --watch input.scss:output.css

也可以监视整个目录:

sass --watch app/sass:public/stylesheets

阅读全文 »

有一个姑娘 – 李荣浩

“那些好听的翻唱”系列之《有一个姑娘》,还珠格格里的歌,原唱好像是赵薇?

个人非常喜欢李荣浩的翻唱。

Sass语法

Sass 是一个 CSS 预处理器,简单来说是一种更强大的书写 CSS 的方式,允许你在 CSS 中使用变量、嵌套、函数等等。Sass 的意思是 Syntactically Awesome StyleSheets(语法上更牛的样式表)。

Sass 有两种语法,一种叫 SCSS(Sassy CSS),扩展名 .scss,语法更接近原生 CSS,实际上也完全兼容原生的 CSS,另一种叫 Sass,扩展名 .scss,不使用分号,并且用缩进来代替花括号:

/* SCSS */
#main {
  color: blue;
  font-size: 0.3em;
}

/* Sass */
#main
  color: blue
  font-size: 0.3em

缩进语法的细节看这里

对 CSS 的扩展

规则嵌套

Sass 允许在 CSS 规则中进行嵌套:

#main p {
  width: 97%;

  .redbox {
    background-color: #ff0000;
  }
}

编译后的结果

#main p {
  width: 97%; }
  #main p .redbox {
    background-color: #ff0000; }

Sass 会自动把 #main p 加到 .redbox 前。

引用父选择器:&

可以用 & 来引用父选择器本身,在写 :hover 等规则时很有用:

a {
  text-decoration: none;
  &:hover { text-decoration: underline; }
}

编译结果为

a {
  text-decoration: none;
  a:hover { text-decoration: underline; }
}

& 会被父选择器代替。如果同时使用嵌套,那么 & 是嵌套后的结果:

#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; }
  }
}

编译结果:

#main {
  color: black; }
  #main a {
    font-weight: bold; }
    #main a:hover {
      color: red; }

属性嵌套

font-familyfont-size 这一类规则,前缀相同,也可以都写在 font 下:

.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}

编译结果:

.funky {
  font-family: fantasy;
  font-size: 30em;
  font-weight: bold; }

阅读全文 »

npm入门

npm 是 Node.js 的包管理工具。通过它能够非常方便地下载别人编写的包,用在自己的项目中,或把自己编写的包发布给其他人使用。npm 一般随同 Node.js 一起安装,要查看是否已安装 npm,运行:

npm -v

使用淘宝镜像

由于墙的原因,连接 npm 服务器非常困难,建议用淘宝的 npm 镜像,叫做 cnpm,执行以下命令:

npm install -g cnpm --registry=https://registry.npm.taobao.org

然后,就可以用 cnpm 命令来代替 npm 使用。

npm 是一个库,上面存放着大量的第三方程序,有点像 GitHub,这些程序主要有两种,一种是包(package),用 JavaScript 编写,作为 Node 模块使用,另一种是命令行程序(也叫 CLI,Command Line Interface),直接在命令行中当成命令使用,比如上面的 cnpm。你也可以自己开发一个包或 CLI 发布到 npm 上。

安装 npm 包

要安装一个 npm 包,执行

npm install lodash

就会在你的当前目录中生成一个 node_modules 子目录,并且下载 lodash 包到这个目录。接着就可以在项目里用 require('lodash') 使用这个模块。

如果要安装的是命令行程序,一般会加上 -g,这样命令才能在任意目录下使用,比如安装 Grunt 时:

npm install grunt-cli -g

阅读全文 »

Git 合并时 –no-ff 的作用

在许多介绍 Git 工作流的文章里,都会推荐在合并分支时,加上 --no-ff 参数:

$ git checkout develop
$ git merge --no-ff feature

--no-ff 在这的作用是禁止快进式合并。

Git 合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward),比如下图:

          A---B---C feature
         /
D---E---F master

要把 feature 合并到 master 中,执行以下命令

$ git checkout master
$ git merge feature

结果就会变成

          A---B---C feature
         /         master
D---E---F 

因为 feature 就在 master 的下游,所以直接移动了 master 的指针,master 和 feature 都指向了 C。而如果执行了 git merge --no-ff feature 的话,是下面的结果:

          A---B---C feature
         /         \
D---E---F-----------G master

由于 --no-ff 禁止了快进,所以会生成一个新的提交,master 指向 G。

从合并后的代码来看,结果其实是一样的,区别就在于 --no-ff 会让 Git 生成一个新的提交对象。为什么要这样?通常我们把 master 作为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 feature 是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master 的提交历史。所以如果你根本不在意提交历史,也不爱管 master 干不干净,那么 --no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,比如上例,你就会发现退一个版本到了 B,而不是想要的 F,因为 feature 的历史合并进了 master 里。

最后提醒下 --no-ff 开头是两个短横(标题显示一条横线是 WordPress 的 bug)。

flight