猫窝私语 — Makumo's Blog

玛酷猫的温馨小窝,记录生活点点滴滴。

@玛酷猫5年前

07/16
16:25
JS&JQUERY

Ajax的收录与history API

虽然google reader已经关闭,但是作为一个重要的学习途径,rss阅读之路还要走下去。

rss上面好东西还是不少的,毕竟还是有不少人还是分享自己的技术知识,今天看到了一篇文章《如何让搜索引擎抓取AJAX内容?》,以前经常在cnbeta上看新闻,就有个疑问,它的首页是不停的用ajax加载的,搜索引擎该如何收录。这篇文章至少提及了一种解决思路。核心就是靠history api来实现。这东东其实并不陌生,工作中经常会用到:

history.back;
history.go(-1);

在HTML4的中,经常使用如下几种方法

  • length:历史堆栈中的记录数。
  • back():返回上一页。
  • forward():前进到下一页。
  • go([delta]):delta是个数字,如果不写或为0,则刷新本页;如果为正数,则前进到相应数目的页面;若为负数,则后退到相应数目的页面。

在HTML5中,又增加了几种用法

  • pushState(data, title [, url]):往历史堆栈的顶部添加一条记录。data为一个对象或null,它会在触发window的popstate事件(window.onpopstate)时,作为参数的state属性传递过去;title为页面的标题,但当前所有浏览器都忽略这个参数;url为页面的URL,不写则为当前页。
  • replaceState(data, title [, url]):更改当前页面的历史记录。参数同上。这种更改并不会去访问该URL。

看完后突发奇想,岂不是这个方法可以用来掩饰钓鱼网站。。在chrome控制台里面试了下,直接报错“Error: SECURITY_ERR: DOM Exception 18”,看来担心是多余的,应该只能在同域名下使用。用这个方法也可以在网站上面搞搞恶作剧,比如做一个好玩的页面,pushState替换成另一个恶搞页面,发给别人,别人不注意再复制转发的话,嘿嘿。再比如Google的20 Things I Learned About Browsers and the Web(需要科学上网),还有这个Eight Equals Equals Dee IN UR URLS(少儿不宜:))

Ajax的收录与history API

@玛酷猫6年前

09/7
17:47
JS&JQUERY

JavaScript闭包和匿名函数

PS:最近在研究JavaScript的模块化,随手做些笔记吧。

模块化首先要了解两个概念,那就是闭包(closure)和匿名函数(anonymous function)。

关于闭包,网上文章非常多,有位牛人的这篇文章《闭包漫谈(从抽象代数及函数式编程角度)》写的很全面。话说数学相关的知识全都还给大学老师了,好多看不懂。

百度百科的解释:

闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。

话说百科的东西都是文字绕呀绕,把你绕糊涂位置,不看也罢。JavaScript的闭包官方解释:指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。一样文绉绉的,不解其意。套用网络通俗的解释就是“闭包就是能够读/写函数内部的某些变量的子函数,并将这些变量保存在内存中。”,其中两个效果,一是读写函数内部变量,二是常驻内存。

匿名函数是指那些无需定义函数名的函数。匿名函数与 Lambda 表达式(拉姆达表达式)是一回事。唯一的不同——语法形式不同。Lambda 表达式更进一步。本质上,它们的作用都是:产生方法——内联方法,也就是说,省去函数定义,直接写函数体。

引用网络上面一个例子

var baz;
(function() {
	var foo = 10;
	var bar = 2;
	baz = function() {
		return foo * bar;
	};
})();
baz();

尽管在匿名函数外执行,但 baz 仍然可以访问 foo 和 bar。
1,第 1 行,baz 是全局变量;
2,第 2 ~第 8 行,定义一个匿名函数;
3,第 3 和 4 行,foo 和 bar 是匿名函数内的局部变量;第 5 ~ 7 行,在匿名函数内定义一个匿名函数,并将其赋值给全局变量 baz;
4,第 9行,调用 baz。若改成 “alert(baz());”,将显示 20;
5,按理说,在匿名函数外不能访问 foo 和 bar,但是现在可以。
要注意的是,函数内部声明变量时,一定要使用 var 关键字,否则,声明的是一个全局变量。最早自己写代码很少注意这个,也出现过变量被修改的混乱情况。

闭包常用于两种情况,一个是保护函数内的变量安全。函数中foo和bar只有函数baz才能访问,而无法通过其他途径访问到,因此保护了变量的安全性。另一个是在内存中维持一个变量。依然如前例,由于闭包,函数中foo和bar一直存在于内存中。

