跳到主要内容

· 阅读需 3 分钟

1.SCSSSass

SassSCSS 其实是同一种东西,我们平时都称之为 Sass他们都是用Ruby开发 Css 预处理器,boostrap4已经将less换成了sass

不同之处:

  • 文件拓展名:分别是sassscss
  • 缩进:sass严格缩进(类似 python 和 ruby),scss是 css 的缩进样式
  • 是否兼容 css 语法:显然,由于缩进的不同,scss是兼容原生的 css 写法。

总的来说,scsssass升级版,兼容 css 语法,并且有着自己的独立语法。

2.环境配置

  1. 安装 ruby:windows 注意添加注册表路径
  2. 安装 sass:利用 ruby 的包管理器gem安装,命令行运行:gem install sass
  3. 升级和删除 sass:gem update/uninstall sass

如果国外源过慢?

gem sources -a https://ruby.taobao.org/
gem sources -l #查看是不是淘宝源

3.编译

编译指的是:将 scss 文件编译为 css 文件的过程。

3.1 源文件编译

单文件编译

scss scss.scss:css.css

实时自动编译

使用--watch参数即可,scss 会在源文件改动时候,自动重新编译。


3.2 输出文件风格

命令行编译时候,使用--style参数。

一段 scss 代码:

  h1 {
color : red;
}
}

默认:嵌套输出方式 nested

body h1 {
color: red; }

展开输出方式 expanded

body h1 {
color: red;
}

紧凑输出方式 compact

body h1 { color: red; }

压缩输出方式 compressed

body h1{color:red}

4.注意

最新的 scss 开启了sourcemap功能,--sourcemap参数默认添加。

· 阅读需 5 分钟

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

为什么要用事件委托

一般来说,dom 需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的 dom 需要添加事件处理呢?比如我们有 100 个 li,每个 li 都有相同的 click 点击事件,可能我们会用 for 循环的方法,来遍历所有的 li,然后给它们添加事件,那这么做会存在什么影响呢?

在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与 dom 节点进行交互,访问 dom 的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少 DOM 操作的原因;如果要用事件委托,就会将所有的操作放到 js 程序里面,与 dom 的操作就只需要交互一次,这样就能大大的减少与 dom 的交互次数,提高性能;

每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈),比如上面的 100 个 li,就要占用 100 个内存空间,如果是 1000 个,10000 个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。

总而言之,就是可以提高性能

实现

<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
window.onload = function() {
var oUl = document.getElementById("ul1");
oUl.onclick = function(e) {
alert(123);
};
};

这样当我们点击 li 的时候也是会 alert 的,但是当我们点击 ul 的时候也会触发,如果想让他不触发,怎么办呢?

当我们点击 li 的时候,会产生一个点击事件,这个点击事件当被点下后就确定了,因为冒泡,就会先触发 li 的 click 事件(如果有的话),再触发 ul 的点击事件,但是传入这两个点击事假的 e 是不变的,从这个 e 中我们就可以判断到底是 ul 点击的还是 li 点击的,从而进行特定的操作

window.onload = function() {
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == "li") {
alert(123);
alert(target.innerHTML);
}
};
};

这样就只有点击 li 会触发 alert 了

other

使用事件委托还有一个好处,正常情况下我们给 li 添加了点击事件后,如果又新增了 li,新的 li 是没有点击事件的,而使用事件委托因为是交给的父元素进行事件的触发,所以新增多少 li 都没有关系

给父容器绑定事件,判断 target 是哪个子元素,做相关操作 JQuery 的 delegate 和 on 就是这么干的

· 阅读需 30 分钟

GitHub链接:https://github.com/zwwill/blo...

PC浏览器前端优化策略

PC端优化的策略很多,如 YSlow(YSlow 是 Yahoo 发布的一款 Firefox 插件,现 Chrome 也可安装,可以对网站的页面性能进行分析,提出对该页面性能优化的建议)原则,或者 Chrome 自带的 Audits 等,总结起来主要包括网络加载类、页面渲染类、CSS 优化类、JavaScript 执行类、缓存类、图片类、架构协议类等几类,下面逐一介绍。

网络加载类

1.减少 HTTP 资源请求次数

在前端页面中,通常建议尽可能合并静态资源图片、JavaScript 或 CSS 代码,减少页面请求数和资源请求消耗,这样可以缩短页面首次访问的用户等待时间。通过构建工具合并雪碧图、CSS、JavaScript 文件等都是为了减少 HTTP 资源请求次数。另外也要尽量避免重复的资源,防止增加多余请求。

2.减小 HTTP 请求大小

除了减少 HTTP 资源请求次数,也要尽量减小每个 HTTP 请求的大小。如减少没必要的图片、JavaScript、CSS 及 HTML 代码,对文件进行压缩优化,或者使用 gzip 压缩传输内容等都可以用来减小文件大小,缩短网络传输等待时延。前面我们使用构建工具来压缩静态图片资源以及移除代码中的注释并压缩,目的都是为了减小 HTTP 请求的大小。

3.将 CSS 或 JavaScript 放到外部文件中,避免使用<style><script>标签直接引入

在 HTML 文件中引用外部资源可以有效利用浏览器的静态资源缓存,但有时候在移动端页面 CSS 或 JavaScript 比较简单的情况下为了减少请求,也会将 CSS 或 JavaScript 直接写到 HTML 里面,具体要根据 CSS 或 JavaScript 文件的大小和业务的场景来分析。如果 CSS 或 JavaScript 文件内容较多,业务逻辑较复杂,建议放到外部文件引入。

<linkrel="stylesheet"href="//cdn.domain.com/path/main.css" >
...
<scriptsrc="//cdn.domain.com/path/main.js"></script>

4.避免页面中空的 href 和 src

<link>标签的 href 属性为空,或<script><img><iframe>标签的 src 属性为空时,浏览器在渲染的过程中仍会将 href 属性或 src 属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免。

<!--不推荐--><imgsrc=""alt="photo" ><ahref="">点击链接</a>

5.为 HTML 指定 Cache-Control 或 Expires

为 HTML 内容设置 Cache-Control 或 Expires 可以将 HTML 内容缓存起来,避免频繁向服务器端发送请求。前面讲到,在页面 Cache-Control 或 Expires 头部有效时,浏览器将直接从缓存中读取内容,不向服务器端发送请求。

<metahttp-equiv="Cache-Control"content="max-age=7200"><metahttp-equiv="Expires"content="Mon,20Jul201623:00:00GMT">

6.合理设置 Etag 和 Last-Modified

合理设置 Etag 和 Last-Modified 使用浏览器缓存,对于未修改的文件,静态资源服务器会向浏览器端返回304,让浏览器从缓存中读取文件,减少 Web 资源下载的带宽消耗并降低服务器负载。

<metahttp-equiv="last-modified"content="Sun,05 Nov 2017 13:45:57 GMT">

7.减少页面重定向

页面每次重定向都会延长页面内容返回的等待延时,一次重定向大约需要200毫秒不等的时间开销(无缓存),为了保证用户尽快看到页面内容,要尽量避免页面重定向。

8.使用静态资源分域存放来增加下载并行数

浏览器在同一时刻向同一个域名请求文件的并行下载数是有限的,因此可以利用多个域名的主机来存放不同的静态资源,增大页面加载时资源的并行下载数,缩短页面资源加载的时间。通常根据多个域名来分别存储 JavaScript、CSS 和图片文件。

<linkrel="stylesheet"href="//cdn1.domain.com/path/main.css" >
...
<scriptsrc="//cdn2.domain.com/path/main.js"></script>

9.使用静态资源 CDN 来存储文件

如果条件允许,可以利用 CDN 网络加快同一个地理区域内重复静态资源文件的响应下载速度,缩短资源请求时间。

10.使用 CDN Combo 下载传输内容

CDN Combo 是在 CDN 服务器端将多个文件请求打包成一个文件的形式来返回的技术,这样可以实现 HTTP 连接传输的一次性复用,减少浏览器的 HTTP 请求数,加快资源下载速度。例如同一个域名 CDN 服务器上的 a.js,b.js,c.js 就可以按如下方式在一个请求中下载。

<scriptsrc="//cdn.domain.com/path/a.js,b.js,c.js"></script>

11.使用可缓存的 AJAX

对于返回内容相同的请求,没必要每次都直接从服务端拉取,合理使用 AJAX 缓存能加快 AJAX 响应速度并减轻服务器压力。

