标签归档:前端开发

JavaScript正则表达式详解

在JavaScript中,正则表达式由RegExp对象表示。RegExp对象呢,又可以通过直接量和构造函数RegExp两种方式创建,分别如下:

//直接量
var re = /pattern/[g | i | m];
//构造函数
var re = new RegExp(["pattern", ["g" | "i" | "m"]]);

其中,末尾的可选字符(g、i和m)分别表示:

  g模式执行一个全局匹配。简而言之,就是找到所有匹配,而不是在找到第一个之后就停止。

  i模式执行不区分大小写的匹配。

  m: 多行模式,^和$锚除了匹配字符串的开头和结尾外,还匹配每行的开头和结尾。例如,模式/Java$/m匹配”Java”和”JavanScript”。

基础篇

特殊字符

在正则表达式中,所有的字母字符和数字都可以按照直接量与自身匹配,如/JavaScript/匹配的就是字符串”JavaScript”,但是有些特殊字符呢?如换行符。所以在JavaScript中规定以反斜杠()开头的转义序列支持这些特殊字符。常用的特殊字符如下:

转义字符 匹配
n 换行符
r 回车
f 换页符
t 制表符
v 垂直制表符

 字符类–

在正则表达式中,倘若将单独的字符放入方括号([ ])中,就可以组合成字符类。应用到匹配字符串中,我们可以将其看成一个漏斗,当字符串中的每个字符通过它时,都查找是否在这个类里面,如若在,就匹配成功,否则out。如下:

/*
    match为字符串的方法,它的唯一参数就是一个正则表达式,
    如果该正则表达式设置了标志g,该方法返回的数组包含的就是出现在字符串中的所有匹配。
    详细的用法将在下面“正则表达式在String中的应用”细讲
*/
"abc".match(/[abc]/g);

匹配结果为:

如果我们的意愿是,想匹配除字符a、b、c之外的字符呢?我们可以定义一个否定类,只需将^符号放入[ ]中作为开头就OK啦。如下:

"abc".match(/[^abc]/g);

由于某些字符类经常用到,固JavaScript的正则表达式就用反斜杠()与一些特殊字符组合起来表示这些常用类,而不必再需要我们自行添加,如d。

常用正则字符类如下:

字符类 匹配 例子
[ …] 位于方括号之中的任意字符 /M[onke]y/ 匹配 “Moy”
[ ^…] 除包含在方括号之中的任意字符 /M[^onke]y/ 匹配 “May”
. 除换行符之外的任意字符 /../ 匹配 “Mo”
w 字母、数字或下划线 /1w/ 匹配 “1A”
W 除字母、数字和下划线之外的字符 /1W/ 匹配 “1%”
s 单个空白字符 /MsK/ 匹配 “M K”
S 单个非空白字符 /MSK/ 匹配 “M_K”
d 0到9的数字 /d/ 匹配 “1”
D 非数字 /D/ 匹配 “M”

重复匹配–

当我们需要匹配三位数字时,我们可以这样:/ddd/,但是当我们需要匹配10位或者更多时呢?考虑到这一点,正则表达式为我们提供了重复字符{ n, m },表示匹配前一项至少n次,但是不能超过m次。例如,刚才我们所说的匹配三位数字时,我们可以利用重复字符这样啦:/d{3}/。

由于某些重复类型经常用到,so,正则规定一些特殊字符表示这些重复类型。

正则重复字符,详情见下:

字符 含义 例子
 {n, m} 匹配前一项至少n次,但不能超过m次 /d{2,3}/ 匹配”12″
{n, } 匹配前一项至少n次,或者更多 /d{2, }/ 匹配”123″
{n} 匹配前一项恰好n次 /d{2}/ 匹配”12″
匹配前一项0次或者1次,等价于{0,1} /d?/ 匹配”2″
+ 匹配前一项1次或者多次,等价于{1, } /d+/ 匹配”12″
* 匹配前一项0次或者多次,等价于{0, } /d*/ 匹配”12″

另,以上重复字符重复规则为:尽可能多的匹配,即俗称的“贪婪匹配”,如:”aaaa”.match(/a+/);匹配的就是整个字符串”aaaa”,而不是匹配到第一个字符a时,就放弃匹配。

那么,有所谓的”贪婪匹配”,就有”非贪婪匹配”,它的规则嘛,肯定与”贪婪匹配”相反咯,即:尽可能少的匹配。

那么,怎么才能触发非贪婪模式呢?

只需要在重复字符后加入?,就ok啦,如({1, 4}?、+?等),如”aaaa”.match(/a+?/);就只会匹配首个字符a咯。

注意,是尽可能少的匹配,而不是少的匹配哦。

神马意思?如下:

"aaab".match(/a*b/);
"aaab".match(/a*?b/);

!匹配结果都是”aaab”!

有没有点诧异,为什么”aaab”.match(/a*?b/);的匹配结果会是”aaab”,而不是”ab”呢?

那是因为正则���配都是从左往右的,就”aaab”.match(/a*?b/);而言,当遇到首字符a时,它会继续往下匹配,直到能符合匹配模式/a*?b/为止,这就是为什么说是尽可能少的匹配,前提是满足匹配规则

如”abbb”.match(/ab*?/)的匹配结果就是”a”啦。

字符 |( )(?: …)

1.1、字符” | ” 用于分隔,表示或。

什么意思?

举个栗子,如/ab | cd | ef/就可以匹配字符串”ab”或者”cd”或者”ef”。

是不是和字符类[ ]很像啊?

是的,如/a | b | c/和/[abc]/匹配效果是一样的哦。

But字符类[ ]仅针对单个字符而言,而分隔字符” | “涉及更广,可以针对多个字符而言,如上述所说的/ab | cd | ef/,字符类就不行咯。

你可能会说,如果我想对利用” | “组装的类进行多次匹配呢?

加个括号就是啦。如:

/(ab | cd |ef)+/

好滴,说到括号,我们再来看看它的作用。非常强大哦。

————————————–分割线 ————————————–

Linux 基础入门教程—-正则表达式基础   http://www.linuxidc.com/Linux/2015-08/121441.htm

Linux正则表达式sed 详述  http://www.linuxidc.com/Linux/2015-04/116309.htm

Linux正则表达式特性及BRE与ERE的区别 http://www.linuxidc.com/Linux/2014-03/99152.htm

grep使用简明及正则表达式 http://www.linuxidc.com/Linux/2013-08/88534.htm

正则表达式的用法 http://www.linuxidc.com/Linux/2013-03/81897.htm

正则表达式之零宽断言 http://www.linuxidc.com/Linux/2013-03/81897.htm

Linux中正则表达式与文件格式化处理命令(awk/grep/sed) http://www.linuxidc.com/Linux/2013-03/81018.htm

基础正则表达式 http://www.linuxidc.com/Linux/2014-09/106296.htm

常用正则表达式整理 http://www.linuxidc.com/Linux/2014-10/108076.htm

————————————–分割线 ————————————–

1.2、括号”( )”

括号的作用如下:

  1、我们可以将一个单独的项目组合成一个子表达式,以便我们可以用|、*等来处理它。如,上诉所示的/(ab | cd | ef)+/

  2、利用括号括起来的部分,我们可以在正则表达式的后面引用前面用括号括起来的子表达式的匹配结果,注意是结果,而不是括起来的正则表达式。

针对第二点,有什么用呢?如我们有个需求,我想匹配在单引号或者双引号中的数字(’12345’)时,我们就可轻而易举利用这第二点,写好正则表达式,如下:

/(['"])d*1/

测试结果如下:

好了,就第二点作用而言,结合上述demo,我们再来看看它的具体引用法则吧:

—-以反斜杠加数字的方式,引用前面带括号的子表达式,而这个数字呢指的就是第几个子表达式,计算规则为从左往右,计算遇到的左括号” ( “,到想引用的地方位置为止,无论在括号中还嵌套不嵌套括号。

测试Demo如下:

咦,倘若我只想让括号的作用为分组,而不想在后面计入引用呢?毕竟括号多了,不好计算呢。

那么,我们就来看看字符(?: …)咯。

1.3、(?: …)

(?: …)的作用就是,规定括号只用于分组,而不计入后面的引用,不好理解,看个demo就明白啦。如下:

/(Java(?:Script))(nice)/

如果我想在末尾引用子表达式nice,那么是2,而不是3咯,因为用(?: …)来分组滴,只管分组,而不引用,切记切记。

对(?: …)的测试demo如下:

 

匹配位置–

在前面我们提到,创建正则对象时,可选字符m表示:多行模式,^和$锚除了匹配字符串的开头和结尾外,还匹配每行的开头和结尾。

那么这个^和$就是正则为我们提供的匹配位置,即所谓的

例如:

将/JavaScript/变为/^JavaScript/,就只匹配字符串中开头为JavaScript的啦,如匹配”JavaScriptxxx”中的JavaScript,而不匹配”xxxJavaScript”中的JavaScript。

正则表达式中的锚字符详情见下:

字符 含义
^ 匹配字符串的开头
$ 匹配字符串的结尾
b 匹配一个词语的边界,指[a-zA-Z_0-9]之外的字符
B 匹配非词语边界位置
(? = p) 正前向声明,exp1(?=exp2),匹配后面是exp2的exp1
(? ! p) 反前向声明,exp1(?!exp2),匹配后面不是exp2的exp1

^和$好理解,但是b、(?=)、(?!)可能比较陌生,结合上表,我们再来看看下面的demo就好啦。

对于b的Demo如下:

 

对于(? = p)的Demo如下:

 

对于(? ! p)的Demo如下:

具体应用见 下一页

更多详情

JavaScript 基础工具清单

在训练营中,为扩展学员们的编程能力,我们给他们介绍了一些工具和库。目前有位JavaScript学员Kalina,他汇总了这些工具的清单,以分享给其他的代码爱好者。

基于Kalina的清单,我们JavaScript训练营的辅导员Ivan Storck画了一张思维导图:

 

通用

 

脚手架工具(用于启动项目)

  • Yeoman – Yeoman是一个健壮且固定的客户端程序库,包含了工具和框架,有助于开发者快速构建漂亮的web应用。

 

构建工具(自动化构建)

  • Grunt.js – Grunt生态系统很巨大,且每天成长着。由于有数以百计的插件可供选择,你可以使用Grunt自动化构建,且花费最少的代价。
  • Pint.js(Grunt助手) – Pint是一个小型、异步、感知依赖的基于Grunt的封装库,试图解决大规模构建过程中的一些问题。
  • Gulp.js – Gulp的流式构建方式和代码优于配置理念使构建更简单、更直观。
  • Browserify.js(浏览器端) – Browserify是一个允许编写、编译node.js风格的模块并将之用于浏览器的开发工具。就像node,我们在单独文件中编写模块,使用module.exports、exports导出外部方法和属性。
  • Uglify.js – Uglify.js是服务于NodeJS的一个JavaScript解析/压缩/美化库。

 

包管理工具

  • Homebrew(适用于Mac 系统) – Homebrew能安装你需要而苹果不提供的东西。
  • Apt (适用于Ubuntu系统) – apt-get命令是一个强大的命令行工具,与Ubuntu的高级包装工具(APT)配合使用,提供了安装新软件、升级已有软件、更新软件列表目录,甚至升级整个Ubuntu系统等功能。
  • NPM – npm是一个Node.js官方包管理工具。
  • Bower – Bower是一个web的包管理工具。

 

前端

 

MVC框架

  • Backbone.js – Backbone.js通过提供进行键值绑定的模块、自定义事件、具有丰富可枚举函数API的集合、能处理已定义事件的视图,搭建了web应用的架构。它通过RESTful JSON接口与其它已存在的API进行通信。
  • Ember.js – 当底层模块改变时,Ember使得Handlebar模板引擎在保持HTML最新方面做得更好。开始时,你甚至不需要编写任何JavaScript。
  • Angular.js – Angular.js能让你扩展应用的HTML词汇。由此产生的效果是网页极富表现力,代码可读性强,适合快速开发。

 

模板

  • Handlebars.js – Handlebars提供了让你顺利、有效地构建语义模板的强大能力。Handlebars兼容Mustache模板,因此你可以在Handlebars中导入Mustache模板,同时享用Handlebars的其他功能。
  • Mustache.js(比Handlebars更少外置元素) – Mustache是一个简单的web模板系统,已有ActionScript、 C++、Clojure、CoffeeScript、ColdFusion、D、Erlang、Fantom、 Go、Java、JavaScript、 Lua、.NET、 Objective-C、Pharo、Perl、PHP、Python、Ruby、Scala 和 XQuery语言实现版本的可用。
  • Jade – Jade 是一个node模板引擎,主要为node.js的服务器端模板而设计。
  • Haml-js – Haml-js允许在JavaScript项目中使用Haml语法,并拥有大部分与原先Haml相同的功能。
  • Eco – Eco能让你在标记元素中嵌入CoffeeScript 的逻辑。

 

测试

  • Casper.js – CasperJS是一个Javascript实现的,PhantomJS和SlimerJS的导航脚本和测试工具。
  • Zombie.js – Zombie.js是一个在模拟环境中测试客户端JS代码的轻量级框架。无需浏览器。

 

后端

 

服务器

  • Express  – Express是一个Node的web应用框架。
  • Node – Node.js是一个基于Chrome JavaScript 运行时建立的平台, 用来方便地搭建快速、 易于扩展的网络应用。

 

数据库

  • MongoDB – MongoDB 是个开源的文档数据库,引领着NoSQL数据库。
  • Postgresql – PostgreSQL 是一个强大、开源、对象-关系型数据库系统。
  • SQL – SQL用于与数据库进行通信。根据美国国家标准学会的定义,它是关系式数据库管理系统的标准语言。

 

架构风格

  • RESTful – 表现层状态转化是一种架构风格,包含了一组相互协作的架构约束。这些约束应用于分布式超媒体系统之间的组件、连接器和数据元素。

 

测试

  • Cucumber.js – Cucumber.js是一种流行的行为驱动开发工具,并将之应用于你自己的JavaScript程序
  • Jasmine – Jasmine是JavaScript的一个行为驱动开发测试框架。它不依赖于浏览器、DOM、或任何其他JavaScript框架。因此它适用于网站、Node.js项目、或任何可运行JavaScript的地方。
  • Mocha – Mocha 是一个运行于node.js和浏览器的特色丰富的JavaScript测试框架,使得异步测试更简单有趣。
  • Q-Unit – Q-Unit 是一个强大,易用的JavaScript单元测试框架。它被用于jQuery、jQuery UI 和 jQuery Mobile 项目,能够测试任何通用的JavaScript代码。

 

断言库

  • Chai – Chai 是一个行为驱动开发/测试驱动开发(BDD / TDD )断言库,用于node和浏览器,可以愉快地搭配任何JavaScript测试框架。

 

函数式编程工具

  • Underscore.js – Underscore是一个提供了一大堆有用的函数式编程辅助,无须扩展任何内置对象的JavaScript库。
  • Lo-Dash – Lo-Dash是一个提供了一致性、定制和性能的实用程序库。

JavaScript高级程序设计(第3版)高清完整PDF中文+英文+源码  下载见 http://www.linuxidc.com/Linux/2014-09/107426.htm

如何使用JavaScript书写递归函数  http://www.linuxidc.com/Linux/2015-01/112000.htm

JavaScript核心概念及实践 高清PDF扫描版 (邱俊涛)  http://www.linuxidc.com/Linux/2014-10/108083.htm

理解JavaScript中的事件流  http://www.linuxidc.com/Linux/2014-10/108104.htm 

JavaScript跨浏览器事件对象类库 http://www.linuxidc.com/Linux/2015-07/120615.htm

Javascript学习小结

作者QQ:415074476

QQ群:191280586

note:解读的Javascript权威指南。
1.变量作用域是全局性的。而不是从定义处开始
例:
var g = “global”;
function a()
{
alert(g);//output undefined, not global
var g=”local”;
alert(g);//output local
}

2.判断一个变量是否有值。用if(typeof(x) ==”undefined”),而不是if(x).因为如果x未声明,会报js错误。另外,”undefined”和undefined不同,前者类型为string,后者类型为undefined.
另外:
不能用if(a===undefined)这样会报错,
但是可以用if(a.b===undefined)

3.基本类型:数值,布尔,null, undefined. 引用类型:对象,数组,函数。 使用引用类型拷贝赋值时得注意。会影响原来变量的值。
如:
var a=[1,2];
var b=a;
b[2]=”3″;
alert(a);//1,2,3
alert(b);//1,2,3
function test(d)
{
d[3]=”haha”;
}
test(a);
alert(a);//1,2,3,haha
alert(b);//1,2,3,haha

4.代码验证ret+=str的效率还是比ret.push(str);return ret.join(“”);高

5.闭包,使用需慎重,需要了解执行环境
应用场景
1、保护函数内的变量安全。
2、在内存中维持一个变量。

6.delete不能删除由var声明及某些内部的核心属性和客户端属性

7.void 主要用在超链中。如open new window

8.关于.和[]操作符。 .的右边只能是直接量的标识符,不能是字符串或变量。[]没有这限制

9.()操作符用于调用函数。第一个运算数总是一个函数名或者是一个引用函数的表达式。主要是得习惯
(function(){alert(1);})() 这种代码。可以把第一个运算数理解成匿名函数。
等同于。
function anonymous()
{
alert(1);
}
anonymous();
用于加载即执行的功能,并且只执行一次。可以和闭包一起用。

10.异常处理。
a.抛出异常 throw new Error(“test error”);
b.捕获异常try{}catch(){} finally{}

11.with语句
用于暂时修改作用域链,可以减少代码。。不建议使用。

12.通用的Object属性和方法
属性:constructor 等于构造函数
方法:toString(),用于字符串环境
toLocaleString()
valueOf().用于数值环境
hasOwnProperty(x)是否有一个非继承的属性x
propertyIsEnumerable(x).判断一个非继承的属性是否可用于for in语句
isPrototypeOf()

13.数组
4种方法
var a=[];//数组直接量
var a= new Array();//空数组
var a=new Array(“a”,”b”);//初始化
var a=new Array(10);//指定长度

数组的length属性可读写。当设定length时,会增加/截断数组
数组的length只影响数字索引,或被数字索引影响。

数组方法:
join() ;//转成字符串
reverse();//倒序
sort();//排序
concat();//连接数组
slice();//取数组的一部分
splice();//插入或删除数组。
push(),pop();//尾部增删
unshift(),shift();//头部增删

14.执行匿名函数的3种方法
(function (){alert(1);}());//比较正常
(function(){alert(2);})();
void function (){alert(3);}();

15.&& ,|| 的返回值问题。。这点得注意和其它语言不同。其它语言是返回布尔值。
javascript是返回执行的表达式的值。
如 var s = “a” || “b”;//”a”
var s = false || “good” ;//”good”
var s = “d” && “b”;//”b”
var s = false || “d”;//”d”

16.函数相关。
三种定义的方式:
a,语句。function a(){} //typeof a ==”function”
b,表达式,直接量 var a=function(){}//typeof a ==”function”
c,构造函数 var a = new Function(“x”,”y”,”return x+y””); //typeof a ==”object”,不使用词法作用域,而是当作顶层函数编译。

函数属性:
a,length 声明函数的形参个数,函数内和函数外都可访问,只读属性
b,prototype
c,定义函数自己的属性,相当于静态变量。
如uniquetest.counter=0; function uniquetest(){
return uniquetest.counter++;
}

函数方法
a,call()和apply()
用于改变this对象引用的对象。call是按个传参。apply是传一个数组
使用apply的好像是可以直接利用arguments对象

17.关于原型对象。prototype
每个对象都包含着对它的原型对象的内部引用。原型对象的任何属性表现为每个以它为原型对象的属性。
换句话说:javascript对象从它的原型那里继承属性。

//code
function a(x,y)
{
this.x = x;
this.y = y;
}

var d = new a(2,3);
alert(a.prototype);
alert(d.constructor);//constructor继承自a.prototype.constructor
alert(d.constructor.prototype);//
alert(d.constructor.prototype.constructor);//

说明:定义a时。a自动地有prototype属性,prototype的初始值为一个对象。这个对象只有constructor属性,指向a本身。
创建d对象时,d继承a的prototype的属性,所以d有属性constructor,指向构造函数a。

区分是自有属性还是通过prototype继承的属性,只能通过api Object.hasOwnProperty()

18.类属性。
由于构造函数本身也是一个对象。对象可以有自己的属性。这个属性也就成了类的属性。
//code1
a.count =0;
function a(x,y)
{
this.x=x;
this.y=y;
a.count++;
this.counter = function()
{
return a.count;
}
}
var b = new a(12,3);//a.count=1
var c = new a(432,23);//a.count=2
//这样可以用count保存调用构造函数的次数。但是有一个弊端。a.count是可以随便改变的,即a.count属性是可写的。
a.count=100;
var d = new a(3,3);//这个时候a.count=101而不是期待的3
//有什么办法来保护count呢?闭包的用武之地来了。

//code2
var a = (function()
{
var count=0;
return function(x,y)
{
this.x=x;
this.y=y;
count++;
this.counter = function()
{
return count;
}
}
})();

19。 || 的使用
为了避免文件的重复包含可能导致的错误。
使用var varibale = varibale || {}的用法,是比较好的。
尤其是在执行代码中有初始化,又只能初始化一次的情况下。

如loadflash.js
var a = function(){var init=0;//假设这里是动态加载flash
return {}}();
如果包两次loadflash.js,就会加载两次flash,导致取flash对象时出现异常。
如果换成var a = a || function(){var init=0;//假设这里是动态加载flash
return {}}();
不管两几次loadflash.js文件,也不会出问题了

20通用对象模型
a.toString()在字符串环境中使用
b.valueOf()在数值环境中使用。在某些字符串环境中valueOf()方法优先级高于toString()
c.=号是按地址比较,要比较两个对象的值,需要定义equals方法。

21。子类
得指定prototype

22正则表达式
几个少用的。
(?=p)正前向声明 要求接下来的字符与模式p匹配
(?!p)反前向声明 要求接下来的字符不与模式p匹配

二.关于兼容.
一、函数和方法差异
1. getYear()方法
【分析说明】先看一下 以下代码:
var year = new Date().getYear();
document.write(year);
在IE中得到的日期是”2010″,在Firefox中看到的日期是”110″,主要是因为在 Firefox 里面 getYear 返回的是 “当前年份-1900” 的值。
【兼容处理】
加上对年份的判断,如:
var year = new Date().getYear();
year = (year < 1900 ? ( 1900 + year):year);
document.write(year);
也可以通过 getFullYear getUTCFullYear 去调用:
var year = new Date().getFullYear();
document.write(year);

2. eval()函数
【分析说明】在IE中,可以使用eval(“idName”)或 getElementById(“idName”)来取得id为idName的 HTML对象;Firefox下只能使用getElementById(“idName”)来取得id为idName的HTML对象。
【兼 容处理】统一用getElementById(“idName”)来取得id为idName的HTML对象。

3. const声明
【分析说明】在 IE 中不能使用 const 关键字。如:
const constVar = 32 ;
在IE中这是语法错误。
【兼 容处理】不使用 const ,以 var 代替。

4.var
【分析说明】请看 以下代码:
echo = function (str){
document.write(str);
}
这个函数在IE上运行 正常,Firefox下却报错了。
【兼容处理】而在echo前加上var就正常了,这个就是我们提到var的目的。

二、样式访问和设置

1 . CSS的”float”属性

【分析说明】Javascript访问一个给定CSS 值的最基本句法是:object.style.property,但部分CSS属性跟Javascript中的保留字命名相同, 如”float”,”for”,”class”等,不同浏览器写法不同。

在IE中这样写:
document.getElementById( ” header ” ).style.styleFloat = ” left ” ;
在Firefox中这样写:
document.getElementById( ” header ” ).style.cssFloat = ” left ” ;
【兼容处理】在写之前加一个判断,判断浏览器是否是IE:
if (document.all){
document.getElementById( ” header ” ).style.styleFloat = ” left ” ;
}
else {
document.getElementById( ” header ” ).style.cssFloat = ” left ” ;
}
2 . 访问

3. 访问和设置class属性

【分析说明】同样由于class是Javascript保留字的原因,这两种浏览器使用不同的 JavaScript 方法来获取这个属性。
IE8.0之前的所有IE版本的写法:
var myObject = document.getElementById( ” header ” );
var myAttribute = myObject.getAttribute( ” className ” );
适用于IE8.0 以及 firefox的写法:
var myObject = document.getElementById( ” header ” );
var myAttribute = myObject.getAttribute( ” class ” );
另外,在使用setAttribute()设置Class属性的时候,两种浏览器也存在同样的差异。
setAttribute(“className”,value);
这种写法适用于IE8.0之前的所有IE版本,注意:IE8.0 也不支持”className”属性了。
setAttribute(“class”,value);适用于IE8.0 以及 firefox。
【兼容处理】
方法一,两种都写上:
var myObject = document.getElementById( ” header ” );
myObject.setAttribute( ” class ” , ” classValue ” );
myObject.setAttribute( ” className ” , ” classValue ” );
// 设置header的class为 classValue
方法二,IE和FF都支持 object.className,所以可以这样写:
var myObject = document.getElementById( ” header ” );
myObject.className = ” classValue ” ; // 设置header的class为classValue
方法三,先判断浏览器类型,再根据浏览 器类型采用对应的写法。

4. 对象宽高赋值问题
【分析说明】FireFox中类似 obj.style.height = imgObj.height 的语句无效。
【兼容处理】统一使用 obj.style.height = imgObj.height + ‘px’;

三、 DOM方法及对象引用
1 . getElementById
【分析说明】先来看一组代 码:

< input id =”id” type =”button”
value =”click me” onclick =”alert(id.value)”/ >
在 Firefox中,按钮没反应,在IE中,就可以,因为对于IE来说,一个HTML 元素的 ID 可以直接在脚本中当作变量名来使用,而Firefox中不可以。

【兼容处理】尽量采用W3C DOM 的写法,访问对象的时候,用 document.getElementById(“id”) 以ID来访问对 象,且一个ID在页面中必须是唯一的,同样在以标签名来访问对象的时候,用document.getElementsByTagName(“div”) [0] 。该方式得到较多浏览器的支持。


< input id =”id” type =”button” value =”click me”
onclick =”alert(document.getElementById(‘id’).value)” / >

2. 集合类对象访问
【分析说明】IE下,可以使用()或[]获取集合类对象;Firefox下,只能使用 []获取集合类对象。如:
document.write(document.forms( ” formName ” ).src);
//该写法在IE下能访问到Form对象的src属性
【兼容处理】将document.forms(“formName”)改为 document.forms[“formName”]。统一使用[]获取集合类对象。

3 . frame的引用
【分析说明】IE可以通过id或者name访问这个frame对应的window对象,而Firefox只可以通过 name来访问这个frame对 应的window对象。
例如如果上述frame标签写在最上层的window里面的htm里面,那 么可以这样访问:
IE: window.top.frameId或者window.top.frameName来访问这个window对象;
Firefox:只能 这样window.top.frameName来访问这个window对象。
【兼容处理】使用frame的name来访问frame对 象,另外,在IE和Firefox中都可以使用 window.document.getElementById(”frameId”)来访问这个frame对象。

4 . parentElement
【分析说明】IE中支持使用parentElement和parentNode获取父节点。而 Firefox只可以使用parentNode。
【兼容处理】因为firefox与IE都支持DOM,因此统一使用 parentNode来访问父节点。

5 . table操作
【分析说明】IE下 table中无论是用innerHTML还是appendChild插入
都没有效果,而其他浏览器却显示正 常。 【兼 容处理】解决的方法是,将加到table的元素中,如下面所示: var row = document.createElement( ” tr ” ); var cell = document.createElement( ” td ” ); var cell_text = document.createTextNode( ” 插 入的内容 ” ); cell.appendChild(cell_text); row.appendChild(cell); document.getElementsByTagName( ” tbody ” )[ 0 ].appendChild(row);

6 . 移除节点removeNode()和removeChild()
【分析说明】appendNode在IE和Firefox下都能正常使用,但是removeNode只能在IE下用。
removeNode方法的功能是删除一个节点,语法为node.removeNode(false)或者 node.removeNode(true),返回值是被删除的节点。
removeNode(false)表示仅仅删除指定节点,然 后这个节点的原孩子节点提升为原双亲节点的孩子节点。
removeNode(true)表示删除指定节点及其所有下属节点。被删除的 节点成为了孤立节点,不再具有有孩子节点和双亲节点。
【兼容处理】Firefox中节点没有removeNode方法,只能用 removeChild方法代替,先回到父节点,在从父节点上移除要移除的 节点。
node.parentNode.removeChild(node);
// 为了在ie和firefox下都能正常使用,取上一层的父结点,然后remove。

7 . childNodes获取的节点
【分析说明】childNodes的下标的含义在IE和Firefox 中不同,看一下下面的代码:
< ul id =”main” >
< li > 1
< li > 2
< li > 3

< input type =button value =”click me!” onclick =
“alert(document.getElementById(‘main’).childNodes.length)” >
分别用IE和 Firefox运行,IE的结果是3,而Firefox则是7。Firefox使用DOM规范,”#text”表示文本(实际是无意义 的空格和换行等)在Firefox里也会被解析成一个节点,在IE里只有有实际意义的文本才会解析成”#text”。
【兼容处理】
方法一,获取子节点时,可以通过node.getElementsByTagName()来回避这个问题。但是 getElementsByTagName对复杂的DOM结构遍历明显不如用childNodes,因为childNodes能更好的处理DOM的层次结 构。
方法二,在实际运用中,Firefox在遍历子节点时,不妨在for循环里加上:
if (childNode.nodeName ==”#text” ) continue ; // 或者使用nodeType == 1。
这 样可以跳过一些文本节点。

8. Firefox不能对innerText支持
【分析说明】 Firefox不支持innerText,它支持textContent来实现innerText,不过textContent没有像 innerText一样考虑元素的display方式,所以不完全与IE兼容。如果不用textContent,字符串里面不包含HTML代码也可以用 innerHTML代替。也可以用js写个方法实现,可参考《为firefox实现innerText属性 》一文。

【兼容处理】通过判断浏览器类型来兼容:
if (document.all){
document.getElementById( ‘element’ ).innerText = ” my text ” ;
} else {
document.getElementById( ‘element’ ).textContent = ” my text ” ;
}

四、事件处理
如果在使用 javascript的时候涉及到event处理,就需要知道event在不同的浏览器中的差异,主要的JavaScript的事件 模型有三种(参考《Supporting Three Event Models at Once 》),它们分别是NN4、IE4+和W3C/Safar。

1 . window.event
【分析说明】先看一段代码
function et()
{
alert(event); // IE: [object]
}
以上代码在IE运行的结果是 [object],而在Firefox无法运行。

因为在IE中event作为window对象的一个属性可以直接使用,但是在 Firefox中却使用了W3C的模型,它是通过传参的方法来传播 事件的,也就是说你需要为你的函数提供一个事件响应的接口。
【兼容处 理】添加对event判断,根据浏览器的不同来得到正确的event:
function et()
{
evt = evt ? evt:(window.event ? window.event: null );
// 兼容IE和Firefox
alert(evt);
}

2 . 键盘值的取得
【分 析说明】IE和Firefox获取键盘值的方法不同,可以理解,Firefox下的event.which与IE下的 event.keyCode相当。关于彼此不同,可参考《键盘事件中keyCode、which和charCode 的兼容性测试 》
【兼容处理】

function myKeyPress(evt){
//兼容IE和Firefox获得keyBoardEvent对象
evt = (evt) ? evt : ((window.event) ? window.event : “” )
// 兼容IE和 Firefox获得keyBoardEvent对象的键值
var key = evt.keyCode ? evt.keyCode:evt.which;
if (evt.ctrlKey && (key == 13 || key == 10 )){
// 同时按下了Ctrl和回车键
// do something;
}
}

3 . 事件源的获取
【分析说明】在使用事件委托的时候,通过 事件源获取来判断事件到底来自哪个元素,但是,在IE下,event对象有srcElement属性,但是 没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。

【兼容处理】

ele = function (evt){ // 捕获当前事件作用的对象
evt = evt || window.event;
return
(obj=event.srcElement?event.srcElement:event.target; );
}

4 . 事件监听

【分析说明】在事件监听处理方面,IE提供了attachEvent和detachEvent两个接口,而Firefox提供 的是 addEventListener和removeEventListener。
【兼容处理】最简单的兼容性处理就是封装这两套接 口:

function addEvent(elem, eventName, handler) {
if (elem.attachEvent) {
elem.attachEvent( ” on ” + eventName, function (){
handler.call(elem)});
//此处 使用回调函数 call(),让this指 向elem
} else if (elem.addEventListener) {
elem.addEventListener(eventName, handler, false );
}
}
function removeEvent(elem, eventName, handler) {
if (elem.detachEvent) {
elem.detachEvent( ” on ” + eventName, function (){
handler.call(elem)});
//此处 使用回 调函数call(),让this指向elem
} else if (elem.removeEventListener) {
elem.removeEventListener(eventName, handler, false );
}
}
需要特别注意,Firefox下,事件处理函数中的this指向被监听元素本身,而在IE下则不然,可使用回调函数call,让当前上下文指向监听的元素。

5 . 鼠标位置
【分析说明】IE下,even对象有x,y属性,但是没有pageX,pageY属性;Firefox下,even对象有 pageX,pageY属 性,但是没有x,y属性。
【兼容处理】使用mX(mX = event.x ? event.x : event.pageX;)来代替IE下的event.x或者Firefox下的event.pageX。复杂点还要考虑绝对位置。

function getAbsPoint(e){
var x = e.offsetLeft, y = e.offsetTop;
while (e = e.offsetParent) {
x += e.offsetLeft;
y += e.offsetTop;
}
alert( ” x: ” + x + ” , ” + ” y: ” + y);
}

五、 其他差异的兼容处理
1 . XMLHttpRequest
【分析说明】new ActiveXObject(“Microsoft.XMLHTTP”);只在IE中起作用,Firefox不支持,但支持XMLHttpRequest。
【兼容处理】

function createXHR() {
var xhr = null ;
if (window.XMLHttpRequest){
xhr = new ActiveXObject( ” Msxml2.XMLHTTP ” );
} else {
try {
xhr = new ActiveXObject( ” Microsoft.XMLHTTP ” );
}
catch () {
xhr = null ;
}
}
if ( ! xhr) return ;
return xhr;
}

2 . 模态和非模态窗口
【分析说明】IE中可以通过showModalDialog和showModelessDialog打开模态和非模态窗 口,但是Firefox不支 持。
【解决办法】直接使用window.open(pageURL,name,parameters)方 式打开新窗口。 如果需要传递参数,可以使用 frame或者iframe。

3. input.type 属性问题
IE下 input.type属性为只读,但是Firefox下可以修改

4 . 对select元素的option操作
设置options,IE和Firefox写法不同:
Firefox:可直接设 置
option.text = ‘ foooooooo ‘ ;
IE:只能设置
option.innerHTML = ‘ fooooooo ‘ ;

删除一个select的option的方法:
Firefox:可以
select.options.remove(selectedIndex);
IE7:可以用
select.options[i] = null ;
IE6:需要写
select.options[i].outerHTML = null ;

5 . img对象alt和title的解析
【分析说明】img对象有alt 和title两个属性,区别在于,alt:当照片不存在或者load错误时的提示。
title:照片的tip说明, 在IE中如果没有定 义title,alt也可以作为img的tip使用,但是在Firefox中,两者完全按照标 准中的定义使用
在定义img对象时。
【兼容处理】最好将alt和title对象都写全,保 证在各种浏览器中都能正常使用 。

6 . img的src刷新问题
【分析说明】先看 一下代码:
< img id =”pic” onclick = “this.src= ‘a.jpg'”
src =”aa.jpg” style =”cursor: pointer” />
在IE 下,这段代码可以用来刷新图片,但在FireFox下不行。主要是缓存问题。
【兼容处理】在地址后面加个随机数就解决了:
< img id =”pic” onclick = “javascript:this.src=this.src+’?’
+Math.random()”src =”a.jpg” style =”cursor: pointer” />

从一行代码里面学点JavaScript

现如今,JavaScript无处不在,因此关于JavaScript的新知识也是层出不穷。JavaScript的特点在于,要学习它的语法入门简简单,但是要精通使用它的方式却是一件不容易的事。

来看看下面的这段代码,它来自于谷歌“名猿”Addy Osmani在几天前贴出的一段代码,它的作用是用来调试你的CSS层。全部代码只有三行,但是你绝对可以把它放在一行里面完成:

[].forEach.call($$(“*”),function(a){

a.style.outline=”1px solid #”+(~~(Math.random()*(1<<24))).toString(16)

})

现在,在你的Chrome浏览器的控制台中输入这段代码,你会发现不同HTML层都被使用不同的颜色添加了一个高亮的边框。是不是非常酷?但是,简单来说,这段代码只是首先获取了所有的页面元素,然后使用一个不同的颜色为它们添加了一个1ps的边框。想法很简单,但是真要实现起来却不是那么容易的一件事。在下面的内容中,我们将一起一步一步学习如何理解上面的这段代码。

选择页面中所有的元素

我们需要做的第一件事情是获取页面中所有的元素,在上面的代码中,Addy使用了一个Chrome浏览器中特有的函数$$。你可以在你的Chrome浏览器控制台中输入$$(‘a’),然后你就能得到一个当前页面中所有锚元素的列表。

$$函数是许多现代浏览器命令行API中的一个部分,它等价于document.querySelectorAll,你可以将一个CSS选择器作为这个函数的参数,然后你就能够获得当前页面中所有匹配这个CSS选择器的元素列表。如果你在浏览器控制台以外的地方,你可以使用document.querySelectorAll(‘*’)来代替$$(‘*’)。更多关于$$函数的详细内容可以查看Chrome开发者工具的文档。

当然,除了使用$$函数之外,我们还有一种更简单的方法,document.all,虽然这并不是一种很规范的使用方法,但是它几乎在每一个浏览器中都能运行成功。

迭代所有的元素

经过第一步,我们已经获得了页面内所有的元素,现在我们想做的事情是遍历每一个元素,然后为它们添加一个彩色边边框。但是上面的代码究竟是怎么一回事呢?

[].forEach.call( $$(‘*’), function( element ) { /* 在这里修改颜色 */ });

首先,我们通过选择器获得的列表是一个NodeLists对象,它和JavaScript中的数组有点像,你可以使用方括号来获取其中的节点,你也可以检查它其中包含多少个元素,但是它并没有实现数组包含的所有方法,因此我们并不能使用$$(‘*’).forEach()来进行迭代。在JavaScript中,有好几个类似于数组但是并不是数组的对象,除了前面的NodeLists,还有函数的参数集合arguments,在这里我们可以使用call或apply函数将函数的方法运用到这些对象上。例如下面的例子:

function say(name) {

console.log( this + ‘ ‘ + name );

}

say.call( ‘hola’, ‘Mike’ ); // 打印 ‘hola Mike’

// 你也可以将这种方法有用在arguments对象上 function example( arg1, arg2, arg3 ) { return Array.prototype.slice.call(arguments, 1); // Returns [arg2, arg3] }

在Addy的代码中,使用了[].forEach.call而不是Array.prototype.forEach.call,二者等价,但是前者可以节省几个字节。

为元素添加颜色

为了让元素都有一个漂亮的边框,我们在上面的代码中使用了CSS属性outline。outline属性位于CSS盒模型之外,因此它并不影响元素的属性或者元素在布局中的位置,这对于我们来说非常有用。这个属性和修改border属性非常类似,因此下面的代码应该不会很难理解:

a.style.outline=”1px solid #” + color

真正有趣的地方在于定义颜色部分:

~~(Math.random()*(1<<24))).toString(16)

天呐,上面的代码是什么意思?在JavaScript中,比特操作符并不是经常被使用,因此这里可能会让很多程序员感到很疑惑。

我们想达到的目的是活的一个十六进制格式的颜色例如白色对应的是FFFFFF,蓝色对应的是0000FF,或者随便一个颜色37f9ac。虽然我们人类喜欢十进制,但是我们的代码常常会需要十六进制的东西。

我们首先要学会如何使用toString函数将一个十进制的数组转换为一个十六进制整数。这个函数可以接受一个参数,如果参数缺省,默认为十进制,但是你完全可以使用别的数组:

(30).toString(); // “30”

(30).toString(10); // “30”

(30).toString(16); // “1e” 十六进制

(30).toString(2); // “11110” 二进制

(30).toString(36); // “u” 36是允许的最大参数值

除此之外,你可以使用parseInt函数将十六进制数字转换为十进制。

parseInt(“30”); // “30”

parseInt(“30”, 10); // “30”

parseInt(“1e”, 16); // “30”

parseInt(“11110”, 2); // “30”

parseInt(“u”, 36); // “30”

因此,我们现在只需要一个位于0和ffffff之间的十六进制数,由于:

parseInt(“ffffff”, 16) == 16777215

而这里的16777215实际上是2^24-1。

如果你对二进制数学熟悉的话,你可能会知道1<<24 == 16777216。

再进一步,你每在1后面添加一个0,你就相当于多做了一次2的乘方:

1 // 1 == 2^0

100 // 4 == 2^2

10000 // 16 == 2^4

1000000000000000000000000 // 16777216 == 2^24

因此,在这里我们可以知道Math.random()*(1<<24)表示一个位于0和16777216之间的数。

但是这里并没有结束,因为Math.random返回的是一个浮点数,但是我们只想要整数部分。我们的代码中使用波浪号操作符来完成这件事。波浪操作符在JavaScript中被用来对一个变量进行取反。

但是我们在这里并不关心取反,我们指向获取整数部分。因此我们还可以知道两次取反可以去掉一个浮点数的小数部分,因此~~的作用相当于parseInt:

var a = 12.34, // ~~a = 12

b = -1231.8754, // ~~b = -1231

c = 3213.000001 // ~~c = 3213

;

~~a == parseInt(a, 10); // true

~~b == parseInt(b, 10); // true

~~c == parseInt(c, 10); // true

当然,我们还有一种更加简洁的方法,使用OR操作符:

~~a == 0|a == parseInt(a, 10)

~~b == 0|b == parseInt(b, 10)

~~c == 0|c == parseInt(c, 10)

最终,我们获得了一个位于0和16777216之间的随机整数,也就是我们想要的随机颜色。此时我们只需要使用toString(16)将它转化为十六进制数即可。

总结

现在,你已经完全理解了前面的这一行代码中的各个部分。作为一个程序员,我们应该在完成工作之后多问自己几遍为什么,还有没有更好更简洁的方法。当然,最应该做的事情当然是多阅读程序代码,也许你就能从某一行代码中学到很多新东西。

关于JavaScript中的复制

在做项目时有一个需求,是需要复制内容到剪切板,因为有众多浏览器,所以要兼容性很重要

1、最简单的copy,只能在IE下使用

使用clipboardData方法

2、跨浏览器的,但是Firefox无法复制

   

   

   

测试后,Firefox访问失败

3、万能的flash

不要重复造轮子了,有一个使用广泛的类库ZeroClipboard

Zero Clipboard 的实现原理

Zero Clipboard 利用 Flash 进行复制,之前有 Clipboard Copy 解决方案,其利用的是一个隐藏的 Flash。但最新的 Flash Player 10 只允许在 Flash 上进行操作才能启动剪贴板。所以 Zero Clipboard 对此进行了改进,用了一个透明的 Flash ,让其漂浮在按钮之上,这样其实点击的不是按钮而是 Flash ,也就可以使用 Flash 的复制功能了。

  • 创建一个透明的flash
  • 将这个flash浮在按钮上层
  • 确定要复制的文本是什么
  • 监听这个透明flash的鼠标点击事件
  • 该flash被点击之后,完成剪切板处理

对于这几件事,ZeroClipboard分别提供了不同的api,来完成整个需求

如何使用 Zero Clipboard

完整代码直接下载即可

git clone https://github.com/chenpingzhao/easycopy.git

关于ZeroClipboard.js

var ZeroClipboard = {

    version: “1.0.7”,

    clients: {},

    moviePath: “zeroclipboard.swf”,

    nextId: 1,

    $: function(A) {

        if (typeof(A) == “string”) {

            A = document.getElementById(A)

        }

        if (!A.addClass) {

            A.hide = function() {

                this.style.display = “none”

            };

            A.show = function() {

                this.style.display = “”

            };

            A.addClass = function(B) {

                this.removeClass(B);

                this.className += ” ” + B

            };

            A.removeClass = function(D) {

                var E = this.className.split(/\s+/);

                var B = -1;

                for (var C = 0; C < E.length; C++) {

                    if (E[C] == D) {

                        B = C;

                        C = E.length

                    }

                }

                if (B > -1) {

                    E.splice(B, 1);

                    this.className = E.join(” “)

                }

                return this

            };

            A.hasClass = function(B) {

                return !!this.className.match(new RegExp(“\\s*” + B + “\\s*”))

            }

        }

        return A

    },

    setMoviePath: function(A) {

        this.moviePath = A

    },

    dispatch: function(D, B, C) {

        var A = this.clients[D];

        if (A) {

            A.receiveEvent(B, C)

        }

    },

    register: function(B, A) {

        this.clients[B] = A

    },

    getDOMObjectPosition: function(C, A) {

        var B = {

            left: 0,

            top: 0,

            width: C.width ? C.width : C.offsetWidth,

            height: C.height ? C.height : C.offsetHeight

        };

        while (C && (C != A)) {

            B.left += C.offsetLeft;

            B.top += C.offsetTop;

            C = C.offsetParent

        }

        return B

    },

    Client: function(A) {

        this.handlers = {};

        this.id = ZeroClipboard.nextId++;

        this.movieId = “ZeroClipboardMovie_” + this.id;

        ZeroClipboard.register(this.id, this);

        if (A) {

            this.glue(A)

        }

    }

};

ZeroClipboard.Client.prototype = {

    id: 0,

    ready: false,

    movie: null,

    clipText: “”,

    handCursorEnabled: true,

    cssEffects: true,

    handlers: null,

    //我们可以通过下面这个api,将flash和按钮重叠,且浮在按钮之上

    glue: function(D, B, E) {

        this.domElement = ZeroClipboard.$(D);

        var F = 99;

        if (this.domElement.style.zIndex) {

            F = parseInt(this.domElement.style.zIndex, 10) + 1

        }

        if (typeof(B) == “string”) {

            B = ZeroClipboard.$(B)

        } else {

            if (typeof(B) == “undefined”) {

                B = document.getElementsByTagName(“body”)[0]

            }

        }

        var C = ZeroClipboard.getDOMObjectPosition(this.domElement, B);

        this.div = document.createElement(“div”);

        var A = this.div.style;

        A.position = “absolute”;

        A.left = “” + C.left + “px”;

        A.top = “” + C.top + “px”;

        A.width = “” + C.width + “px”;

        A.height = “” + C.height + “px”;

        A.zIndex = F;

        if (typeof(E) == “object”) {

            for (addedStyle in E) {

                A[addedStyle] = E[addedStyle]

            }

        }

        B.appendChild(this.div);

        this.div.innerHTML = this.getHTML(C.width, C.height)

    },

 

    /*IE 的 Flash JavaScript 通信接口上有一个 bug 。

    你必须插入一个 object 标签到一个已存在的 DOM 元素中。并且在写入 innerHTML 之前请确保该元素已经 appendChild 方法插入到 DOM 中*/

    getHTML: function(D, A) {

        var C = “”;

        var B = “id=” + this.id + “&width=” + D + “&height=” + A;

        if (navigator.userAgent.match(/MSIE/)) {

            var E = location.href.match(/^https/i) ? “https://” : “http://”;

            C += ‘

        } else {

            C += ‘

        }

        return C

    },

    hide: function() {

        if (this.div) {

            this.div.style.left = “-2000px”

        }

    },

    show: function() {

        this.reposition()

    },

    destroy: function() {

        if (this.domElement && this.div) {

            this.hide();

            this.div.innerHTML = “”;

            var A = document.getElementsByTagName(“body”)[0];

            try {

                A.removeChild(this.div)

            } catch (B) {}

            this.domElement = null;

            this.div = null

        }

    },

    /* 因为按钮上漂浮有一个 Flash 按钮,所以当页面大小发生变化时,Flash 按钮可能会错位,就点不着了

    Zero Clipboard 提供了一个 reposition() 方法,可以重新计算 Flash 按钮的位置。我们可以将它绑定到 resize 事件上

    bind(window, “resize”, function(){ clip.reposition(); });

   

    function bind(obj, type, fn) {

        if (obj.attachEvent) {

            obj[‘e’ + type + fn] = fn;

            obj[type + fn] = function() {

                obj[‘e’ + type + fn](window.event);

            }

            obj.attachEvent(‘on’ + type, obj[type + fn]);

        } else

            obj.addEventListener(type, fn, false);

    }*/

 

    reposition: function(C) {

        if (C) {

            this.domElement = ZeroClipboard.$(C);

            if (!this.domElement) {

                this.hide()

            }

        }

        if (this.domElement && this.div) {

            var B = ZeroClipboard.getDOMObjectPosition(this.domElement);

            var A = this.div.style;

            A.left = “” + B.left + “px”;

            A.top = “” + B.top + “px”

        }

    },

    setText: function(A) {

        this.clipText = A;

        if (this.ready) {

            this.movie.setText(A)

        }

    },

    addEventListener: function(A, B) {

        A = A.toString().toLowerCase().replace(/^on/, “”);

        if (!this.handlers[A]) {

            this.handlers[A] = []

        }

        this.handlers[A].push(B)

    },

    setHandCursor: function(A) {

        this.handCursorEnabled = A;

        if (this.ready) {

            this.movie.setHandCursor(A)

        }

    },

 

    /*鼠标移到按钮上或点击时,由于有 Flash 按钮的遮挡,所以像 css “:hover”, “:active” 等伪类可能会失效。

    setCSSEffects() 方法就是解决这个问题。首先我们需要将伪类改成类

    copy – botton: hover {

        border – color: #FF6633;

    }

    可以改成下面的 “:hover” 改成 “.hover”

   

    copy – botton.hover {

        border – color: #FF6633;

    }

    我们可以调用 clip.setCSSEffects( true ); 这样 Zero Clipboard 会自动为我们处理:将类 .hover 当成伪类 :hover*/

 

    setCSSEffects: function(A) {

        this.cssEffects = !! A

    },

    /*Zero Clipboard 提供了一些事件,你可以自定义函数处理这些事件。

    Zero Clipboard 事件处理函数为 addEventListener(); 例如当 Flash 完全载入后会触发一个事件 “load”

 

    clip.addEventListener( “load”, function(client) {

        alert(“Flash 加载完毕!”);

    });*/

 

    receiveEvent: function(D, E) {

        D = D.toString().toLowerCase().replace(/^on/, “”);

        switch (D) {

            case “load”:

                this.movie = document.getElementById(this.movieId);

                if (!this.movie) {

                    var C = this;

                    setTimeout(function() {

                        C.receiveEvent(“load”, null)

                    }, 1);

                    return

                }

                if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {

                    var C = this;

                    setTimeout(function() {

                        C.receiveEvent(“load”, null)

                    }, 100);

                    this.ready = true;

                    return

                }

                this.ready = true;

                this.movie.setText(this.clipText);

                this.movie.setHandCursor(this.handCursorEnabled);

                break;

            case “mouseover”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.addClass(“hover”);

                    if (this.recoverActive) {

                        this.domElement.addClass(“active”)

                    }

                }

                break;

            case “mouseout”:

                if (this.domElement && this.cssEffects) {

                    this.recoverActive = false;

                    if (this.domElement.hasClass(“active”)) {

                        this.domElement.removeClass(“active”);

                        this.recoverActive = true

                    }

                    this.domElement.removeClass(“hover”)

                }

                break;

            case “mousedown”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.addClass(“active”)

                }

                break;

            case “mouseup”:

                if (this.domElement && this.cssEffects) {

                    this.domElement.removeClass(“active”);

                    this.recoverActive = false

                }

                break

        }

        if (this.handlers[D]) {

            for (var B = 0, A = this.handlers[D].length; B < A; B++) {

                var F = this.handlers[D][B];

                if (typeof(F) == “function”) {

                    F(this, E)

                } else {

                    if ((typeof(F) == “object”) && (F.length == 2)) {

                        F[0][F[1]](this, E)

                    } else {

                        if (typeof(F) == “string”) {

                            window[F](this, E)

                        }

                    }

                }

            }

        }

    }

};

全方位比较PHP的Node.js的优缺点

【编者按】PHP vs Node.js之争由来已久,前者用于动态网页开发,后者是用来编写高性能网络服务器的JavaScript工具包,到底他们如何?InfoWorld测试中心的Peter Wayner日前撰文指出两者的优势所在,不妨一看。

以下为译文:

这是典型好莱坞情节:分道扬镳的两位老朋友间的战斗。摩擦经常开始于一位对另一位不言而喻的领域感兴趣。这部电影的编程语言版本是Node.js的引入将好友情节变成一场旗鼓相当的比赛。PHP和JavaScript,两个曾经一起统治互联网的合作伙伴现在为了开发者心中的份额开始一决雌雄。

在过去,他们的合作关系很简单。JavaScript处理浏览器上的小细节,PHP处理所有的存在于80端口和MySQL的服务器端任务。这个幸福的联合不断支持着因特网的许多关键部分。在WordPress、Drupal和Facebook上,人们几乎不会离开PHP一分钟。

但是,后来一些聪明的孩子发现他能使JavaScript运行在服务器上。突然,我们发现没必要使用PHP构建下一代服务器栈了。一种语言就足够建立Node.js和运行在客户端的框架。对一些人来说,“JavaScript无处不在”变成了咒语。

当然,结局并没有写完。相比较与吹嘘Node.js的纯粹和JavaScript无处不在的简单的程序员,还有另外的程序员,他们对深度代码库和了解PHP的稳定性感到满意。怪老头能够击退服务器端新贵吗?JavaScript能推翻它的老朋友,实现统治世界吗?我们在微波炉里再抓一把爆米花,坐下来瞧瞧。

PHP赢在何处:混合内容的代码

你正在打字,想法随之变成你网站中的文本。你想为进程添加一个分支,根据URL的一些参数,一点if-then语句就会使它看起来漂亮。或者可能你想从数据库中加入文本或数据。用PHP,你能打开PHP魔法标签在几秒内开始编写代码。不需要模板——一切都是一个模板。不需要额外的文件或者煞费苦心的体系结构,因为可编程逻辑能量就在你的指尖。

Node赢在何处:分离的内容

混合内容的代码是拐杖,最终会使你受到损害。当然,在最初的两到三次,混合HTML代码是有趣的。但是不久,你的代码库乱成一团。真正的程序员添加结构,从逻辑层分离出装饰层。对新的程序员来说,代码很容易理解清楚,便于维护。运行在Node.js的框架由这样的程序员所建,他们知道当模型,视图和控制器分离时,生活会变得更好。

PHP赢在何处:深的代码库

网络充满了PHP代码。最受欢迎的构建网站平台(WordPress、Drupal和Joomla)都是用PHP编写。不仅这些开源平台,大部分他们插件也是用PHP编写。网上到处有PHP代码,它等着你去下载、修改和为你所用。

Node赢在何处:新的代码意味着更多现代特征

当然,网上有数以千计的开源PHP文件,但是一些是8岁的WordPress插件希望、祈祷有人下载它们。有谁愿意去花费几个小时、几天或者是几周的时间去倒腾那些已经好几年没有更新的代码?Node.js插件不仅是新的,而且用最新体系的完整知识构建而成。

PHP赢在何处:简单(在一定程度上)

PHP中没有太多的东西:几个处理字符串、数字的变量和基本函数。它除了把数据从80端口移动到数据库并返回,不会做的太多。这是应该做的。现代数据库是个神奇的工具,它能离开重的负载。对不应该复杂工作,PHP的复杂度是适量的。

Node赢在何处:闭包和更多的复杂性

JavaScript可能会有许多把一些人逼疯的小特质。但在大多数情况下,它是一个娱乐现代语法的现代语言,有几个有用的特征,比如闭包。你能容易地重新配置和拓展它,使强大的函数库像jQuery成为可能。你能像传递对象一样四处传递函数。为什么限制你自己呢?

PHP赢在何处:不需要客户端应用程序

所有的关于在浏览器和服务器上使用相同的语言的讨论是好的,但是如果你不需要在浏览器上使用任何语言呢?如果你运送HTML表单中数据呢?浏览器弹出,不会出现被未启动的JavaScript造成的令人头疼的事情和小故障,这个JavaScript试图在浏览器上创建一个来自二十多个web服务调用的页面。纯粹的HTML比其他东西工作更频繁,而PHP是最优化去创建HTML。为何费心在浏览器上用JavaScript呢?在服务器上建立所有操作,避免小手机上的小浏览器重载。

Node赢在何处:与HTML-fat PHP调用相对的瘦服务调用

虽然AJAX-crazy HTML5 Web应用程序有许多移动部件,他们很酷,非常有效。一旦JavaScript代码在浏览器缓存中,新数据沿着线路移动。这没有大量的HTML标记语言,不重复地去下载整个页面。只有数据改变了。如果你愿意投入时间创建一个平滑的浏览器端Web应用程序,这将会有不错的报酬。Node.js是最优化地去传送数据,仅仅只有数据通过Web服务。如果你的应用程序是复杂而又数据丰富的,这将是有效传送的良好基础。

PHP赢在何处:SQL

PHP与MySQL和它的许多变体,比如MariaDB。如果MySQL不全是正确的,还有其他的来自Oracle和Microsoft的伟大的SQL数据库。你的代码用很少的改变就能转换成你的查询。广阔的SQL世界没边界。一些最稳定,成熟的代码与SQL数据库连接,意味着所有力量也能容易地被整合到PHP项目中。它可能不是完美幸福的家庭,但它是大的。

Node.js赢在何处:JSON

如果你必须接入SQL,Node.js的函数库可以做到。但Node.js也有JSON,一个与许多最新NoSQL数据库交互的通用语言。这并不是说你不能为你的PHP栈获得JSON库,但当使用JavaScript时有些流体可使用JSON的简单性去处理。这是从浏览器到Web服务器,再到数据库的语法。冒号和花括号在每处的作用相同,这节约了你的时间。

PHP赢在何处:编码速度

对大多数开发者,编写PHP Web应用程序感到更快:没有编译器,没有部署,没有JAR文件或者预处理器——仅仅是你喜欢的编辑器和一些PHP文件目录。你的进度会不同,但就一起迅速确定项目而论,PHP是一个很好用的工具。

Node.js赢在何处:原始速度

编写JavaScript代码的过程中,当你在计算花括号和圆括号时,它有点难,但是编写成功后,你的Node.js代码可以飞。它的回调机制很巧妙,因为能帮你节约运行线程的时间。核心被建好,旨在为你做一切,这不是每个人想要的吗?

英文链接:PHP vs. Node.js: An epic battle for developer mind share

下面的内容更精彩

Ubuntu 14.04下搭建Node.js开发环境  http://www.linuxidc.com/Linux/2014-12/110983.htm

Ubunru 12.04 下Node.js开发环境的安装配置 http://www.linuxidc.com/Linux/2014-05/101418.htm

Node.Js入门[PDF+相关代码] http://www.linuxidc.com/Linux/2013-06/85462.htm

Node.js开发指南 高清PDF中文版 +源码 http://www.linuxidc.com/Linux/2014-09/106494.htm

Node.js入门开发指南中文版 http://www.linuxidc.com/Linux/2012-11/73363.htm

Node.js安装与配置 http://www.linuxidc.com/Linux/2013-05/84836.htm

Ubuntu 编译安装Node.js http://www.linuxidc.com/Linux/2013-10/91321.htm

Node.js 的详细介绍请点这里
Node.js 的下载地址请点这

JavaScript代码模块化的正规方法

RequireJS-CommonJS-AMD-ES6 Import/Export详解

为什么起了一个这个抽象的名字呢,一下子提了四个名词分别是:RequireJS,CommonJS,AMD,ES6,答案是因为现实很骨感,我们必须很勇敢才能正视这一段悲催的往事。如今的JavaScript平台正值如日中天,大家可能会忽略他的过去和弊端,这些弊端中一直被人诟病的就是JavaScript的包管理,比如类似Java中的import,其实理论上来讲这种基本元素的缺失大大的阻碍了人们对一种语言的认可,认为他难以担当大任,其实这么多年来JavaScript平台的发展主要还是他存在的位置比较有利,在浏览器中,有标准的支持和约束,跨平台等等,但是这种先天不足就没办法了,只能后天努力,这样从ES3-ES6不断地加入新的功能终于使JavaScript这门语言逐渐完备,这个漫长的过程让我们逐渐的明白了一个道理:社会的需求胜过十驾马车的力量可以催生一项技术不断的完善,进步。

正如前面提到的JavaScript没有包管理,不适合构建复杂应用,但是现实是就需要用JavaScript来构建复杂应用,因为随着社会的进步,人们对web应用的期许提高了,这都难不倒工程师,不是语言不提供么,我们有work around。先来说说CommonJS,

CommonJS的出发点是让JavaScript这门语言写出的代码可以跨前后端,(当然这里面指的是逻辑代码,不包含DOM, BOM操作)也就是可以在不同的宿主上跑,不如同一段代码可以跑在NodeJS也可以跑在Nashorn或者浏览器,但是事实上对CommonJS标准应用最多的是NodeJS平台,也就是NodeJS中的Require, 那么CommonJS Require为什么没有在浏览器里流行呢,主要原因是这个Require是同步的,这个浏览器接受不了,用户体验差,下面我们来说说浏览器中的AMD。

// sum.js
module.exports = {
  sum: function(a, b) { return a + b; }
};

// app.js
var assert = require(‘assert’);
var cal = require(‘./sum’);
assert.equal(3, cal.sum(1, 2));

CommonJS在浏览器中不行我们再找一个方式,总会有适合的,下面我们来说说AMD (Asynchronous Module Definition) 对CommonJS稍加改变,构造一个异步的变种就得到了AMD,示例代码如下,这下变成异步的了,终于可以在浏览器中使用了

// sum.js
define(“sum”, function() {
  return {
    sum: function(a, b) { return a + b; }
  };
});

// app.js
define(“app”, [“sum”], function(cal) {
  console.log(cal.sum(1, 2)); // => 3
});

但是以上的代码直接写是没办法运行的,如果想在浏览器中直接运行,需要知道define是个什么鬼,所以需要先把RequireJS引入,这就是RequireJS的作用,在浏览器中实现define, 引入依赖包。

// main.js
requirejs.config({ baseUrl: ‘/scripts’ });
requirejs([‘app’]);

看着这种不一致的痛苦ECMAScript 6终于忍不了了,加入了import/export标准来统一JavaScript世界,这就是标准的力量,但是从语法上来看还是同步的加载,还是没有办法支持浏览器,不知道这块ECMAScript 6是怎么考量的。

// sum.js
export function sum(a, b) { return a + b; }

// app.js
import * as cal from ‘sum’;

console.log(cal.sum(1, 2)); // => 3

综合以上的分析,在ES6还没有实现完成的今天如果想写一段同时支持前后台,支持AMD, CommonJS的代码要想下面这个样子。

;(function (root, factory, undef) {
    if (typeof exports === “object”) {
        // CommonJS
        module.exports = exports = factory(require(“./core”), require(“./cipher-core”));
    }
    else if (typeof define === “function” && define.amd) {
        // AMD
        define([“./core”, “./cipher-core”], factory);
    }
    else {
        // Global (browser)
        factory(root.CryptoJS);
    }
}(this, function (CryptoJS) {

    return CryptoJS.pad.Pkcs7;

}));

总结

本文总结了RequireJS,CommonJS,AMD,ES6 import/export的前世今生,并且对每个部分给出了完整的代码样例,希望对大家有所帮助。

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn

JavaScript基本类型及类型转换

  每种语言都有自己的基本类型,JavaScript也不例外。在JavaScript中有五大基本类型,分别是number,string,boolean,null,undefined。其他不属于这五种基本类型的都是对象,有时候null也h是对象的一种。

  一、基本类型介绍

  可以通过typeof来确定是哪种类型。

  number包括基本的数字,Infinity,unInfinity,NaN。其中NaN比较特殊,在一个不能做运算的时候做了运算就会得到NaN的结果,例如1*’abc’。

  string几乎所有的语言都有的类型,但是实现都不一样。

  boolean也是很常见的一种基本类型,只有两个值true和false。

  null其实就是空

  undefined指的是未定义的

  二、类型转换

  任何语言都可以进行类型转换。javascript特殊的一点是她回自动做一些类型转换,这样做的好处是开发者不用做一些强制的类型转换,但是这个特性也是被视为javascript诟病之一,很多人认为这个特性会造成一些意想不到的错误。当然我觉得只要掌握好类型转换的特点和细节,就能够趋利避害。

  说几点在类型转换中容易出错的地方。

  在做+操作时一定要注意,因为在javascript中,+既可以是数字的加法,也可以是字符串的拼接。当两个操作数之一是字符串是就会将另一个数字转换为字符串,再做字符串的拼接,例如1+’12’和’1’+12得到的都是字符串’112’。所以如果想要做数字的加法,一定要保证两个操作数都是数字,可以用Number进行强制类型转换,例如1+Number(’12’)。当然也可以用一些简单地转换例如1+1*’12’。但是不推荐这二种做法,因为语义不明确,会给阅读代码的人造成困惑或误解。

  任何变量都可以转换为Boolean值,不是true就是false。常见的空字符串”,undefined,null,NaN,0都可以被转换为false。其他的则都是true。

  我们在定义变量时,经常会这么做var a = a || 10。我们想做的是,如果a被定义了则使用a的值,没定义则赋值为10.但是经常忽略,如果a的值为0。所以这种定义方法一定要慎用。

  在javascript中做等比较时有两种做法,一个是==另一个是===,对应的不等比较是!=和!==。===被称作是严格相等。两者的区别是,==会做类型转换而===不会,例如1==’1’,1==true都会返回true,而1===’1′,1===true则会返回false。所以在做等比较时也一定要慎重。

  三、总结

  作为一门弱类型语言,javascript的类型转换一方面给开发者带来了很多方便而受人们追捧,另一方面也会产生一些莫名其妙的错误而遭人谩骂。其实我觉得任何语言都是不完美的,而我们能做的就是真正精通这些可能产生误区的特性,趋利避害才是王道。

大话设计模式(带目录完整版) PDF+源代码  http://www.linuxidc.com/Linux/2014-08/105152.htm

JavaScript设计模式 中文清晰扫描版PDF  http://www.linuxidc.com/Linux/2015-09/122725.htm

javascript(对象之"."和"[]"访问的差别)

对象的奇怪之处:

function Test(){

this.2=”test”;

}

这个对象是错误的.因为变量名不能是数字.这很好理解.但是请看下面:

var Test = {2:”test”};

利用对象直接量创建的对象确能有数字的属性.这里又要注意一点.两种访问对角的方式.”.”和”[]”.

在这里只能用Test[2]或Test[‘2’]来访问.却不能用Test.2来访问.

这说明[]和.是不等价的.其实可以把Test()对象的定义改下.

function Test(){

this[2]=”test”;

}

这样也是可行的.

针对”.”和”[]”还有一种区别.

var test1 = new Test();

test1.another = 5;

alert(test1.another); 这是可行的.

换成[]同样可行.但请看下面.

var test1 = new Test();

another = “test”;

test1.another = 5;//2

alert(test1.another); //成功

alert(test1.test);//失败..很显然在//2时并没有把another 替换成test.把”.”号改成”[]”却可以.这说明要给一个对象添加一个新的属性,而这个属性又是变量时,只能用”[]”方法.

总结:

“[]”相对”.”的优势.一是可以用变量.二是变量可以是任意值,而不局限于合法的标志符。

更科学的解决请参考<>page154