由于闭包的维持占用内存的特性,频繁使用会大量消耗内存,引起内存泄露。如无特殊需要,尽量不适用闭包,如果使用,当使用完毕后,要记得释放占用的内存。

JavaScript闭包和匿名函数

@玛酷猫6年前

08/30
15:07
JS&JQUERY

javaScript模块规范、AMD、CMD

学无止境真是一点没错,IT行业新知识新技术简直是井喷状态在发展,这两年javaScript(以下简写JS)发展是相当迅猛,09年诞生的node.js成长迅速,今天又在网上看到AMD/CMD两新名词,互联网就是这点好,不懂可以查可以搜。

AMD/CMD其实都是JS模块化开发的规范。最早JS需求都很简单,基本都是写函数,一种面向过程的写法,后来慢慢的引入面对对象开发思想,慢慢写成类。随着应用程序的日益增大,JS代码行数迅猛增长,如何管理、组织、优化成为一个很头疼的事情。node.js的模块化写法让人眼前一亮,于是乎各路牛人纷纷效仿,各种写模块的规范也就涌现出来了。

异步模块定义(AMD)是Asynchronous Module Definition的缩写,是 RequireJS 在推广过程中对模块定义的规范化产出。规范传送门
通用模块定义(CMD)是Common Module Definition的缩写,是SeaJS 在推广过程中对模块定义的规范化产出。规范传送门
此外还有 CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出。
等等。。。

话说光看介绍理解不能呀,主要还是试试其中的功能,感觉一下,好像各大常用的JS框架也慢慢支持模块化调用,试用下,之后再来写写感受。

javaScript模块规范、AMD、CMD

@玛酷猫6年前

08/21
16:18
JS&JQUERY

正则表达式中的反向引用

今天群里有人抛出一个正则求分析,如下:

^(?:(?!\d{4}).)*(\d{4})(?:(?!\1).)*\1

咋一看,整句全都是特殊符号,头晕中。不过正则表达式都是看起来晕,慢慢分析起来还是蛮有意思。里面有两天稍微复杂点,一个是断言,这个之前写过一篇文章介绍《正则表达式中的断言和非捕捉组》,另外一个就是反向引用,这个以前遇到的少,遇到不怕,搜索一下就好了。一下引用百度百科:

正则表达式的最重要功能之一是存储匹配的模式的一部分以供以后重新使用的能力。您可能想起,若在正则表达式模式或模式的一部分两侧加上括号,就会导致表达式的一部分被存储到临时缓冲区中。可以通过使用非捕获元字符 ?:、?= 或 ?! 来重写捕获。
反向引用
每个捕获的子匹配项按照它们在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。可以使用 \n来访问每个缓冲区,其中n 是标识特定缓冲区的一位或两位十进制数字。

清楚这个,上面那个就好分析了。借助Regex Match Tracer试着分析如下:

^边界开头条件,(?!\d{4}). 负向零宽度断言,意思断言自身位置的后面不能匹配四位数字,也就是开头到第一组四位数字为止,(?:(?!\d{4}).)*非捕捉组,不进行捕捉组记录。(\d{4}),第一个捕捉组,4位数字。\1反向引用,也就是前面第一个捕捉组所捕捉到的4位数字,(?!\1).,和前面的负向零宽度断言相同,意思断言自身位置的后面不能匹配第一个捕捉组的四位数字,这之间可以出现其他的数字组合。(?:(?!\1).)*非捕捉组,最后再跟一个\1,也就是第一捕捉组的那4位数字。

整体意思大概就是:从开始遇到第一个4位数字。继续,当遇到第二次同样的4位数字后截止,匹配这部分内容。

另外还有一点需要注意,就是反向引用如果后面要加数字,例如\10,不同的引擎会有不同的解释:在.NET中,这里的“\10”被解析成第10个捕获组的反向引用,但如果正则表达式加了RegexOptions.ECMAScript参数,则这里的“\10”被解析成第1个捕获组的反向引用加一个普通字符“0”;而在JavaScript中,在IE的浏览器引擎中,“\10”被解析成第1个捕获组的反向引用加一个普通字符“0”,而在Firefox、Opera等浏览器中,得到的结果为空,说明“\10”被解析成第10个捕获组的反向引用。为了防止这种情况,后面跟的数字一般用非捕捉组代替,例如:\1(?:0)表示。