$.ajax({
url : url,
type :'get',
cache :true, //推荐使用缓存data : {},
success (){//...},
error (){//...}
});

12.使用 GET 来完成 AJAX 请求

使用 XMLHttpRequest 时,浏览器中的 POST 方法会发起两次 TCP 数据包传输,首先发送文件头,然后发送 HTTP 正文数据。而使用 GET 时只发送头部,所以在拉取服务端数据时使用 GET 请求效率更高。

$.ajax({
url : url,
type :'get', //推荐使用get完成请求data : {},
success (){//...},
error(){//...}
});

HTTP 请求通常默认带上浏览器端的 Cookie 一起发送给服务器,所以在非必要的情况下,要尽量减少 Cookie 来减小 HTTP 请求的大小。对于静态资源,尽量使用不同的域名来存放,因为 Cookie 默认是不能跨域的,这样就做到了不同域名下静态资源请求的 Cookie 隔离。

14.缩小 favicon.ico 并缓存

有利于 favicon.ico 的重复加载,因为一般一个 Web 应用的 favicon.ico 是很少改变的。

15.推荐使用异步 JavaScript 资源

异步的 JavaScript 资源不会阻塞文档解析,所以允许在浏览器中优先渲染页面,延后加载脚本执行。例如 JavaScript 的引用可以如下设置,也可以使用模块化加载机制来实现。

<scriptsrc="main.js"defer></script><scriptsrc="main.js"async></script>

使用 async 时,加载和渲染后续文档元素的过程和 main.js 的加载与执行是并行的。使用 defer 时,加载后续文档元素的过程和 main.js 的加载是并行的,但是 main.js 的执行要在页面所有元素解析完成之后才开始执行。

16.消除阻塞渲染的 CSS 及 JavaScript

对于页面中加载时间过长的 CSS 或 JavaScript 文件,需要进行合理拆分或延后加载,保证关键路径的资源能快速加载完成。

17.避免使用 CSS import 引用加载 CSS

CSS 中的 @import 可以从另一个样式文件中引入样式,但应该避免这种用法,因为这样会增加 CSS 资源加载的关键路径长度,带有 @import 的 CSS 样式需要在 CSS 文件串行解析到 @import 时才会加载另外的 CSS 文件,大大延后 CSS 渲染完成的时间。

<!--不推荐--><style>
@import"path/main.css";
</style><!--推荐--><linkrel="stylesheet"href="//cdn1.domain.com/path/main.css" >

页面渲染类

1.把 CSS 资源引用放到 HTML 文件顶部

一般推荐将所有 CSS 资源尽早指定在 HTML 文档 <head> 中,这样浏览器可以优先下载 CSS 并尽早完成页面渲染。

2.JavaScript 资源引用放到 HTML 文件底部

JavaScript 资源放到 HTML 文档底部可以防止 JavaScript 的加载和解析执行对页面渲染造成阻塞。由于 JavaScript 资源默认是解析阻塞的,除非被标记为异步或者通过其他的异步方式加载,否则会阻塞 HTML DOM 解析和 CSS 渲染的过程。

3.尽量预先设定图片等大小

在加载大量的图片元素时,尽量预先限定图片的尺寸大小,否则在图片加载过程中会更新图片的排版信息,产生大量的重排

4.不要在 HTML 中直接缩放图片

在 HTML 中直接缩放图片会导致页面内容的重排重绘,此时可能会使页面中的其他操作产生卡顿,因此要尽量减少在页面中直接进行图片缩放。

5.减少 DOM 元素数量和深度

HTML 中标签元素越多,标签的层级越深,浏览器解析 DOM 并绘制到浏览器中所花的时间就越长,所以应尽可能保持 DOM 元素简洁和层级较少。

<!--不推荐--><div><span><ahref="javascript:void(0);"><imgsrc="./path/photo.jpg"alt="图片"></a></span></div><!--推荐--><imgsrc="./path/photo.jpg"alt="图片" >

6.尽量避免在选择器末尾添加通配符

CSS 解析匹配到 渲染树的过程是从右到左的逆向匹配,在选择器末尾添加通配符至少会增加一倍多计算量。

7.减少使用关系型样式表的写法

直接使用唯一的类名即可最大限度的提升渲染引擎绘制渲染树等效率

8.尽量减少使用JS动画

JS 直接操作 DOM 极容易引起页面的重排

9.CSS 动画使用 translate、scale 代替 top、height

尽量使用 CSS3 的 translate、scale 属性代替 top、left 和 height、width,避免大量的重排计算

10.尽量避免使用<table><iframe>

<table> 内容的渲染是将 table 的 DOM 渲染树全部生成完并一次性绘制到页面上的,所以在长表格渲染时很耗性能,应该尽量避免使用它,可以考虑使用列表元素 <ul> 代替。尽量使用异步的方式动态添加 iframe,因为 iframe 内资源的下载进程会阻塞父页面静态资源的下载与 CSS 及 HTML DOM 的解析。

11.避免运行耗时的 JavaScript

长时间运行的 JavaScript 会阻塞浏览器构建 DOM 树、DOM 渲染树、渲染页面。所以,任何与页面初次渲染无关的逻辑功能都应该延迟加载执行,这和 JavaScript 资源的异步加载思路是一致的。

12.避免使用 CSS 表达式或 CSS 滤镜

CSS 表达式或 CSS 滤镜的解析渲染速度是比较慢的,在有其他解决方案的情况下应该尽量避免使用。

//不推荐
.opacity{
filter :progid : DXImageTransform.Microsoft.Alpha( opacity = 50 );
}

移动端浏览器前端优化策略

相对于桌面端浏览器,移动端 Web 浏览器上有一些较为明显的特点:设备屏幕较小、新特性兼容性较好、支持一些较新的 HTML5 和 CSS3 特性、需要与 Native 应用交互等。但移动端浏览器可用的 CPU 计算资源和网络资源极为有限,因此要做好移动端 Web 上的优化往往需要做更多的事情。首先,在移动端 Web 的前端页面渲染中,桌面浏览器端上的优化规则同样适用,此外针对移动端也要做一些极致的优化来达到更好的效果。需要注意的是,并不是移动端的优化原则在桌面浏览器端就不适用,而是由于兼容性和差异性的原因,一些优化原则在移动端更具代表性。

网络加载类

1.首屏数据请求提前,避免 JavaScript 文件加载后才请求数据

为了进一步提升页面加载速度,可以考虑将页面的数据请求尽可能提前,避免在 JavaScript 加载完成后才去请求数据。通常数据请求是页面内容渲染中关键路径最长的部分,而且不能并行,所以如果能将数据请求提前,可以极大程度上缩短页面内容的渲染完成时间。

2.首屏加载和按需加载,非首屏内容滚屏加载,保证首屏内容最小化

由于移动端网络速度相对较慢,网络资源有限,因此为了尽快完成页面内容的加载,需要保证首屏加载资源最小化,非首屏内容使用滚动的方式异步加载。一般推荐移动端页面首屏数据展示延时最长不超过3秒。目前中国联通 3G 的网络速度为 338KB/s(2.71Mb/s),所以推荐首屏所有资源大小不超过 1014KB,即大约不超过 1MB。

3.模块化资源并行下载

在移动端资源加载中,尽量保证 JavaScript 资源并行加载,主要指的是模块化 JavaScript 资源的异步加载,例如AMD的异步模块,使用并行的加载方式能够缩短多个文件资源的加载时间。

4.inline 首屏必备的 CSS 和 JavaScript

通常为了在 HTML 加载完成时能使浏览器中有基本的样式,需要将页面渲染时必备的 CSS 和 JavaScript 通过 <script><style> 内联到页面中,避免页面 HTML 载入完成到页面内容展示这段过程中页面出现空白。

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>样例</title><metaname="viewport"content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"><style>/*必备的首屏CSS*/html,body{
margin:0;
padding:0;
background-color:#ccc;
}
</style></head><body></body></html>

5.meta dns prefetch 设置 DNS 预解析

设置文件资源的 DNS 预解析,让浏览器提前解析获取静态资源的主机 IP,避免等到请求时才发起 DNS 解析请求。通常在移动端 HTML 中可以采用如下方式完成。

<!--cdn域名预解析--><metahttp-equiv="x-dns-prefetch-control"content="on" ><linkrel="dns-prefetch"href="//cdn.domain.com" >

6.资源预加载

对于移动端首屏加载后可能会被使用的资源,需要在首屏完成加载后尽快进行加载,保证在用户需要浏览时已经加载完成,这时候如果再去异步请求就显得很慢。

7.合理利用MTU策略

通常情况下,我们认为 TCP 网络传输的最大传输单元(Maximum Transmission Unit,MTU)为 1500B,即一个RTT(Round-Trip Time,网络请求往返时间)内可以传输的数据量最大为 1500 字节。因此,在前后端分离的开发模式中,尽量保证页面的 HTML 内容在 1KB 以内,这样整个 HTML 的内容请求就可以在一个 RTT 内请求完成,最大限度地提高 HTML 载入速度。

缓存类

1.合理利用浏览器缓存

除了上面说到的使用 Cache-Control、Expires、Etag 和 Last-Modified 来设置 HTTP 缓存外,在移动端还可以使用 localStorage 等来保存 AJAX 返回的数据,或者使用 localStorage 保存 CSS 或 JavaScript 静态资源内容,实现移动端的离线应用,尽可能减少网络请求,保证静态资源内容的快速加载。

2.静态资源离线方案

对于移动端或 Hybrid 应用,可以设置离线文件或离线包机制让静态资源请求从本地读取,加快资源载入速度,并实现离线更新。关于这块内容,我们会在后面的章节中重点讲解。

3.尝试使用 AMP HTML

AMP HTML 可以作为优化前端页面性能的一个解决方案,使用 AMP Component 中的元素来代替原始的页面元素进行直接渲染。

<!--不推荐--><videowidth="400"height="300"src="http://www.domain.com/videos/myvideo.mp4"poster="path/poster.jpg"><divfallback><p>Your browser doesn’t support HTML5 video</p></div><sourcetype="video/mp4"src="foo.mp4"><sourcetype="video/webm"src="foo.webm"></video><!--推荐--><amp-videowidth="400"height="300"src="http://www.domain.com/videos/myvideo.mp4"poster="path/poster.jpg"><divfallback><p>Your browser doesn’t support HTML5 video</p></div><sourcetype="video/mp4"src="foo.mp4"><sourcetype="video/webm"src="foo.webm"></amp-video>

4.尝试使用 PWA 模式

PWA(Progressive Web Apps)是 Google 提出的用前沿的 Web 技术为网页提供 App 般使用体验的一系列方案。

图片类

1.图片压缩处理

在移动端,通常要保证页面中一切用到的图片都是经过压缩优化处理的,而不是以原图的形式直接使用的,因为那样很消耗流量,而且加载时间更长。

2.使用较小的图片,合理使用 base64 内嵌图片

在页面使用的背景图片不多且较小的情况下,可以将图片转化成 base64 编码嵌入到 HTML 页面或 CSS 文件中,这样可以减少页面的 HTTP 请求数。需要注意的是,要保证图片较小,一般图片大小超过 2KB 就不推荐使用 base64 嵌入显示了。

.class-name{
background-image : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAALCAMAAABxsOwqAAAAYFBMVEWnxwusyQukxQudwQyZvgyhxAyfwgyxzAsUHQGOuA0aJAERGAFIXwSTugyEqgtqhghQZgUwQQIpOQKbuguVtQuKrAuCowp2kQlheghTbQZHWQU7SwVAVgQ6TgQlLwMeKwFOemyQAAAAVElEQVQI1y3JVRaAIAAF0UconXbvf5ei8HfPDIQQhBAAFE10iKig3SLRNN4SP/p+N08VC0YnfIlNWtqIkhg/TPYbCvhqdHAWRXPZSp3g3CWZvVLXC6OJA3ukv0AaAAAAAElFTkSuQmCC');
}

3.使用更高压缩比格式的图片

使用具有较高压缩比格式的图片,如 webp(需要设计降级兼容方案)等。在同等图片画质的情况下,高压缩比格式的图片体积更小,能够更快完成文件传输,节省网络流量。

<img src="//cdn.domain.com/path/photo.webp" alt="webp格式图片" >

4.图片懒加载

为了保证页面内容的最小化,加速页面的渲染,尽可能节省移动端网络流量,页面中的图片资源推荐使用懒加载实现,在页面滚动时动态载入图片。

<img data-src="//cdn.domain.com/path/photo.jpg" alt="懒加载图片" >

5.使用 MediaQuery 或 srcset 根据不同屏幕加载不同大小图片

在介绍响应式的章节中我们了解到,针对不同的移动端屏幕尺寸和分辨率,输出不同大小的图片或背景图能保证在用户体验不降低的前提下节省网络流量,加快部分机型的图片加载速度,这在移动端非常值得推荐。

6.使用 iconfont 代替图片图标

在页面中尽可能使用 iconfont 来代替图片图标,这样做的好处有以下几个:

  • 使用 iconfont 体积较小,而且是矢量图,因此缩放时不会失真;

  • 可以方便地修改图片大小尺寸和呈现颜色。

但是需要注意的是,iconfont 引用不同 webfont 格式时的兼容性写法,根据经验推荐尽量按照以下顺序书写,否则不容易兼容到所有的浏览器上。

@font-face{
font-family:iconfont;
src:url("./iconfont.eot");
src:url("./iconfont.eot?#iefix") format("eot"),
url("./iconfont.woff") format("woff"),
url("./iconfont.ttf") format("truetype");
}

7.定义图片大小限制

加载的单张图片一般建议不超过 30KB,避免大图片加载时间长而阻塞页面其他资源的下载,因此推荐在 10KB 以内。如果用户上传的图片过大,建议设置告警系统,帮助我们观察了解整个网站的图片流量情况,做出进一步的改善。

8.强缓存策略

对于一些「永远」不会变的图片可以使用强缓存的方式缓存在用户的浏览器上。

脚本类

1.尽量使用 id

选择器选择页面 DOM 元素时尽量使用 id 选择器,因为 id 选择器速度最快。

2.合理缓存 DOM 对象

对于需要重复使用的 DOM 对象,要优先设置缓存变量,避免每次使用时都要从整个DOM树中重新查找。

//不推荐
$('#mod.active').remove('active');
$('#mod.not-active').addClass('active');

//推荐
let $mod=$('#mod');
$mod.find('.active').remove('active');
$mod.find('.not-active').addClass('active');

3.页面元素尽量使用事件代理,避免直接事件绑定

使用事件代理可以避免对每个元素都进行绑定,并且可以避免出现内存泄露及需要动态添加元素的事件绑定问题,所以尽量不要直接使用事件绑定。

//不推荐
$('.btn').on('click',function(e){
console.log(this);
});

//推荐
$('body').on('click','.btn',function(e){
console.log(this);
});

4.使用 touchstart 代替 click

由于移动端屏幕的设计, touchstart 事件和 click 事件触发时间之间存在 300 毫秒的延时,所以在页面中没有实现 touchmove 滚动处理的情况下,可以使用 touchstart 事件来代替元素的 click 事件,加快页面点击的响应速度,提高用户体验。但同时我们也要注意页面重叠元素 touch 动作的点击穿透问题。

//不推荐
$('body').on('click','.btn',function(e){
console.log(this);
});

//推荐
$('body').on('touchstart','.btn',function(e){
console.log(this);
});

5.避免 touchmove、scroll 连续事件处理

需要对 touchmove、scroll 这类可能连续触发回调的事件设置事件节流,例如设置每隔 16ms(60 帧的帧间隔为 16.7ms,因此可以合理地设置为 16ms )才进行一次事件处理,避免频繁的事件调用导致移动端页面卡顿。

//不推荐
$('.scroller').on('touchmove','.btn',function(e){
console.log(this);
});

//推荐
$('.scroller').on('touchmove','.btn',function(e){
let self=this;
setTimeout(function(){
console.log(self);
},16);
});

6.避免使用 eval、with,使用 join 代替连接符+,推荐使用 ECMAScript6 的字符串模板

这些都是一些基础的安全脚本编写问题,尽可能使用较高效率的特性来完成这些操作,避免不规范或不安全的写法。

7.尽量使用 ECMAScript6+的特性来编程

ECMAScript6+ 一定程度上更加安全高效,而且部分特性执行速度更快,也是未来规范的需要,所以推荐使用 ECMAScript6+ 的新特性来完成后面的开发。

渲染类

1.使用 Viewport 固定屏幕渲染,可以加速页面渲染内容

一般认为,在移动端设置 Viewport 可以加速页面的渲染,同时可以避免缩放导致页面重排重绘。在移动端固定 Viewport 设置的方法如下。

<!--设置viewport不缩放--><metaname="viewport"content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">

2.避免各种形式重排重绘

页面的重排重绘很耗性能,所以一定要尽可能减少页面的重排重绘,例如页面图片大小变化、元素位置变化等这些情况都会导致重排重绘。

3.使用 CSS3 动画,开启GPU加速

使用 CSS3 动画时可以设置 transform:translateZ(0) 来开启移动设备浏览器的GPU图形处理加速,让动画过程更加流畅,但需要注意的是,在 Native WebView 下 GPU 加速有几率产生 App Crash。

-webkit-transform:translateZ(0);
-ms-transform:translateZ(0);
-o-transform:translateZ(0);
transform:translateZ(0);

4.合理使用 Canvas 和 requestAnimationFrame

选择 Canvas 或 requestAnimationFrame 等更高效的动画实现方式,尽量避免使用 setTimeout、setInterval 等方式来直接处理连续动画。

5.SVG 代替图片

部分情况下可以考虑使用 SVG 代替图片实现动画,因为使用 SVG 格式内容更小,而且 SVG DOM 结构方便调整。

6.不滥用 float

在 DOM 渲染树生成后的布局渲染阶段,使用 float 的元素布局计算比较耗性能,所以尽量减少 float 的使用,推荐使用固定布局或 flex-box 弹性布局的方式来实现页面元素布局。

7.不滥用 web 字体或过多 font-size 声明

过多的 font-size 声明会增加字体的大小计算,而且也没有必要的。

8.做好脚本容错

脚本容错可以避免「非正常环境」的执行错误影响页面的加载和不相关功能的使用

架构协议类

1.尝试使用 SPDY 和 HTTP2

在条件允许的情况下可以考虑使用 SPDY 协议来进行文件资源传输,利用连接复用加快传输过程,缩短资源加载时间。HTTP2 在未来也是可以考虑尝试的。

2.使用后端数据渲染

使用后端数据渲染的方式可以加快页面内容的渲染展示,避免空白页面的出现,同时可以解决移动端页面SEO的问题。如果条件允许,后端数据渲染是一个很不错的实践思路。后面的章节会详细介绍后端数据渲染的相关内容。

3.使用 NativeView 代替 DOM 的性能劣势

可以尝试使用 NativeView 的 MNV* 开发模式来避免 HTML DOM 性能慢的问题,目前使用 MNV* 的开发模式已经可以将页面内容渲染体验做到接近客户端 Native 应用的体验了。但需要避免 js Framework 和 native Framework 的频繁交互。

· 阅读需 3 分钟

class Parent(object): def init(self, name): self.name = name

    def say(self):
print('this is %s' % self.name)


class Child(Parent):
def __init__(self, name, age):
Parent.__init__(self, name)
self.age = age
def say(self):
print('this is %s, his age is %s' % (self.name, self.age))

child = Child('Bob', 1)
child.say()

运行结果

this is Bob, his age is 1

super 继承

修改 Child 类

class Child(Parent): def init(self, name, age): super(Child, self).init(name) self.age = age

def say(self): print('this is %s, his age is %s' % (self.name, self.age))

第三行把 Parent 改成了 super(Child, self),并且去掉了后面__init__中的 self,

运行结果与上面是一样的

这里使用了 super, self 会隐式传入 init 中,可是感觉这样写其实有点多余,比较 super 中的 Child 和 self 都是固定的不是吗,每次写都很麻烦

于是,找到了一颗语法糖

直接写 super(), 删除 Child 和 self 也是可行的

普通继承和 super 的不同点

表面上看 普通继承和 super 继承的结果是一致的,实际上这两种方法的内部处理机制大大不同,当涉及多继承情况时,就会表现出明显的差异来,直接给例子:

代码一:

class A:
def __init__(self):
print("Enter A")
print("Leave A")

class B(A):
def __init__(self):
print("Enter B")
A.__init__(self)
print("Leave B")

class C(A):
def __init__(self):
print("Enter C")
A.__init__(self)
print("Leave C")

class D(A):
def __init__(self):
print("Enter D")
A.__init__(self)
print("Leave D")

class E(B, C, D):
def __init__(self):
print("Enter E")
B.__init__(self)
C.__init__(self)
D.__init__(self)
print("Leave E")

E()

结果:

Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E

执行顺序很好理解,唯一需要注意的是公共父类 A 被执行了多次。

代码二:

class A:
def __init__(self):
print("Enter A")
print("Leave A")

class B(A):
def __init__(self):
print("Enter B")
super(B, self).__init__()
print("Leave B")

class C(A):
def __init__(self):
print("Enter C")
super(C, self).__init__()
print("Leave C")

class D(A):
def __init__(self):
print("Enter D")
super(D, self).__init__()
print("Leave D")

class E(B, C, D):
def __init__(self):
print("Enter E")
super(E, self).__init__()
print("Leave E")

E()

结果:

Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E

在 super 机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照 mro 进行的(E.__mro__)

· 阅读需 34 分钟

1. 简介

Vim(Vi[Improved])编辑器是功能强大的跨平台文本文件编辑工具,继承自 Unix 系统的 Vi 编辑器,支持 Linux/Mac OS X/Windows 系统,利用它可以建立、修改文本文件。进入 Vim 编辑程序,可以在终端输入下面的命令:

$vim [filename]

其中filename是要编辑器的文件的路径名。如果文件不存在,它将为你建立一个新文件。Vim 编辑程序有三种操作模式,分别称为 编辑模式插入模式命令模式,当运行 Vim 时,首先进入编辑模式。

2. 编辑模式

Vim 编辑方式的主要用途是在被编辑的文件中移动光标的位置。一旦光标移到到所要的位置,就可以进行剪切和粘贴正文块,删除正文和插入新的正文。当完成所有的编辑工作后,需要保存编辑器结果,退出编辑程序回到终端,可以发出ZZ命令,连续按两次大写的Z键。

2.1 跳转

如果键盘上有上、下、左、右箭头的导航键,就由这些键来完成光标的移动。另外,可以用下面的键完成同样的 按字符移动 功能:

k                上移;
j 下移;
h 左移;
l 右移。

上面这4个键将光标位置每次移动一行或一个 字符 。Vim 还提供稍大范围移动光标的命令:

ctrl+f        在文件中前移一页(相当于 page down);
ctrl+b 在文件中后移一页(相当于 page up);

更大范围的移动:

*          当光标停留在一个单词上,* 键会在文件内搜索该单词,并跳转到下一处;
# 当光标停留在一个单词上,# 在文件内搜索该单词,并跳转到上一处;
(/) 移动到 前/后 句 的开始;
{/} 跳转到 当前/下一个 段落 的开始。
g_ 到本行最后一个不是 blank 字符的位置。
fa 到下一个为 a 的字符处,你也可以fs到下一个为s的字符。
t, 到逗号前的第一个字符。逗号可以变成其它字符。
3fa 在当前行查找第三个出现的 a。
F/T 和 f 和 t 一样,只不过是相反方向;
gg 将光标定位到文件第一行起始位置;
G 将光标定位到文件最后一行起始位置;
NG或Ngg 将光标定位到第 N 行的起始位置。

在屏幕中找到需要的 一页 时,可以用下面的命令快速移动光标:

H                将光标移到屏幕上的起始行(或最上行);
M 将光标移到屏幕中间;
L 将光标移到屏幕最后一行。

同样需要注意字母的大小写。HL 命令还可以加数字。如 2H 表示将光标移到屏幕的第2行,3L 表示将光标移到屏幕的倒数第 3 行。 当将光标移到所要的行是,行内移动 光标可以用下面的命令来实现:

w                右移光标到下一个字的开头;
e 右移光标到一个字的末尾;
b 左移光标到前一个字的开头;
0 数字0,左移光标到本行的开始;
$ 右移光标,到本行的末尾;
^ 移动光标,到本行的第一个非空字符。

2.2 搜索匹配

和许多先进的编辑器一样,Vim 提供了强大的字符串搜索功能。要查找文件中指定字或短语出现的位置,可以用 Vim 直接进行搜索,而不必以手工方式进行。搜索方法是:键入字符 / ,后面跟以要搜索的字符串,然后按回车键。编辑程序执行正向搜索(即朝文件末尾方向),并在找到指定字符串后,将光标停到该字符串的开头;键入 n 命令可以继续执行搜索,找出这一字符串下次出现的位置。用字符 ? 取代 / ,可以实现反向搜索(朝文件开头方向)。例如:

/str1                正向搜索字符串 str1;
n 继续搜索,找出 str1 字符串下次出现的位置;
N 继续搜索,找出 str1 字符串上一次出现的位置;
?str2 反向搜索字符串 str2 。

无论搜索方向如何,当到达文件末尾或开头时,搜索工作会循环到文件的另一端并继续执行。 Vim 中执行搜索匹配最强大的地方是结合 正则表达式 来搜索,后续将会介绍。

2.3 替换和删除

Vim 常规的删除命令是 dx (前者删除 ,后者删除 字符 ),结合 Vim 的其他特性可以实现基础的删除功能。将光标定位于文件内指定位置后,可以用其他字符来替换光标所指向的字符,或从当前光标位置删除一个或多个字符或一行、多行。例如:

rc                 用 c 替换光标所指向的当前字符;
nrc 用 c 替换光标所指向的前 n 个字符;
5rA 用 A 替换光标所指向的前 5 个字符;
x 删除光标所指向的当前字符;
nx 删除光标所指向的前 n 个字符;
3x 删除光标所指向的前 3 个字符;
dw 删除光标右侧的字;
ndw 删除光标右侧的 n 个字;
3dw 删除光标右侧的 3 个字;
db 删除光标左侧的字;
ndb 删除光标左侧的 n 个字;
5db 删除光标左侧的 5 个字;
dd 删除光标所在行,并去除空隙;
ndd 删除(剪切) n 行内容,并去除空隙;
3dd 删除(剪切) 3 行内容,并去除空隙;

其他常用的删除命令有:

d$                从当前光标起删除字符直到行的结束;
d0 从当前光标起删除字符直到行的开始;
J 删除本行的回车符(CR),并和下一行合并。

Vim 常规的替换命令有 cs ,结合 Vim 的其他特性可以实现基础的替换功能,不过替换命令执行以后,通常会由 编辑模式 进入 插入模式

s                用输入的正文替换光标所指向的字符;
S 删除当前行,并进入编辑模式;
ns 用输入的正文替换光标右侧 n 个字符;
nS 删除当前行在内的 n 行,并进入编辑模式;
cw 用输入的正文替换光标右侧的字;
cW 用输入的正文替换从光标到行尾的所有字符(同 c$ );
ncw 用输入的正文替换光标右侧的 n 个字;
cb 用输入的正文替换光标左侧的字;
ncb 用输入的正文替换光标左侧的 n 个字;
cd 用输入的正文替换光标的所在行;
ncd 用输入的正文替换光标下面的 n 行;
c$ 用输入的正文替换从光标开始到本行末尾的所有字符;
c0 用输入的正文替换从本行开头到光标的所有字符。

2.4 复制粘贴

从正文中删除的内容(如字符、字或行)并没有真正丢失,而是被剪切并复制到了一个内存缓冲区中。用户可将其粘贴到正文中的指定位置。完成这一操作的命令是:

p               小写字母 p,将缓冲区的内容粘贴到光标的后面;
P 大写字母 P,将缓冲区的内容粘贴到光标的前面。

如果缓冲区的内容是字符或字,直接粘贴在光标的前面或后面;如果缓冲区的内容为整行正文,执行上述粘贴命令将会粘贴在当前光标所在行的上一行或下一行。 注意上述两个命令中字母的大小写。Vim 编辑器经常以一对大、小写字母(如 pP)来提供一对相似的功能。通常,小写命令在光标的后面进行操作,大写命令在光标的前面进行操作。

有时需要复制一段正文到新位置,同时保留原有位置的内容。这种情况下,首先应当把指定内容复制(而不是剪切)到内存缓冲区。完成这一操作的命令是:

yy              复制当前行到内存缓冲区;
nyy 复制 n 行内容到内存缓冲区;
5yy 复制 5 行内容到内存缓冲区;
“+y 复制 1 行到操作系统的粘贴板;
“+nyy 复制 n 行到操作系统的粘贴板。

2.5 撤销和重复

在编辑文档的过程中,为消除某个错误的编辑命令造成的后果,可以用撤消命令。另外,如果用户希望在新的光标位置重复前面执行过的编辑命令,可用重复命令。

u               撤消前一条命令的结果;
. 重复最后一条修改正文的命令。

3. 插入模式

3.1 进入插入模式

在编辑模式下正确定位光标之后,可用以下命令切换到插入模式:

i            在光标左侧插入正文
a 在光标右侧插入正文
o 在光标所在行的下一行增添新行
O 在光标所在行的上一行增添新行
I 在光标所在行的开头插入
A 在光标所在行的末尾插入

3.2 退出插入模式

退出插入模式的方法是,按 ESC 键或组合键 Ctrl+[ ,退出插入模式之后,将会进入编辑模式 。

4. 命令模式

在 Vim 的命令模式下,可以使用复杂的命令。在编辑模式下键入 : ,光标就跳到屏幕最后一行,并在那里显示冒号,此时已进入命令模式。命令模式又称 末行模式 ,用户输入的内容均显示在屏幕的最后一行,按回车键,Vim 执行命令。

4.1 打开、保存、退出

在已经启动的 Vim 中打开一个文件需要用 :e 命令:

:e path_to_file/filename

保存当前编辑的文件需要用 :w 命令(单词 write 的缩写):

:w

将当前文件另存为 file_temp 则:

:w file_temp

在编辑模式下可以用 ZZ 命令退出 Vim 编辑程序,该命令保存对正文所作的修改,覆盖原始文件。如果只需要退出编辑程序,而不打算保存编辑的内容,可用下面的命令:

: q                在未作修改的情况下退出;
: q! 放弃所有修改,退出编辑程序。

保存并退出则可以讲两条命令结合起来使用(注意命令顺序,先保存,后退出):

:wq

4.2 行号与文件

编辑中的每一行正文都有自己的行号,用下列命令可以移动光标到指定行(效果与 编辑模式 下的 nggnG 相同):

: n             将光标移到第 n 行

命令模式下,可以规定命令操作的行号范围。数值用来指定绝对行号;字符“.”表示光标所在行的行号;字符符“\$”表示正文最后一行的行号;简单的表达式,例如“.+5”表示当前行往下的第 5 行。例如:

:345                  将光标移到第 345 行
:345w file 将第 345 行写入 file 文件
:3,5w file 将第 3 行至第 5 行写入 file 文件
:1,.w file 将第 1 行至当前行写入 file 文件
:.,$w file 将当前行至最后一行写入 file 文件
:.,.+5w file 从当前行开始将 6 行内容写入 file 文件
:1,$w file 将所有内容写入 file 文件,相当于 :w file 命令

在命令模式下,允许从文件中读取正文,或将正文写入文件。例如:

:w                 将编辑的内容写入原始文件,用来保存编辑的中间结果
:wq 将编辑的内容写入原始文件并退出编辑程序(相当于 ZZ 命令)
:w file 将编辑的内容写入 file 文件,保持原有文件的内容不变
:a,bw file 将第 a 行至第 b 行的内容写入 file 文件
:r file 读取 file 文件的内容,插入当前光标所在行的后面
:e file 编辑新文件 file 代替原有内容
:f file 将当前文件重命名为 file
:f 打印当前文件名称和状态,如文件的行数、光标所在的行号等

4.3 字符串搜索

编辑模式 讲过字符串的搜索,此处的 命令模式 也可以进行字符串搜索,给出一个字符串,可以通过搜索该字符串到达指定行。如果希望进行正向搜索,将待搜索的字符串置于两个 / 之间;如果希望反向搜索,则将字符串放在两个 ? 之间。例如:

:/str/                  正向搜索,将光标移到下一个包含字符串 str 的行
:?str? 反向搜索,将光标移到上一个包含字符串 str 的行
:/str/w file 正向搜索,并将第一个包含字符串 str 的行写入 file 文件
:/str1/,/str2/w file 正向搜索,并将包含字符串 str1 的行至包含字符串 str2 的行写

4.4 Vim 中的正则表达式

当给 Vim 指定搜索字符串时,可以包含具有特殊含义的字符。包含这些特殊字符的搜索字符串称为正则表达式(Regular Expressions)。例如,要搜索一行正文,这行正文的开头包含 struct 字。下面的命令做不到这一点:

:/struct/

因为它只找出在行中任意位置包含 struct的第一行,并不一定在行的开始包含 struct 。解决问题的办法是在搜索字符串前面加上特殊字符^:

:/^struct/

^ 字符比较每行开头的字符串。所以上面的命令表示:找出以字符串 struct 开头的行。 也可以用类似办法在搜索字符串后面加上表示行的末尾的特殊字符 $ 来找出位于行末尾的字:

:/^struct/

下表给出大多数特殊字符和它们的含义:

^                放在字符串前面,匹配行首的字;
$ 放在字符串后面,匹配行尾的字;
\< 匹配一个字的字头;
\> 匹配一个字的字尾;
. 匹配任何单个正文字符;
[str] 匹配 str 中的任何单个字符;
[^str] 匹配任何不在 str 中的单个字符;
[a-b] 匹配 a 到 b 之间的任一字符;
* 匹配前一个字符的 0 次或多次出现;
\ 转义后面的字符。

简单介绍这么多,正则表达式知识可以参考 《正则表达式 30 分钟入门》:http://deerchao.net/tutorials/regex/regex.htm 另外,进阶的 Vim 正则表达式还有对 Magic 模式的介绍,可以参考 《Vim 正则表达式详解》: http://blog.csdn.net/salc3k/article/details/8222397

4.5 正文替换

利用 :s 命令可以实现字符串的替换。具体的用法包括:

:%s/str1/str2/        用字符串 str2 替换行中首次出现的字符串 str1
:s/str1/str2/g 用字符串 str2 替换行中所有出现的字符串 str1
:.,$ s/str1/str2/g 用字符串 str2 替换正文当前行到末尾所有出现的字符串 str1
:1,$ s/str1/str2/g 用字符串 str2 替换正文中所有出现的字符串 str1
:g/str1/s//str2/g 功能同上
:m,ns/str1/str2/g 将从m行到n行的str1替换成str2

从上述替换命令可以看到:

  1. g 放在命令末尾,表示对搜索字符串的每次出现进行替换,不止匹配每行中的第一次出现;不加 g,表示只对搜索字符串的首次出现进行替换;g 放在命令开头,表示对正文中所有包含搜索字符串的行进行替换操作;
  2. s 表示后面跟着一串替换的命令;
  3. % 表示替换范围是所有行,即全文。

另外一个实用的命令,在 Vim 中统计当前文件中字符串 str1 出现的次数,可用替换命令的变形:

:%s/str1/&/gn

4.6 删除正文

在命令模式下,同样可以删除正文中的内容。例如:

:d                              删除光标所在行
:3d 删除 3 行
:.,$d 删除当前行至正文的末尾
:/str1/,/str2/d 删除从字符串 str1 到 str2 的所有行
:g/^\(.*\)$\n\1$/d 删除连续相同的行,保留最后一行
:g/\%(^\1$\n\)\@<=\(.*\)$/d 删除连续相同的行,保留最开始一行
:g/^\s*$\n\s*$/d 删除连续多个空行,只保留一行空行
:5,20s/^#//g 删除5到20行开头的 # 注释

总之,Vim 的初级删除命令是用 d ,高级删除命令可以用 正则替换 的方式执行。

4.7 恢复文件

Vim 在编辑某个文件时,会另外生成一个临时文件,这个文件的名称通常以 . 开头,并以 .swp 结尾。Vim 在正常退出时,该文件被删除,若意外退出,而没有保存文件的最新修改内容,则可以使用恢复命令 :recover 来恢复文件,也可以在启动 Vim 时用 -r 选项。

4.8 选项设置

为控制不同的编辑功能,Vim 提供了很多内部选项。利用 :set 命令可以设置选项。基本语法为:

:set option         设置选项 option

常见的功能选项包括:

autoindent        设置该选项,则正文自动缩进
ignorecase 设置该选项,则忽略规则表达式中大小写字母的区别
number 设置该选项,则显示正文行号
ruler 设置该选项,则在屏幕底部显示光标所在行、列的位置
tabstop 设置按 Tab 键跳过的空格数。例如 :set tabstop=n,n 默认值为 8
mk 将选项保存在当前目录的 .exrc 文件中

4.9 Shell 切换

当处于编辑的对话过程中时,可能需要执行一些 Linux 命令。如果需要保存当前的结果,退出编辑程序,再执行所需的 Linux 命令,然后再回头继续编辑过程,就显得十分累赘。如果能在编辑的环境中运行 Linux 命令就要省事得多。在 Vim 中,可以用下面的命令来做到这一点:

:!shell_command   执行完 shell_command 后回到Vim

这称为 Shell 切换。它允许执行任何可以在标准的 Shell 提示符下执行的命令。当这条命令执行完毕,控制返回给编辑程序。又可以继续编辑对话过程。

4.10 分屏与标签页

分屏

普通的 Vim 模式,打开一个 Vim 程序只能查看一个文件,如果想同时查看多个文件,就需要用到 Vim 分屏与标签页功能。 Vim 的分屏,主要有两种方式:上下分屏(水平分屏)和左右分屏(垂直分屏),在命令模式分别敲入以下命令即可:

:split(可用缩写 :sp)            上下分屏;
:vsplit(可用缩写 :vsp) 左右分屏。

另外,也可以在终端里启动 vim 时就开启分屏操作:

vim -On file1 file2...   打开 file1 和 file2 ,垂直分屏
vim -on file1 file2... 打开 file1 和 file2 ,水平分屏

理论上,一个 Vim 窗口,可以分为多个 Vim 屏幕,切换屏幕需要用键盘快捷键,命令分别有:

Ctrl+w+h            切换到当前分屏的左边一屏;
Ctrl+w+l 切换到当前分屏的右边一屏;
Ctrl+w+j 切换到当前分屏的下方一屏;
Ctrl+w+k 切换到当前分屏的上方一屏。

即键盘上的h,j,k,l 四个 Vim 专用方向键,配合Ctrl键和w键(window的缩写),就能跳转到目标分屏。另外,也可以直接按 Ctrl+w+w 来跳转分屏,不过跳转方向则是在当前 Vim 窗口所有分屏中,按照逆时针方向跳转。 下面是改变尺寸的一些操作,主要是高度,对于宽度你可以使用 [Ctrl+W <] 或是 [Ctrl+W >] ,但这可能需要最新的版本才支持。

Ctrl+W =            让所有的屏都有一样的高度;
Ctrl+W + 增加高度;
Ctrl+W - 减少高度。

标签页

Vim 的标签(Tab)页,类似浏览器的标签页,一个标签页打开一个 Vim 的窗口,一个 Vim 的窗口可以支持 N 个分屏。 在 Vim 中新建一个标签的命令是:

:tabnew

如果要在新建标签页的同时打开一个文件,则可以在命令后面直接附带文件路径:

:tabnew filename

Vim 中的每个标签页有一个唯一的数字序号,第一个标签页的序号是0,从左向右依次加一。关于标签页有一系列操作命令,简介如下:

:tN[ext]                跳转到上一个匹配的标签
:tabN[ext] 跳到上一个标签页
:tabc[lose] 关闭当前标签页
:tabdo 为每个标签页执行命令
:tabe[dit] 在新标签页里编辑文件
:tabf[ind] 寻找 'path' 里的文件,在新标签页里编辑之
:tabfir[st] 转到第一个标签页
:tabl[ast] 转到最后一个标签页
:tabm[ove] N 把标签页移到序号为N位置
:tabnew [filename] 在新标签页里编辑文件
:tabn[ext] 转到下一个标签页
:tabo[nly] 关闭所有除了当前标签页以外的所有标签页
:tabp[revious] 转到前一个标签页
:tabr[ewind] 转到第一个标签页

4.11 与外部工具集成

Vim 可以与许多外部程序集成,功能十分强大,比如 diff , ctags , sort , xxd 等等,下面选取几个简单介绍一下。

diff

Linux 命令 diff 用来对比两个文件的内容,不过对比结果显示在终端里,可读性比较差。结合 Vim,在终端里可以直接输入命令 vimdiff,后面跟两个文件名作为参数:

vimdiff file1 file2

即可在 Vim 里分屏显示两个文件内容的对比结果,对文件内容差异部分进行高亮标记,还可以同步滚动两个文件内容,更可以实时修改文件内容,方便程度和用户体验大大提高。

vimdiff a.txt b.txt

如果直接给 -d 选项是一样的

vim -d a.txt b.txt

除了在终端里开启 vimdiff 功能,也可以在打开 Vim 后,在 Vim 的命令模式输入相关命令来开启 vimdiff 功能:

:diffsplit abc.txt

如果你现在已经开启了一个文件,想 Vim 帮你区分你的文件跟 abc.txt 有什么区别,可以在 Vim 中用 diffsplit 的方式打开第二个文件,这个时 候 Vim 会用 split(分上下两屏)的方式开启第二个文件,并且通过颜色,fold来显示两个文件的区别 这样 Vim 就会用颜色帮你区分开 2 个文件的区别。如果文件比较大(源码)重复的部分会帮你折叠起来。

:diffpatch filename

通过 :diffpatch 你的 patch 的文件名,就可以以当前文件加上你的 patch 来显示。vim 会 split 一个新的屏,显示 patch 后的信息并且用颜色标明区别。 如果不喜欢上下对比,喜欢左右(比较符合视觉)可以在前面加 vert ,例如:

:vert diffsplit abc.txt
:vert diffpatch abc.txt

看完 diff,用 :only 回到原本编辑的文件,觉得 diff 的讨厌颜色还是在哪里,只要用 :diffoff 关闭就好了。 还有个常用的 diff 中的就是 :diffu ,这个是 :diffupdate 的简写,更新的时候用。 Vim 的diff功能显示效果如下所示:

图片来自 http://www.2cto.com/net/201608/536924.html

sort

Linux 命令 sort 可以对文本内容进行按行中的字符比较、排序,但在终端里使用 sort 命令处理文件,并不能实时查看文件内容。具体用法请自查手册。

xxd

vim+xxd 是 Linux 下最常用的二进制文本编辑工具,xxd其实是 Vim 外部的一个转换程序,随 Vim 一起发布,在 Vim 里调用它来编辑二进制文本非常方便。 首先以二进制模式在终端里打开一个文件:

vim -b filename

Vim 的 -b 选项是告诉 Vim 打开的是一个二进制文件,不指定的话,会在后面加上 0x0a ,即一个换行符。 然后在 Vim 的命令模式下键入:

:%!xxd

即可看到二进制模式显示出来的文本,看起来像这样:

 0000000: 1f8b 0808 39d7 173b 0203 7474 002b 4e49  ....9..;..tt.+NI
0000010: 4b2c 8660 eb9c ecac c462 eb94 345e 2e30 K,......b..4^.0
0000020: 373b 2731 0b22 0ca6 c1a2 d669 1035 39d9 7;'1.".....i.59

然后就可以在二进制模式下编辑该文件,编辑后保存,然后用下面命令从二进制模式转换到普通模式:

:%!xxd -r

另外,也可以调整二进制的显示模式,默认是 2 个字节为一组,可以通过 g 参数调整每组字节数:

:%!xxd -g 1         表示每1个字节为1组
:%!xxd -g 2 表示每2个字节为1组(默认)
:%!xxd -g 4 表示每4个字节为1组

5. Vim 配置

最初安装的 Vim 功能、特性支持比较少,用起来比较费劲,想要稍微“好用”一点,需做一些初步的配置。Vim 的配置主要分为 Vim 本身特性的配置和外部插件的配置两部分。 Vim 的配置是通常是存放在用户主目录的 .vimrc 的隐藏文件中的。就 Vim 本身特性来说,基础的配置有编程语言语法高亮、缩进设置、行号显示、搜索高亮、TAB 键设置、字体设置、Vim 主题设置等等,稍微高级一些的有编程语言缩进、自动补全设置等,具体配置项可以自行查资料,全面详细的配置项介绍可以参考: 《Vim Options》: http://vimcdoc.sourceforge.net/doc/options.html#%27completeopt%27

6. Vim 插件

Vim“编辑器之神”的称号并不是浪得虚名,然而,这个荣誉的背后,或许近半的功劳要归功于强大的插件支持特性,以及社区开发的各种各样功能强大的插件。

平时开发人员常用插件主要是目录(文件)查看和管理、编程语言缩进与自动补全、编程语言 Docs 支持、函数跳转、项目管理等等,简单配置可以参考下面:

《Vim 插件简单介绍》: http://blog.segmentfault.com/xuelang/1190000000630547

《手把手教你把 Vim 改装成一个 IDE 编程环境(图文)》: http://blog.csdn.net/wooin/article/details/1858917

《将 Vim 改造为强大的 IDE》: http://www.cnblogs.com/zhangsf/archive/2013/06/13/3134409.html

当然,这些插件都是拜 Vim 本身的插件支持特性所赐。Vim 为了支持丰富的第三方插件,自身定义了一套简单的脚本开发语言,供程序员自行开发自己所需要的插件,插件开发介绍可以参考:

《Writing Vim Plugins》: http://stevelosh.com/blog/2011/09/writing-vim-plugins/

7. Vim 完整文档

  1. Vim 官方文档:http://vimdoc.sourceforge.net/
  2. Vim 中文用户手册 7_3.pdf :http://pan.baidu.com/s/1jGzbTBo

vim cheat-sheet

vim快捷键 vim键盘图

· 阅读需 7 分钟

初始准备工作

mkdir learngit 创建 learngit 文件夹
cd learngit 进入 learngit 文件夹
pwd 显示当前目录

基本操作

git init git 仓库初始化,把目录变成 git 可以管理的仓库

git add readme.txt 将当前目录下的 readme.txt 加入到 git 仓库的暂存区
git commit -m "wrote a readme file" 将暂存区的 readme.txt 提交到分支上

git status 查看状态

git diff HEAD -- readme.txt 查看版本库和工作区里面最新版本的区别

.gitignore 用于 git 忽略某些文件和文件夹的配置文件

git log 显示从最近到最远的提交日志

git log --pretty=oneline git log 的美观版本,过滤掉许多信息,更简洁

版本回退

git reset --hard HEAD^ 回退到上一个版本
git reset --hard "HEAD^" 在 windows 中需要加入双引号
git reset --hard HEAD"^" 在 windows 中的另一种写法
git reset --hard "HEAD^^" 回退到上上个版本
git reset --hard HEAD~1 回退到上一个版本,将数字 1 改为 n 就是回退到前 n 个版本 git reset --hard commit 的版本号 回退到制定版本,参数为该版本的版本号

git reflog 显示每一次命令,版本回退的版本号也可以从中查看

文件恢复与删除

git checkout -- readme.txt 让 readme.txt 回到最近一次 git commit 或者 git add 时的状态,也就是把工作区中的文件恢复成版本库中的文件

git rm test.txt 将本地的和版本库中的 test.txt 文件都删除,想要恢复就得先将操作过的其他文件转移,再进行版本回退,之后再将其他文件转移回来
如果只是本地的文件被删除了,可以 git checkout -- file 恢复
git commit -m "remove test.txt" 再更新一下分支

github 仓库使用

ssh-keygen -t rsa -C "[email protected]" 创建 SSH Key,创建后在用户主目录下的.ssh 目录中会有 id_rsa 和 id_rsa.pub 两个文件,其中 id_rsa.pub 是公钥,id_rsa 是私钥

git remote add origin git@server-name:path/repo-name.git 将本地 git 和 GitHub 上的仓库关联

git push -u origin master 将本地 git 提交到 GitHub 仓库的 master 分支,-u 在第一次推送 master 分支的所有内容时要使用

git push origin master 不是第一次就用这个

git clone 用于从远程库克隆

git 分支操作

git checkout -b dev 创建并切换到 dev 分支,效果等同于下面两个命令

git checkout -b dev origin/dev 创建远程 origin 的 dev 分支到本地

git branch dev 创建 dev 分支 git checkout dev 切换到 dev 分支

git branch 查看有哪些分支和当前所处的分支

git 分支合并

git checkout master 切换到 master 分支 git merge dev 当当前分支在 master 下时,(master 分支未改动,dev 分支已经改动),将 master 分支和 dev 分支合并
git branch -d dev 之后删除 dev 分支

创建一个分支,之后分别在 master 和分支上修改 readme.txt,之后合并 master 和分支会产生冲突, 此时需要把冲突后的文件手动解决冲突,修改文件后 add commit,冲突就解决了,之后就可以删除分支了

git log --graph --pretty=oneline --abbrev-commit 比较图像化地显示分支历史

git 工作区备份操作

git stash 将当前的工作区备份存档

git stash list 显示当前分支的工作区存档

git stash apply 恢复最近一次的工作区存档
git stash apply stash@{0} 若经过多次存档,恢复指定的工作区存档

git stash drop 删除最近一次的工作区存档

git stash pop 恢复并删除最近一次的工作区存档,等同于 apply+drop

git branch -D dev 强行删除 dev 分支

###git 远程库操作 git remote 查看远程库信息

git remote -v 查看详细的远程库信息

git remote rm origin 把本地与 origin 远程库的关联取消

git 自定义

git config --global color.ui true 美化

git add -f App.class 将被.ginignore 忽略的文件强制添加到 Git

git check-ignore -v App.class 检查定位导致 App.class 添加到 Git 失败的规则

.gitignore. windows 上这样就能创建.gitignore 文件

git config --global alias.st status 为 git 命令取别名
git config --global alias.last 'log -1' 也可以用引号把一句命令引起来,为它取个别名

git branch --set-upstream branch-name origin/branch-name 创建本地分支与远程分支的链接关系

git 标签操作

git tag 查看所有标签

git tag v1.0 为最新提交的 commit 打上标签

git tag v1.0 commit 的版本号 为指定的 commit 打上标签

git show v1.0 查看标签信息

git tag -a v1.0 -m "version 1.0 released" 3435334 创建带有说明的标签

git tag -s v1.0 -m "version 1.0 released" 3435334 gpg 配置成功前提下用私钥签名一个标签

git tag -d v1.0 删除标签

git push origin v1.0 推送某个标签到远程

git push origin --tags 一次性推送所有尚未推送到远程的本地标签

git tag -d v1.0 如果标签已经推送到远程,要删除该标签先删除本地标签
git push origin :refs/tags/v1.0 再把远程标签删除

参考于https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

· 阅读需 7 分钟

background-color

设置区块背景的颜色

background-position

设置背景图像的起始位置
这个属性设置背景原图像(由 background-image 定义)的位置,背景图像如果要重复,将从这一点开始
需要把 background-attachment 属性设置为 "fixed",才能保证该属性在 Firefox 和 Opera 中正常工作
语法:background-position: 水平位置 垂直位置;
可以使用关键词 center top left bottom right 如果您仅规定了一个关键词,那么第二个值将是"center"。
水平和垂直位置的搭配通式为 关键词x x%|xpos 关键词y y%|ypos
如果您仅规定了一个值,另一个值将是 50%。
比如
left 20% bottom 10%
left 10px bottom 10px
left 20% bottom 10px
若不加%pos默认0% 0%

background-size

规定背景图像的尺寸
语法
background-size: length|percentage|cover|contain;
length:设置背景图像的高度和宽度。 第一个值设置宽度,第二个值设置高度。 如果只设置一个值,则第二个值会被设置为 "auto"。
percentage:以父元素的百分比来设置背景图像的宽度和高度。 第一个值设置宽度,第二个值设置高度。 如果只设置一个值,则第二个值会被设置为 "auto"。
cover:把背景图像扩展至足够大,以使背景图像完全覆盖背景区域。 背景图像的某些部分也许无法显示在背景定位区域中。
contain:把背景图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域。
coverVScontain
相同点:图片都是等比例缩放
不同点:cover 是铺满整个显示区域。如果显示比例和显示区域的比例相差很大某些部分会不显示; contain 正好相反,他是按照某一边来覆盖显示区域的,会有白边

background-repeat

设置是否及如何重复背景图像
默认地,背景图像在水平和垂直方向上重复。
可能的值:
repeat:默认。背景图像将在垂直方向和水平方向重复。
repeat-x:背景图像将在水平方向重复。
repeat-y :背景图像将在垂直方向重复。
no-repeat:背景图像将仅显示一次。
inherit:规定应该从父元素继承 background-repeat 属性的设置。

background-origin

规定 background-position 属性相对于什么位置来定位
如果背景图像的 background-attachment 属性为 "fixed",则该属性没有效果
语法
background-origin: padding-box|border-box|content-box; padding-box:背景图像相对于内边距框来定位。
border-box:背景图像相对于边框盒来定位。
content-box:背景图像相对于内容框来定位。

background-clip

规定背景的绘制区域 语法 background-clip: border-box|padding-box|content-box;
border-box:背景被裁剪到边框盒。
padding-box:背景被裁剪到内边距框。
content-box:背景被裁剪到内容框。

background-attachment

设置背景图像是否固定或者随着页面的其余部分滚动
scroll:默认值。背景图像会随着页面其余部分的滚动而移动。
local:背景随元素内容滚动。
fixed:当页面的其余部分滚动时,背景图像不会移动。
inherit:规定应该从父元素继承 background-attachment 属性的设置。

background-image

为元素设置背景图像
url('URL'):指向图像的路径。
none:默认值。不显示背景图像。
inherit:规定应该从父元素继承 background-image 属性的设置。

##简写顺序 background:color img_url repeat attachment position / size origin clip

##复合属性。 检索或设置对象的背景特性(背景色 <' background-color '> 不能设置多组)。
一个元素可以设置多重背景图像。
每组属性间使用逗号分隔。
如果设置的多重背景图之间存在着交集(即存在着重叠关系),前面的背景图会覆盖在后面的背景图之上。
示例:假设要在同一个元素上定义 3 个背景图像
缩写方式:

background:url(test1.jpg) no-repeat scroll 10px 20px/50px 60px content-box padding-box,
url(test1.jpg) no-repeat scroll 10px 20px/70px 90px content-box padding-box,
url(test1.jpg) no-repeat scroll 10px 20px/110px 130px content-box padding-box #aaa;

注意, <' background-color '> 只能设置一次,且由于写在前面的背景会叠在之后的背景之上,所以背景色通常都定义在最后一组上,避免背景色将图像盖住。
拆分方式:

background-image:url(test1.jpg),url(test2.jpg),url(test3.jpg);
background-repeat:no-repeat,no-repeat,no-repeat;
background-attachment:scroll,scroll,scroll;
background-position:10px 20px,10px 20px,10px 20px;
background-size:50px 60px,70px 90px,110px 130px;
background-origin:content-box,content-box,content-box;
background-clip:padding-box,padding-box,padding-box;
background-color:#aaa;

如果定义了多个背景图片,而其他属性只有一个参数值,则表明所有背景图片的该属性都应用同一个参数值。据此可以对上面的例子进行缩写:
缩写方式:

background-image:url(test1.jpg),url(test2.jpg),url(test3.jpg);
background-repeat:no-repeat;
background-attachment:scroll;
background-position:10px 20px;
background-size:50px 60px,70px 90px,110px 130px;
background-origin:content-box;
background-clip:padding-box;
background-color:#aaa;

如果定义了多个背景图片,而 <' background-origin '> 和 <' background-clip '> 设置了相同的值。可这样缩写:
缩写方式:

background:url(test1.jpg) no-repeat scroll 10px 20px/50px 60px padding-box,
url(test1.jpg) no-repeat scroll 10px 20px/70px 90px padding-box,
url(test1.jpg) no-repeat scroll 10px 20px/110px 130px padding-box #aaa;

这表示 <' background-origin '> 和 <' background-clip '> 都使用了 padding-box 参数值。

· 阅读需 1 分钟

#条件:浏览器是Chrome或是Safari #工具:background-clip + text-fill-color #实战 html

<p>文字渐变效果实现</p>

css
p{
background-image: linear-gradient(yellow,pink);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

实在是太简便了,唯一美中不足的是只有chrome内核浏览器和safari才支持。

· 阅读需 7 分钟

语法 #匹配中文字符的正则表达式: [u4e00-u9fa5] 评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

#匹配双字节字符(包括汉字在内):x00-xff 评注:可以用来计算字符串的长度(一个双字节字符长度计 2,ASCII 字符计 1)

#匹配空白行的正则表达式:ns*r 评注:可以用来删除空白行

#匹配 HTML 标记的正则表达式:< (S?)>>.?|< .? /> 评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

#匹配首尾空白字符的正则表达式:^s|s\$ 评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

#匹配 Email 地址的正则表达式:w+([-+.]w+)@w+([-.]w+).w+([-.]w+)* 评注:表单验证时很实用

#匹配网址 URL 的正则表达式:[a-zA-z]+://s* 评注:网上流传的版本功能很有限,上面这个基本可以满足需求

#匹配帐号是否合法(字母开头,允许 5-16 字节,允许字母数字下划线):^[a-zA-Z][a-za-z0-9_]{4,15}\$ 评注:表单验证时很实用

#匹配国内电话号码:d{3}-d{8}|d{4}-d{7} 评注:匹配形式如 0511-4405222 或 021-87888822

#匹配腾讯 QQ 号:[1-9][0-9]{4,} 评注:腾讯 QQ 号从 10000 开始

#匹配中国邮政编码:[1-9]d{5}(?!d) 评注:中国邮政编码为 6 位数字

#匹配身份证:d{15}|d{18} 评注:中国的身份证为 15 位或 18 位

#匹配 ip 地址:d+.d+.d+.d+ 评注:提取 ip 地址时有用

#匹配特定数字: ^[1-9]d\$    //匹配正整数 ^-[1-9]d$   //匹配负整数 ^-?[1-9]d$   //匹配整数 ^[1-9]d|0\$  //匹配非负整数(正整数 + 0) ^-[1-9]d|0$   //匹配非正整数(负整数 + 0) ^[1-9]d.d|0.d[1-9]d$   //匹配正浮点数 ^-([1-9]d.d|0.d[1-9]d)$  //匹配负浮点数 ^-?([1-9]d.d|0.d[1-9]d|0?.0+|0)$  //匹配浮点数 ^[1-9]d.d|0.d[1-9]d|0?.0+|0$   //匹配非负浮点数(正浮点数 + 0) ^(-([1-9]d.d|0.d[1-9]d*))|0?.0+|0$  //匹配非正浮点数(负浮点数 + 0) 评注:处理大量数据时有用,具体应用时注意修正

#匹配特定字符串: ^[A-Za-z]+$  //匹配由26个英文字母组成的字符串 ^[A-Z]+$  //匹配由 26 个英文字母的大写组成的字符串 ^[a-z]+$  //匹配由26个英文字母的小写组成的字符串 ^[A-Za-z0-9]+$  //匹配由数字和 26 个英文字母组成的字符串 ^w+\$  //匹配由数字、26 个英文字母或者下划线组成的字符串

#在使用 RegularExpressionValidator 验证控件时的验证功能及其验证表达式介绍如下:

只能输入数字:“^[0-9]*$”
只能输入n位的数字:“^d{n}$”
只能输入至少n位数字:“^d{n,}$”
只能输入m-n位的数字:“^d{m,n}$”
只能输入零和非零开头的数字:“^(0|[1-9][0-9]*)$”
只能输入有两位小数的正实数:“^[0-9]+(.[0-9]{2})?$”
只能输入有1-3位小数的正实数:“^[0-9]+(.[0-9]{1,3})?$”
只能输入非零的正整数:“^+?[1-9][0-9]*$”
只能输入非零的负整数:“^-[1-9][0-9]*$”
只能输入长度为3的字符:“^.{3}$”
只能输入由26个英文字母组成的字符串:“^[A-Za-z]+$”
只能输入由26个大写英文字母组成的字符串:“^[A-Z]+$”
只能输入由26个小写英文字母组成的字符串:“^[a-z]+$”
只能输入由数字和26个英文字母组成的字符串:“^[A-Za-z0-9]+$”
只能输入由数字、26个英文字母或者下划线组成的字符串:“^w+$”
验证用户密码:“^[a-zA-Z]w{5,17}$”正确格式为:以字母开头,长度在6-18之间,


只能包含字符、数字和下划线。
验证是否含有^%&’,;=?$”等字符:“[^%&',;=?$x22]+”
只能输入汉字:“^[u4e00-u9fa5],{0,}$”
验证Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”
验证InternetURL:“^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$”
验证电话号码:“^((d{3,4})|d{3,4}-)?d{7,8}$”


正确格式为:“XXXX-XXXXXXX”,“XXXX-XXXXXXXX”,“XXX-XXXXXXX”,


“XXX-XXXXXXXX”,“XXXXXXX”,“XXXXXXXX”。
验证身份证号(15位或18位数字):“^d{15}|d{}18$”
验证一年的12个月:“^(0?[1-9]|1[0-2])$”正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:“^((0?[1-9])|((1|2)[0-9])|30|31)$”


正确格式为:“01”“09”和“1”“31”。


匹配中文字符的正则表达式: [u4e00-u9fa5]
匹配双字节字符(包括汉字在内):[^x00-xff]
匹配空行的正则表达式:n[s| ]*r
匹配HTML标记的正则表达式:/<(.*)>.*|< (.*) />/
匹配首尾空格的正则表达式:(^s*)|(s*$)
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w-./?%&=]*)?

#(1)应用:计算字符串的长度(一个双字节字符长度计 2,ASCII 字符计 1) String.prototype.len=function(){returnthis.replace(x00-xff/g,”aa”).length;}

#(2)应用:JavaScript 中没有像 vbscript 那样的 trim 函数,我们就可以利用这个表达式来实现 String.prototype.trim = function() { return this.replace(/(^s)|(s$)/g, “”); } #(3)应用:利用正则表达式分解和转换IP地址 function IP2V(ip) //IP地址转换成对应数值 { re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正则表达式 if(re.test(ip)) { returnRegExp.$1Math.pow(255,3))+RegExp.\$2Math.pow(255,2))+RegExp.$3255+RegExp.$41 } else { throw new Error(”Not a valid IP address!”) } } #(4)应用:从 URL 地址中提取文件名的 javascript 程序 s=”http://www.9499.NET/page1.htm”; s=s.replace(/(.*/){0,}(.+).*/ig,”\$2″) ; //Page1.htm
#(5)应用: #利用正则表达式限制网页表单里的文本框输入内容 用正则表达式限制只能输入中文: onkeyup=”value=”/blog/value.replace(/["^u4E00-u9FA5]/g,”)” onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^u4E00-u9FA5]/g,”))” #用正则表达式限制只能输入全角字符: onkeyup=”value=”/blog/value.replace(/["^uFF00-uFFFF]/g,”) ”onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^uFF00-uFFFF]/g,”))” #用正则表达式限制只能输入数字: onkeyup=”value=”/blog/value.replace(/["^d]/ g,”)“onbeforepaste=“clipboardData.setData (’text’,clipboardData.getData(’text’).replace(/[^d]/ g,”))” #用正则表达式限制只能输入数字和英文: onkeyup=”value=”/blog/value.replace(/[W]/g,””)“onbeforepaste=”clipboardData.setData(’text’,clipboardData.getDa

· 阅读需 3 分钟

1. 方法概述

 map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组。

2. 例子

2.1 在字符串中使用map###

在一个 String 上使用 map 方法获取字符串中每个字符所对应的 ASCII 码组成的数组:

var map = Array.prototype.map
var a = map.call("Hello World", function(x) { return x.charCodeAt(0); })
// a的值为[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

2.2 易犯错误###

通常情况下,map 方法中的 callback 函数只需要接受一个参数(很多时候,自定义的函数形参只有一个),就是正在被遍历的数组元素本身。

但这并不意味着 map 只给 callback 传了一个参数(会传递3个参数)。这个思维惯性可能会让我们犯一个很容易犯的错误。

// 下面的语句返回什么呢:
["1", "2", "3"].map(parseInt);
// 你可能觉的会是[1, 2, 3]
// 但实际的结果是 [1, NaN, NaN]

// 通常使用parseInt时,只需要传递一个参数.但实际上,parseInt可以有两个参数.第二个参数是进制数.可以通过语句"alert(parseInt.length)===2"来验证.
// map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素, 元素索引, 原数组本身.
// 第三个参数parseInt会忽视, 但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用.从而返回了NaN.

/*
//应该使用如下的用户函数returnInt

function returnInt(element){
return parseInt(element,10);
}

["1", "2", "3"].map(returnInt);
// 返回[1,2,3]