本人正则表达式并不是很熟练,如有问题,欢迎指正。

正则表达式中的反向引用

@玛酷猫7年前

04/6
11:52
JS&JQUERY

正则表达式中的断言和非捕捉组

前段时间在cnblogs看到一道有意思的题目,传送门地址。题面很简单:将一段数字从右到左每隔三位插入一个逗号 ,也就是通常说的插入千分位符,使用javascript实现,据说是某大公司的面试题。动态语言就没有什么难点了,现成的函数都有。我第一反应也就是把类似字符串倒转原理的操作,只不过不是一位一位,是三位三位,然后用分号连接起来。各式各样的解答和效率测试就不多说了,源地址的博客中都有说明。单单说下其中的一个解答,如下:

var cuter2 = function( str ){//abcd
     return str.replace( /\B(?=(?:\d{3})+$)/g, ',' );
};

看到这个解答很神奇,单单一句正则就搞定,虽然效率一般,在页面大量需要此操作的情况下并不是很适用。老实说正则也写过不少,以前做页面抓取,各式各样的匹配也写过,但是这个正则表达式基本理解不能。幸好手上有正则利器,一个叫“Regex Match Tracer”的小工具(我就不贴下载地址,可自行搜索),可以分解测试正则表达式。去掉/g全局参数和开头的/,正则的结构分解的很清楚,见右图。其中有两个词倒是第一次见,一个是零宽度断言,另一个就是非捕捉组。网上搜索一下,明了很多。

先说非捕捉组,这个很好理解,用法(?:Expression)。非捕捉组主要是整体效率的考虑,因为并不是所有的捕捉组都是我们需要的,有一些为了方便分割,有一些是必须使用捕捉组的形式,往往并不关心捕捉组的具体内容,每一个捕捉组都会消耗一部分内存,当一个很长或者重复很多的时候,这些捕捉组消耗的内存就不是个小数目了。

再说说断言,这个比较难理解,先引用网上搜索到的说明:

元字符/b、^、$都匹配一个位置,且这个位置满足一定的条件。在此,把满足这一个条件称为断言或零宽度断言。

表达式(?=experssion)、(?!experssion)、(?<=experssion)和(?<!experssion)都是匹配一个位置。
(?=experssion)又称为零宽度正预测先行断言,它断言自身位置的后面能够匹配表达式experssion。
(?<=experssion)又称为零宽度正回顾后发断言,它断言自身位置的前面能够匹配表达式experssion。
(?!experssion)又称为负向零宽度断言或者零宽度负预测先行断言,它断言自身位置的后面不能匹配字符串experssion。
(?<!experssion)又称为零宽度负回顾后发断言,它断言自身位置的前面不能匹配字符串experssion。

说明比较绕口,个人理解为一般的正则是匹配字符或者字符串,而断言是匹配符合一定条件的位置,就拿上面那个正则说明(个人理解):\d{3}是三位数字组,(?:\d{3})非捕捉组,(?:\d{3})+贪婪模式,一个或者多个三位数字组合,(?=(?:\d{3})+$)断言,以一个或者多个3位数字组合结尾的那个位置,最后前面的/B是匹配不是在字符的开始或结束位置,防止字符串正好是3的倍数,千分号打在最开头。/g全局模式,因为一次只能将一个位置替换成逗号。其实弄清楚了每一小部分,整个正则还是很好理解的。主要就是能不能想到这个方法。

最后再多说一些,随着javascript的框架应用层出不穷,很多做前端的为了开发效率考虑,直接就使用框架来开发,在这个速成的时代,甚至有些前端只会使用框架写法,基本的javascript都写不出几行出来。这是一个很恐怖的事情,就好比一个学步的人,天天使用代步工具,汽车、飞机、甚至电动轮椅,一旦脱离这些东西,这个人将寸步难行。框架也是同样的原理,不管什么语言的框架,都是为了更高的开发效率,但是框架的实现原理也需要研究弄懂的,大部分框架都是开源的,花些时间研究并不是很困难的事情,一方面可以巩固自身的语言基础用法,最重要的是从架构上理解开发者为什么要这样部署框架结构,框架运行思想,也能从中发现存在的瑕疵或者不适应自身项目的地方,加以完善或者改进调整,同时也能为自身在系统架构认识上面,增加不少的经验。

正则表达式中的断言和非捕捉组