js代码规范和动态加载js
来源:互联网 发布:系统工程师 软件开发 编辑:程序博客网 时间:2024/05/20 07:15
js代码规范
JavaScript文件
JavaScript程序应该作为一个.js文件存储和发布。
JavaScript代码不应该嵌入在HTML文件里,除非那些代码是一个单独的会话特有的。HTML里的JavaScript代码大大增加了页面的大小,并且
很难通过缓存和压缩来缓解。
<script src=filename.js>标签应该在body里越靠后的位置越好。这减少了由于加载script而导致的其它页面组件的延迟。没有必要使用
language或者type属性。由服务器而不是script标签来决定MIME类型。
缩进
缩进的最小单位是4个空格。不要使用tab键,because (as of this writing in the 21st Century) there still is not a standard
for the placement of tabstops. 使用空格会引起文件变大,但是这点大小对局域网无关紧要,而且差别被minification消除了。
行宽
不要让一行代码超过80个字符。当一条语句不能在单独一行写完时,可能有必要拆分它。在操作符后进行拆分,最好是在逗号后面拆分。
操作符后面进行拆分减少了通过插入分号伪装copy-paste错误的可能性。下一行应该缩进8个空格。
注释
慷慨的写注释。留下一些供需要理解你做了什么的人们(可能是你自己)下次阅读的信息是有用的。注释应该书写良好和清晰,就像它们
标注的代码一样。偶尔小幽默一把也是可以的。挫折和怨恨就别写了。
更新注释非常重要。错误的注释让程序更难读懂和理解。
让注释有意义。更多的关注于不能马上可见的东西。不要用如下内容浪费读者的时间:
- i = 0; // Set i to zero.
i = 0; // Set i to zero.
一般使用行注释。把块注释用于正式文档或外部注释。
变量声明
所有的变量应该在使用前声明。JavaScript不强求这点,但是这样做会让程序更易读,并且会让探测未声明的可能变成隐式的globals的
变量更容易。
var语句应该为方法体内的第一个语句。
每个变量声明应该自己占一行并有注释。它们应该按字母顺序排列。
- var
currentEntry; //currentyly selected table entry - var
level; // indentation level - var
size; // size of table
JavaScript没有块作用域,所以在块里定义变量可能会让有其它C家族语言经验的程序员迷惑。在方法顶端定义所有变量。
尽量少使用全局变量。隐式的全局变量应该从来不使用。
方法声明
所有的方法应该在它们使用前声明。内部方法应该位于var语句后面。这让哪些变量包含在它的scope里更清楚。
方法名和参数列表的“(”(左圆括号)之间不应该有空格。在“)”(右圆括号)和“{”(左大括号)之间有一个空格。
方法体本身缩进4个空格。“}”(右大括号)应该和方法声明处对齐。
- function
outer(c, d) { -
var e = c * d; -
-
function inner(a, b) { -
return (e * a) + b; -
} -
-
return inner( 0,1); - }
这个规范可以和JavaScript很好的工作,因为在JavaScript里方法和对象字面量可以放在允许表达式的任何位置。它使用内部方法和复杂
结构提供最好的可读性。
- function
getElementsByClassName(className) { -
var results = []; -
walkTheDOM(document.body, function (node) { -
var a; // array of class names -
var c = node.className; // the node's classname -
var i; // loop counter - //
If the node has a class name, then split it into a list of simple names. - //
If any of them match the requested name, then append the node to the set of results. -
if (c) { -
a = c.split(' ' ); -
for (i 0;= i 1)< a.length; i += { -
if (a[i] === className) { -
results.push(node); -
break; -
} -
} -
} -
}); -
return results; - }
如果一个方法字面量为匿名的,则在“function”和“(”(左圆括号)之间应该有一个空格。如果省略空格,则它可能看起来方法名是
“function”,而这是错误的。
- div.onclick
= function (e) { -
return false; - };
- that
= { -
method: function () { -
return this.datum; -
}, -
datum: 0; - };
尽量少用全局方法。
命名
命名应该由26个大小写字母(A .. Z, a .. z),10个数字(0 .. 9)和_(下划线)组成。不要使用国际字符,因为它们可能不易读或者不能在
任何地方都能容易理解。不要在名字里使用$(美元符号)或\(反斜线符号)。
不要使用_(下划线)作为名字的首字母。它有时被用来表示私有,但是它实际上不提供私有性。
如果私有性很重要,使用提供私有性的private members。
Avoid conventions that demonstrate a lack of competence.
大多数变量和方法名应该以小写字母开始。
必须使用new前缀的构造函数应该以大写字母开始。JavaScript不会在省略new时报编译期警告或运行时警告。
不使用new时会发生坏事情,所以大写首字母规范是我们拥有的唯一的防御。
全局变量应该全部使用大写字母。(JavaScript没有宏或常量,所以没有多少要求使用大写字母来表示JavaScript的特性的场景)
语句
简单语句
每行应该包含至少一个语句。在每个简单语句末尾添加一个“;”(分号)。注意一个给方法字面量或对象字面量赋值的赋值语句仍然是
一个赋值语句,所以也必须以分号结尾。
JavaScript允许任何表达式作为语句使用。这可能产生一些错误,特别是在插入分号时。唯一可以当作语句使用的表达式是赋值表达式和
调用表达式。
复合语句
复合语句是包含一个用“{}”(大括号)包围语句列表的的语句。
1,包围的语句应该再缩进4个空格。
2,“{”(左大括号)应该位于开始复合语句的行的末尾。
3,“}”(右大括号)应该新起一行并且和相匹配的“{”所在那行的起始位置对齐
4,当语句是控制结构的一部分时,所有语句都应该用括号包围,即使是单行语句,例如if或for语句。这让添加语句更容易而且不会引起八哥。
标签
语句标签是可选的。只有如下语句需要被标签标识: while,do,for,switch。
return语句
具有值的return语句不应该使用“()”(圆括号)包围值。返回值表达式必须和return关键字在同一行从而避免插入分号。
if语句
if语句应该使用如下格式:
- if
(condition) { -
statements; - }
-
- if
(condition) { -
statements; - }
else { -
statements; - }
-
- if
(condition) { -
statements; - }
else if (condition) { -
statements; - }
else { -
statements; - }
for语句
for语句应该使用如下格式:
- for
(initialization; condition; update) { -
statements; - }
-
- for
(variable in object) { -
statements; - }
第一种格式应该和数组使用。
第二种格式应该和对象使用。注意添加到对象的prototype中的成员将被包含在遍历中。通过使用hasOwnProperty方法来区分对象的
成员是明智的:
- for
(variable in object) { -
if (object.hasOwnProperty()) { -
statements; -
} - }
while语句
while语句应该使用如下格式:
- while
(condition) { -
statements; - }
do语句
do语句应该使用如下格式:
- do
{ -
statements; - }
while (condition);
不像其它复合语句,do语句始终使用“;”(分号)结尾。
switch语句
switch语句应该有如下格式:
- switch
(expression) { - case
expression: -
statements; - default:
-
statements; - }
每个case和switch对齐,这避免了缩进过度。
每组语句(除了default)应该以break,return或者throw结束。不要fall through。
try语句
try语句应该使用如下格式:
- try
{ -
statements; - }
catch (variable) { -
statements; - }
-
- try
{ -
statements; - }
catch (variable) { -
statements; - }
finally { -
statements; - }
continue语句
不要使用continue语句。它会让方法的控制流程模糊。
with语句
不要使用with语句。
空格
空行通过将逻辑相关的代码放到一起来增加可读性。
空格应该用于如下情况:
1,关键字后面跟“(”(左圆括号)时应该用一个空格隔开。
- while
( true){
2,方法名和方法的“(”(左圆括号)之间不要有空格。这利于区分关键字和方法调用。
3,所有的二元操作符,除了“.”(圆点)、“(”(左圆括号)和“[”(左中括号),都应该使用一个空格来和操作数隔开。
4,一元操作符和操作数之间不应该使用空格隔开,除了操作符是一个单词时,如typeof。
5,for语句控制部分的每个“;”(分号)应该在后面跟一个空格。
6,每个“,”(逗号)后面应该跟一个空格。
额外的建议
{}和[]
使用{}替代new Object()。使用[]替代new Array()。
当成员名字为连续的整数时使用数组。当成员名字为任意的字符串或名字时使用对象。
逗号操作符
不要使用逗号操作符,除了for语句的控制部分的严格使用。(这不适合逗号操作符,它应该用于对象字面量,数组字面量,var语句和参数
列表。)
块作用域
在JavaScript里块没有作用域,只有方法有作用域。不要使用块,除了复合语句一定需要用到外。
赋值表达式
不要在if和while语句的条件部分做赋值。不要写不易懂的代码。
===和!==操作符
始终使用===和!==操作符会更好。==和!=操作符会做类型强制转换。特别是,不要使用==来和“假”值做比较。
令人混淆的加和减
注意不要在“+”后面跟“+”或“++”。这种模式令人混淆。在它们之间插入圆括号来让你的意图更清晰。
- total
= subtotal + +myInput.value; -
- //
is better written as -
- total
= subtotal + (+myInput.value);
这样“+ +”就不会被读错成“++”。
邪恶的eval
eval方法是JavaScript里最滥用的特性。不要使用它。
eval有别名。不要使用Function构造函数。不要传递字符串给setTimeout或者setInterval。
14条最佳JS代码编写技巧
写任何编程代码,不同的开发者都会有不同的见解。但参考一下总是好的,下面是来自Javascript Toolbox发布的14条最佳JS代码编写技巧,Sofish翻译(1,2)。
1. 总是使用 ‘var’
在JavaScript中,变量不是全局范围的就是函数范围的,使用”var”关键词将是保持变量简洁明了的关键。当声明一个或者是全局或者是函数级(function-level)的变量,需总是前置”var”关键词,下面的例子将强调不这样做潜在的问题。
不使用 Var 造成的问题
1
var
i=0;
// This is good - creates a global variable
2
function
test() {
3
for
(i=0; i<10; i++) {
4
alert(
"Hello World!"
);
5
}
6
}
7
test();
8
alert(i);
// The global variable i is now 10!
因为变量函数中变量 i 并没有使用 var 使其成为函数级的变量,在这个例子中它引用了全局变量。总是使用 var 来声明全局变量是一个很多的做法,但至关重要的一点是使用 var 定义一个函数范围的变量。下面这两个方法在功能上是相同的:
正确的函数
1
function
test() {
2
var
i=0;
3
for
(i=0; i<10; i++) {
4
alert(
"Hello World!"
);
5
}
6
}
正确的函数
1
function
test() {
2
for
(
var
i=0; i<10; i++) {
3
alert(
"Hello World!"
);
4
}
5
}
2. 特性检测而非浏览器检测
一些代码是写来发现浏览器版本并基于用户正使用的客户端的对其执行不同行为。这个,总的来说,是一个非常糟的实践。更好的方法是使用特性检测,在使用一个老浏览器可能不支持的高级的特性之前,首先检测(浏览器的)是否有这个功能或特性,然后使用它。这单独检测浏览器版本来得更好,即使你知道它的性能。你可以在 http://www.jibbering.com/faq/faq_notes/not_browser_detect.html找到一个深入讨论这个问题的文章。
例子:
1
if
(document.getElementById) {
2
var
element = document.getElementById(
'MyId'
);
3
}
4
else
{
5
alert(
'Your browser lacks the capabilities required to run this script!'
);
6
}
3. 使用方括号记法
当访问由执行时决定或者包括要不能用”.”号访问的对象属性,使用方括号记法。如果你不是一个经验丰富的Javascript程序员,总是使用方括号是一个不错的做法
对象的属性由两种固定的方法来访问:”.”记法和”[ ]“方括号记法:
“.”号记法
1
MyObject.property
“[ ]“方括号记法
1
MyObject[
"property"
]
使用”.”号,属性名是硬代码,不能在执行时改变。使用”[ ]“方括号,属性名是一个通过计算属性名而来的字符串。字符串要以是硬代码,也可能是变量,甚至可以是一个调回一个字母串值的函数。如果一个属性名在执行产生,方括号是必须,如果你有 “value1″, “value2″, 和 “value3″这样的属性,并且想利用变量 i=2来访问
这个可以运行:
1
MyObject[
"value"
+i]
这个不可以:
1
MyObject.value+i
并且在某些服务器端环境(PHP、Struts等)下,Form 表单被附加了 [ ] 号来表示 Form 表单在服务器端必须被当作数组来对待。如此,用”.”号来引用一个包含 [ ] 号的字段将不会执行,因为 [ ] 是引用一个 Javascript 数组的语法。所以,[ ] 号记法是必须的:
这个可以运行:
1
formref.elements[
"name[]"
]
这个不可以:
1
formref.elements.name[]
推荐使用”[ ]“方括号记法是说当其需要时(明显地)总是使用它。当不是严格需要使用它的时候,它是一个私人的偏好和习惯。一个好的经验原则是,使用”.”号记法访问标准的对象属性,使用”[ ]“方括号记法访问由页面定义的对象属性。这样,document["getElementById"]() 是一个完美可行的”[ ]“方括号记法用法,但 document.getElementById() 在语法上是首选,因为 getElementById 是一个 DOM 规范中定义的一个标准文档对象属性。混合使用这两个记法使哪个是标准对象属性,哪个属性名是由上下文所定义的,在代码中显得清晰明了:
1
document.forms[
"myformname"
].elements[
"myinput"
].value
这里,forms 是 document 的一个标准属性,而表单名 myformname 则是由页面所定义的。同时,elements 和 value 属性都是由规范所定义的标准属性。而 myinput 则是由页面所定义的。这页是句法让人非常容易理解(代码的内容),是一个推荐遵循的习惯用法,但不是严格原则。
4. 避免 ‘eval’
在Javascript中,eval()功能是一个在执行期中执行任意代码的方法。在几乎所有的情况下,eval 都不应该被使用。如果它出现在你的页面中,则表明你所做的有更好的方法。举一个例子,eval 通常被不知道要使用方括号记法的程序员所使用。
原则上,”Eval is evil(Eval是魔鬼)”。别使用它,除非你是一个经验丰富的开发者并且知道你的情况是个例外。
5. 正确地引用表单和表单元素
所有的 HTML 表单都应该有一个 name 属性。对于 XHTML 文档来说,name 属性是不被要求的,但 Form 标签中应有相应有 id 属性,并必须用 document.getElementById() 来引用。使用像 document.forms[0] 这样的索引方法来引用表单,在几乎所有情况下,是一个糟糕的做法。有些浏览器把文档中使用 form 来命名的元素当作一个可用的 form 属性。这样并不可靠,不应该使用。
下面这个例子用使用方括号和正确的对象引用方法来展示如何防止错误地引用一个表单的input:
正确引用表单 Input:
1
document.forms[
"formname"
].elements[
"inputname"
]
糟糕的做法:
1
document.formname.inputname
如果你要引用一个函数里的两个表单元素,较好的做法是先引用这个form对象,并将其储存在变量中。这样避免了重复查询以解决表单的引用:
1
var
formElements = document.forms[
"mainForm"
].elements;
2
formElements[
"input1"
].value=
"a"
;
3
formElements[
"input2"
].value=
"b"
;
当你使用 onChange 或者其他类似的事件处理方法,一个好的做法是总是通过一个引来把 input 元素本身引用到函数中来。所有 input 元素都带有一个对包含其在内的Form表单有一个引用:
01
<input type=
"text"
name=
"address"
onChange=
"validate(this)"
>
02
03
function
validate(input_obj) {
04
// 引用包含这个元素的form
05
var
theform = input_obj.form;
06
// 现在你可以不需要使用硬代码来引用表单自身
07
if
(theform.elements[
"city"
].value==
""
) {
08
alert(
"Error"
);
09
}
10
}
通过对表单元素的引用来访问表单的属性,你可以写一个不包含硬代码的函数来引用这个页面中任何一个有特定名的表单。这是一个非常好的做法,因为函数变得可重用。
6. 避免 ‘with’
Javascript 中的 with 声明在一个作用域的前端插入一个对象,所以任何属性/变量的引用将会倚着对象被首先解决。这通常被用作一个避免重复引用的快捷方法:
使用 with 的例子:
1
with
(document.forms[
"mainForm"
].elements) {
2
input1.value =
"junk"
;
3
input2.value =
"junk"
;
4
}
但问题在于程序员并没有方法来验证 input1 或 input2 实际上已经被当作 Form 元素数组的属性来解决。它首先以为这些名来检测属性,如果找不到,它将会继续(向下)检测这个作用域。最后,它在全局对象中尝试把input1 和 input2 作为一个全局对象来对待,而这以一个错误作为结尾。
变通的方法是:创建一个引用来减少引用的对象,并使用它来解决这些引用。
使用一个引用:
1
var
elements = document.forms[
"mainForm"
].elements;
2
elements.input1.value =
"junk"
;
3
elements.input2.value =
"junk"
;
7. 在锚点中使用 “onclick” 替代 “javascript: Pseudo-Protocol”
如果你想在 标签中触发Javascript 代码,选择 onclick 而非 JavaScript: pseudo-protocol;使用 onclick 来运行的 Javascript 代码必须返回 ture 或者false(or an expression than evalues to true or false [这句要怎么翻译呢? 我是这样理解的:一个优先性高于true 或 false 的表达式])来返回标签本身:如果返回 true,则锚点的 href 将被当作一个一般的链接;如果返回 false,则 href 会被忽略。这就是为什么”return false;” 经常被包含在 onclick 所处理代码的尾部。
正确句法:
1
<a href=
"javascript_required.html"
onclick=
"doSomething(); return false;"
>go</a>
在这个实例中,”doSomething()” 函数(定义于页面的某个角落)将在被点击时调用。href 将永远不会被启用了Javascript 的浏览器访问。在你可以提醒Javascript 是必须的、而用户未启用之的浏览器中,文档 javascript_required.html 才会被加载。通常,当你确保用户将会开启 Javascript 支持,为尽量简化,链接将只包含 href=”#”。 而这个做法是不被鼓励的。通常有一个不错的做法是:可以提供没用启用 javascript 一个返回本地的页面。
有时,众多想要分情况来访问一个链接。例如,当一个用户要离开你的一个表单页面,而想先验证来确保没有东西被改变。在这个情况下,你的 onclick 将会访问一个返回询问链接是否应该被遵循的函数:
有条件的链接访问:
1
<a href=
"/"
onClick=
"return validate();"
>Home</a>
2
3
function
validate() {
4
return
prompt(
"Are you sure you want to exit this page?"
);
5
}
在这个实例中,validate() 函数必须只返回 ture 或 false。ture 的时候用户将被允许问题 home 页面,或 false 的时候链接不被访问。这个例子提示确认(其行为),以访问 ture 或 false,这完全由用户点击”确实”或者”取消”决定。
下面是一些”不应该”的例子。如果你在自己的页面中看到下面这样的代码,这是不正确的,需要被修改:
什么是不应该做的:
1
<a href=
"javascript:doSomething()"
>link</a>
2
<a href=
"#"
onClick=
"doSomething()"
>link</a>
3
<a href=
"#"
onClick=
"javascript:doSomething();"
>link</a>
4
<a href=
"#"
onClick=
"javascript:doSomething(); return false;"
>link</a>
8. 使用一元 ‘+’ 号运算符使类型转向Number
在Javascript中,”+”号运算符同时充当数学加号和连接符。这会在form表单的域值相加时出现问题,例如,因为Javascript是一个弱类型语言,form 域的值将会被当作数组来处理,而你把它们”+”一起的时候,”+”将被当成连接符,而非数学加号。
有问题的例子:
01
<form name=
"myform"
action=
"[url]"
>
02
<input type=
"text"
name=
"val1"
value=
"1"
>
03
<input type=
"text"
name=
"val2"
value=
"2"
>
04
</form>
05
06
function
total() {
07
var
theform = document.forms[
"myform"
];
08
var
total = theform.elements[
"val1"
].value + theform.elements[
"val2"
].value;
09
alert(total);
// 这个将会弹出 "12", 但你想要的是 3!
10
}
解决这个问题,Javascript 需要一个提示来让它把这些值当做数字来处理。你可以使用”+”号来把数组转换成数字。给变量或者表达式前置一个”+”号将会强制其当作一个数字来处理,而这也将使得数学”+”得以成功应用。
修改好的代码:
1
function
total() {
2
var
theform = document.forms[
"myform"
];
3
var
total = (+theform.elements[
"val1"
].value) + (+theform.elements[
"val2"
].value);
4
alert(total);
// This will alert 3
5
}
9. 避免 document.all
document.all 是由Microsoft 的 IE 所引进的,并不是一个标准的 Javascript DOM 特性。尽管大多数新的浏览器支持它以支持依赖于它的糟糕代码,(而)还有很多浏览器是不支持的。
并没有理由其他方法都不适用,而一个老的IE浏览器(<5.0)需要支持,而在Javascript中使用 document.all 作为一个折衷方法。 你并不需要使用 document.all 来检测其是不是IE浏览器,因为其他浏览器现在一般都支持。
只把 document.all 当做最后的选择:
1
if
(document.getElementById) {
2
var
obj = document.getElementById(
"myId"
);
3
}
4
else
if
(document.all) {
5
var
obj = document.all(
"myId"
);
6
}
一些使用 document.all 的原则:
* 同尝试其他方法
* 当其作为最后的选择
* 当需要支持 5.0 版本以下的 IE 浏览器
* 总是使用 “if (document.all) { }” 来查看是否支持.
10. 不要在脚本代码块中使用HTML注释
在 Javascript 的旧日子(1995)里,诸如 Netscape 1.0 的一些浏览器并不支持或认识 <script> 标签。所以,当 Javascript 第一次被发布,需要有一个技术来让实些代码不被当做文本显示于旧版浏览器上。有一个”hack” 是在代码中使用 HTML 注释来隐藏这些代码。
使 HTML 注释并不好:
1
<script language=
"javascript"
>
2
<!--
3
// code here
4
//-->
5
</script>
在今天,没有任何一个常用的浏览器会忽略掉 <script> 标签。因此,再没必要隐藏 Javascript 源代码。事实上,它还可以因为下面的理由,被认为是无益的:
* 在 XHTML 文档中,源代码将向所有浏览器隐藏并被渲染成无用的(内容);
* – 在 HTML 注释并不允许 ,这个会让任何递减操作将失效。
11. 避免乱用全局命名空间
一般很少需要全部变量和函数。全局使用将可能导致 Javascript 源文件文档冲突,和代码中止。因此,一个好的做法是在一个全局命名空间内采用函数性的封装。有多个方法可以完成这个任务,有此相对比较复杂。最简单的方法是创建一个全局对象,并把属性和方法指派给这个对象:
创建一个命名空间:
1
var
MyLib = {};
// global Object cointainer
2
MyLib.value = 1;
3
MyLib.increment =
function
() { MyLib.value++; }
4
MyLib.show =
function
() { alert(MyLib.value); }
5
6
MyLib.value=6;
7
MyLib.increment();
8
MyLib.show();
// alerts 7
命名空间也可以使用 Closures(闭包?) 来创建,并且 Private Member Variables (私有变量?) 也可以伪装于 Javascript中。
12. 避免同步的 ‘Ajax’ 调用
当使用”Ajax”请求时,你要么选择异步模式,要么使用同步模式。当浏览器行为可以继续执行,异步模式将请求放在后台执行,同步模式则会等待请求完成后才继续。
应该避免同步模式做出的请求。这些请求将会对用户禁用浏览器,直至请求返回。一旦服务器忙,并需要一段时间来完成请求,用户的浏览器(或者 OS)将不能做任何其他的事,直至请求超时。
如果你觉得自己的情况需要同步模式,最大的可能是你需要时间来重新想一下你的设计。很少(如果有的话)实际上需要同步模式的 Ajax 请求。
13. 使用 JSON
当需要将数据结构存储成纯文本,或者通过 Ajax 发送/取回数据结构,尽可能使用 JSON 代替 XML。JSON (JavaScript Object Notation) 是一个更简洁有效的数据存储格式,并且不依赖任何语言(and is a language-neutral)。
14. 使用正确的 <script> 标签
不造成在 <script> 中的使用LANGUAGE 属性。一个合适的方式是创建如下的 Javascript 代码块:
1
<script type=
"text/javascript"
>
2
// code here
3
</script>
javascirpt 的一些在IE下不支持的函数小结
好多js的方法都是在IE9+才支持,连IE8都不支持。。想要实现这些方法只能自己写,总结下。
// ============ isArray ===============//
// isArray
function isArray(value){
return Object.prototype.toString.call(value) == "[object Array]";
}
var arr = [1,2,3,4,5];
alert(isArray(arr)); // IE8 及以下不支持
// ============ filter 等 ===============//
// 数组的一些方法 every(), filter(), forEach(), map(), some()
// IE8 及以下不支持
// 解决办法,以filter为例,自己写一个filter
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/){
var len = this.length;
if (typeof fun != "function"){
throw new TypeError();
}
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++){
if (i in this){
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this)) {
res.push(val);
}
}
}
return res;
};
}
var numbers = [1,2,3,4,5,6];
var filterResult = numbers.filter(function(item, inde, array){
return (item>2);
});
alert(filterResult); // 3,4,5,6
// ============ Date.now() ===============//
// Date.now(); IE8及以下不支持,只能自己写一个解决
if(!Date.now){
Date.now = function(){
return new Date().valueOf();
}
}
alert(Date.now());
// ============ stringValue[1] ===============//
// 在IE7 及以下版本显示 undefined
var stringValue = "hello world";
alert(stringValue[1]);
// ============ trim() ===============//
// 在IE8 及以下版本无效,需要自己写
String.prototype.trim = function(){
return this.replace(/(^\s*)(\s*$)/g, "");
};
var stringValue2 = " hello world ";
alert(stringValue2.trim());
用JS实现用 字符串 替换 占位符
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>用JS实现用 字符串 替换 占位符</title>
</head>
<body>
<script type="text/javascript">
String.prototype.format=function()
{
if(arguments.length==0) return this;
for(var s=this, i=0; i<arguments.length; i++)
s=s.replace(new RegExp("\\{"+i+"\\}","g"), arguments[i]);
return s;
};
//占位符可以为多个
alert("http://{0}/{1}".format("www.songyanjun.net", "index.html"));
//与上同理
alert("请输入{0},输完后再按存盘按钮".format("姓名"));
</script>
</body>
</html>
Java中直接调用js代码
JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码。
不能调用浏览器中定义的js函数,会抛出异常提示ReferenceError: “alert” is not defined。
package com.sinaapp.manjushri;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException; /** * 直接调用js代码 */
public class ScriptEngineTest {
public static void main(String[] args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
try{ engine.eval("var a=3; var b=4;print (a+b);"); // engine.eval("alert(\"js alert\");"); // 不能调用浏览器中定义的js函数 // 错误,会抛出alert引用不存在的异常
}catch(ScriptException e){ e.printStackTrace(); } } }
输出结果:7
在Java中绑定js变量
在调用engine.get(key);时,如果key没有定义,则返回null
package com.sinaapp.manjushri; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class ScriptEngineTest2 { public static void main(String[] args) { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("javascript"); engine.put("a", 4); engine.put("b", 3); Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); try { // 只能为Double,使用Float和Integer会抛出异常 Double result = (Double) engine.eval("a+b"); System.out.println("result = " + result); engine.eval("c=a+b"); Double c = (Double)engine.get("c"); System.out.println("c = " + c); } catch (ScriptException e) { e.printStackTrace(); } } }
输出:
result = 7.0
c = 7.0
在Java中调用js文件中的function,传入调用参数,并获取返回值
js文件中的merge函数将两个参数a,b相加,并返回c。
// expression.js
function merge(a, b) {
c = a * b;
return c;
}
在Java代码中读取js文件,并参数两个参数,然后回去返回值。
package com.sinaapp.manjushri; import java.io.FileReader; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; /** * Java调用并执行js文件,传递参数,并活动返回值 * * @author manjushri */ public class ScriptEngineTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("javascript"); String jsFileName = "expression.js"; // 读取js文件 FileReader reader = new FileReader(jsFileName); // 执行指定脚本 engine.eval(reader); if(engine instanceof Invocable) { Invocable invoke = (Invocable)engine; // 调用merge方法,并传入两个参数 // c = merge(2, 3); Double c = (Double)invoke.invokeFunction("merge", 2, 3); System.out.println("c = " + c); } reader.close(); }}
输出结果:
c = 5.0
java调用脚本语言笔记(jython,jruby,groovy)
有两种方法
1.java se 6以后实现了jsr 223规范
java代码:
- ScriptEngineManager factory = new ScriptEngineManager();
- ScriptEngineManager scriptEngine = factory.getEngineByName("javascript");//或者"js"
- scriptEngine.eval(code);//执行一段脚本,code是js代码
很方便调用脚本
2.可以使用脚本语方本身提供的与java的集成手段
jython集成
使用jsr223:
前提下载jython的包,已实现jsr223
(建议在官网上下载,在安装目录下有jython.jar,http://repo2.maven.org/maven2/org/python/jython/2.5.0/ 这里也有,但是这个包里没有jsr223的实现,看包下存不存在org.python.jsr223)
- ScriptEngineManager factory = new ScriptEngineManager();
- ScriptEngineManager scriptEngine = factory.getEngineByName("python");//或者"jython"
- scriptEngine.eval(code);
使用PythonInterpreter,可以调用exec(String code)方法:
- PythonInterpreter interpreter = new PythonInterpreter();
- interpreter.exec(code);
访问数据库
使用jdbc:
- from oracle.jdbc.driver import OracleDriver
- from java.sql import DriverManager
- username = 'hr'
- password = '123456'
- url = 'jdbc:oracle:thin:@localhost:1521:XE'
- driver = OracleDriver()
- DriverManager.registerDriver(driver)
- conn = DriverManager.getConnection(url, username, password)
- stmt = conn.createStatement()
- sql = "select salary from EMPLOYEES t where t.salary<2300"
- rs = stmt.executeQuery(sql)
- while (rs.next()):
- print rs.getInt('salary')
- rs.close()
- stmt.close()
结果:
2200
2100
2200
使用zxJDBC :
- from com.ziclix.python.sql import zxJDBC
- url = 'jdbc:oracle:thin:@localhost:1521:XE'
- username = 'hr'
- password = '123456'
- driverName = 'oracle.jdbc.driver.OracleDriver'
- mysqlConn = zxJDBC.connect(url,username, password,driverName)
- cursor = mysqlConn.cursor()
- cursor.execute("select last_name from EMPLOYEES t where t.salary<2300");
- #print cursor.fetchone()
- list = cursor.fetchall()
- for record in list:
- print "name:"+record[0]
- #print cursor.description[0]
- #print cursor.description[1]
结果:
name:麦克
name:Olson
name:Philtanker
从数据库中查出的中文内容正常的。
而在代码里面的中文全部是乱码或抛异常,未解决。
与jruby集成
使用jsr223:Java代码
- ScriptEngineManager factory = new ScriptEngineManager();
- ScriptEngineManager scriptEngine = factory.getEngineByName("jruby");//或者"ruby"
- scriptEngine.eval(code);
访问数据库
Ruby代码
- require 'java'
- module JavaLang
- include_package "java.lang"
- end
- module JavaSql
- include_package 'java.sql'
- end
- begin
- username = 'hr'
- password = '123456'
- url = 'jdbc:oracle:thin:@localhost:1521:XE'
- driverName = 'oracle.jdbc.driver.OracleDriver'
- JavaLang::Class.forName(driverName).newInstance
- conn = JavaSql::DriverManager.getConnection(url, username, password)
- stmt = conn.createStatement
- sql = "select last_name from EMPLOYEES t where t.salary<2300"
- rs = stmt.executeQuery(sql)
- while (rs.next) do
- puts "名字:"+rs.getString("last_name")
- end
- rs.close
- stmt.close
- conn.close()
- rescue JavaLang::ClassNotFoundException
- puts "ClassNotFoundException"
- rescue JavaSql::SQLException
- puts "SQLException"
- end
结果:
名字:楹﹀厠
名字:Olson
名字:Philtanker
从数据库中查出的中文内容为乱码的。
而在代码里面的中文正常。
与groovy集成
使用jsr223:
Java代码
- ScriptEngineManager factory = new ScriptEngineManager();
- ScriptEngineManager scriptEngine = factory.getEngineByName("groovy");//或者"Groovy"
- scriptEngine.eval(code);
使用GroovyShell:
Java代码
- GroovyShell shell = new GroovyShell();
- Script script = shell.parse(code);
- Object result = script.run();
访问数据库
- import groovy.sql.Sql
- def username = 'hr'
- def password = '123456'
- def url = 'jdbc:oracle:thin:@localhost:1521:XE'
- def driverName = 'oracle.jdbc.driver.OracleDriver'
- def sql = Sql.newInstance(url, username, password, driverName)
- sql.eachRow("select last_name from EMPLOYEES t where t.salary<2300") {
- println "名字:${it.last_name}"
- }
结果:
名字:麦克
名字:Olson
名字:Philtanker
在使用groovy过程中碰到了一个异常
Exception in thread "main" java.lang.VerifyError: (class: groovy/runtime/metaclass/java/util/ArrayListMetaClass, method: super$2$invokeMethod signature: (Ljava/lang/Class;Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;ZZ)Ljava/lang/Object;) Illegal use of nonvirtual function call
这个异常解决花了很长时间
是因为在原来项目中存在json-lib-2.1.jar(有可能名称为json-lib-2.1-jdk15.jar),这个包是用来处理json的,与groovy1.7.5存在冲突,更新为json-lib-2.3.jar即可
(json-lib里有一些groovy运行时处理的内容)
JS正则表达式知识大全
1、非捕获性分组:?:
在一些只需要分组匹配但是并不需要得到各个分组匹配的结果时使用非捕获性分组可以提高匹配速度
)
正则表达式可以:
•测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证
•替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字
•根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字
正则表达式语法
一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
创建正则表达式
- var re = new RegExp();//RegExp是一个对象,和Aarray一样
- //但这样没有任何效果,需要将正则表达式的内容作为字符串传递进去
- re =new RegExp("a");//最简单的正则表达式,将匹配字母a
- re=new RegExp("a","i");//第二个参数,表示匹配时不分大小写
var re = new RegExp();//RegExp是一个对象,和Aarray一样//但这样没有任何效果,需要将正则表达式的内容作为字符串传递进去re =new RegExp("a");//最简单的正则表达式,将匹配字母are=new RegExp("a","i");//第二个参数,表示匹配时不分大小写
RegExp构造函数第一个参数为正则表达式的文本内容,而第一个参数则为可选项标志.标志可以组合使用
•g (全文查找)
•i (忽略大小写)
•m (多行查找)
- var re = new RegExp("a","gi");//匹配所有的a或A
var re = new RegExp("a","gi");//匹配所有的a或A
正则表达式还有另一种正则表达式字面量的声明方式
- var re = /a/gi;
var re = /a/gi;
和正则表达式相关的方法和属性
正则表达式对象的方法
•test,返回一个 Boolean 值,它指出在被查找的字符串中是否存在模式。如果存在则返回 true,否则就返回 false。
•exec,用正则表达式模式在字符串中运行查找,并返回包<script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>含该查找结果的一个数组。
•compile,把正则表达式编译为内部格式,从而执行得更快。
正则表达式对象的属性
•source,返回正则表达式模式的文本的复本。只读。
•lastIndex,返回字符位置,它是被查找字符串中下一次成功匹配的开始位置。
•$1...$9,返回九个在模式匹配期间找到的、最近保存的部分。只读。
•input ($_),返回执行规范表述查找的字符串。只读。
•lastMatch ($&),返回任何正则表达式搜索过程中的最后匹配的字符。只读。
•lastParen ($+),如果有的话,返回任何正则表达式查找过程中最后括的子匹配。只读。
•leftContext ($`),返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符。只读。
•rightContext ($'),返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符。只读。
String对象一些和正则表达式相关的方法
•match,找到一个或多个正则表达式的匹配。
•replace,替换与正则表达式匹配的子串。
•search,检索与正则表达式相匹配的值。
•split,把字符串分割为字符串数组。
测试正则表达式是如何工作的!
- //test方法,测试字符串,符合模式时返回true,否则返回false
- var re = /he/;//最简单的正则表达式,将匹配he这个单词
- var str = "he";
- alert(re.test(str));//true
- str = "we";
- alert(re.test(str));//false
- str = "HE";
- alert(re.test(str));//false,大写,如果要大小写都匹配可以指定i标志(i是ignoreCase或case-insensitive的表示)
- re = /he/i;
- alert(re.test(str));//true
- str = "Certainly!He loves her!";
- alert(re.test(str));//true,只要包含he(HE)就符合,如果要只是he或HE,不能有其它字符,则可使用^和$
- re = /^he/i;//脱字符(^)代表字符开始位置
- alert(re.test(str));//false,因为he不在str最开始
- str = "He is a good boy!";
- alert(re.test(str));//true,He是字符开始位置,还需要使用$
- re = /^he$/i;//$表示字符结束位置
- alert(re.test(str));//false
- str = "He";
- alert(re.test(str));//true
- //当然,这样不能发现正则表达式有多强大,因为我们完全可以在上面的例子中使用==或indexOf
- re = /\s/;// \s匹配任何空白字符,包括空格、制表符、换页符等等
- str= "user Name";//用户名包含空格
- alert(re.test(str));//true
- str = "user Name";//用户名包含制表符
- alert(re.test(str));//true
- re=/^[a-z]/i;//[]匹配指定范围内的任意字符,这里将匹配英文字母,不区分大小写
- str="variableName";//变量名必须以字母开头
- alert(re.test(str));//true
- str="123abc";
- alert(re.test(str));//false
//test方法,测试字符串,符合模式时返回true,否则返回falsevar re = /he/;//最简单的正则表达式,将匹配he这个单词var str = "he";alert(re.test(str));//truestr = "we";alert(re.test(str));//falsestr = "HE";alert(re.test(str));//false,大写,如果要大小写都匹配可以指定i标志(i是ignoreCase或case-insensitive的表示)re = /he/i;alert(re.test(str));//truestr = "Certainly!He loves her!";alert(re.test(str));//true,只要包含he(HE)就符合,如果要只是he或HE,不能有其它字符,则可使用^和$re = /^he/i;//脱字符(^)代表字符开始位置alert(re.test(str));//false,因为he不在str最开始str = "He is a good boy!";alert(re.test(str));//true,He是字符开始位置,还需要使用$re = /^he$/i;//$表示字符结束位置alert(re.test(str));//falsestr = "He";alert(re.test(str));//true//当然,这样不能发现正则表达式有多强大,因为我们完全可以在上面的例子中使用==或indexOfre = /\s/;// \s匹配任何空白字符,包括空格、制表符、换页符等等str= "user Name";//用户名包含空格alert(re.test(str));//truestr = "userName";//用户名包含制表符alert(re.test(str));//truere=/^[a-z]/i;//[]匹配指定范围内的任意字符,这里将匹配英文字母,不区分大小写str="variableName";//变量名必须以字母开头alert(re.test(str));//truestr="123abc";alert(re.test(str));//false
当然,仅仅知道了字符串是否匹配模式还不够,我们还需要知道哪些字符匹配了模式
- var osVersion = "Ubuntu 8";//其中的8表示系统主版本号
- var re = /^[a-z]+\s+\d+$/i; //+号表示字符至少要出现1次,\s表示空白字符,\d表示一个数字
- alert(re.test(osVersion));//true,但我们想知道主版本号
- //另一个方法exec,返回一个数组,数组的第一个元素为完整的匹配内容
- re=/^[a-z]+\s+\d+$/i;
- arr = re.exec(osVersion);
- alert(arr[0]);//将osVersion完整输出,因为整个字符串刚好匹配re
- //我只需要取出数字
- re=/\d+/;
- var arr = re.exec(osVersion);
- alert(arr[0]);//8
var osVersion = "Ubuntu 8";//其中的8表示系统主版本号var re = /^[a-z]+\s+\d+$/i; //+号表示字符至少要出现1次,\s表示空白字符,\d表示一个数字alert(re.test(osVersion));//true,但我们想知道主版本号//另一个方法exec,返回一个数组,数组的第一个元素为完整的匹配内容re=/^[a-z]+\s+\d+$/i;arr = re.exec(osVersion);alert(arr[0]);//将osVersion完整输出,因为整个字符串刚好匹配re//我只需要取出数字re=/\d+/;var arr = re.exec(osVersion);alert(arr[0]);//8
更复杂的用法,使用子匹配
- //exec返回的数组第1到n元素中包含的是匹配中出现的任意一个子匹配
- re=/^[a-z]+\s+(\d+)$/i;//用()来创建子匹配
- arr =re.exec(osVersion);
- alert(arr[0]);//整个osVersion,也就是正则表达式的完整匹配
- alert(arr[1]);//8,第一个子匹配,事实也可以这样取出主版本号
- alert(arr.length);//2
- osVersion = "Ubuntu 8.10";//取出主版本号和次版本号
- re = /^[a-z]+\s+(\d+)\.(\d+)$/i;//.是正则表达式元字符之一,若要用它的字面意义须转义
- arr = re.exec(osVersion);
- alert(arr[0]);//完整的osVersion
- alert(arr[1]);//8
- alert(arr[2]);//10
//exec返回的数组第1到n元素中包含的是匹配中出现的任意一个子匹配re=/^[a-z]+\s+(\d+)$/i;//用()来创建子匹配arr =re.exec(osVersion);alert(arr[0]);//整个osVersion,也就是正则表达式的完整匹配alert(arr[1]);//8,第一个子匹配,事实也可以这样取出主版本号alert(arr.length);//2osVersion = "Ubuntu 8.10";//取出主版本号和次版本号re = /^[a-z]+\s+(\d+)\.(\d+)$/i;//.是正则表达式元字符之一,若要用它的字面意义须转义arr = re.exec(osVersion);alert(arr[0]);//完整的osVersionalert(arr[1]);//8alert(arr[2]);//10
注意,当字符串不匹配re时,exec方法将返回null
String对象的一些和正则表达式有关的方法
- //replace方法,用于替换字符串
- var str ="some money";
- alert(str.replace("some","much"));//much money
- //replace的第一个参数可以为正则表达式
- var re = /\s/;//空白字符
- alert(str.replace(re,"%"));//some%money
- //在不知道字符串中有多少空白字符时,正则表达式极为方便
- str ="some some \tsome\t\f";
- re = /\s+/;
- alert(str.replace(re,"#"));//但这样只会将第一次出现的一堆空白字符替换掉
- //因为一个正则表达式只能进行一次匹配,\s+匹配了第一个空格后就退出了
- re = /\s+/g;//g,全局标志,将使正则表达式匹配整个字符串
- alert(str.replace(re,"@"));//some@some@some@
- //另一个与之相似的是split
- var str = "a-bd-c";
- var arr = str.split("-");//返回["a","bd","c"]
- //如果str是用户输入的,他可能输入a-bd-c也可能输入a bd c或a_bd_c,但不会是abdc(这样就说他输错了)
- str = "a_db-c";//用户以他喜欢的方式加分隔符s
- re=/[^a-z]/i;//前面我们说^表示字符开始,但在[]里它表示一个负字符集
- //匹配任何不在指定范围内的任意字符,这里将匹配除字母处的所有字符
- arr = str.split(re);//仍返回["a","bd","c"];
- //在字符串中查找时我们常用indexOf,与之对应用于正则查找的方法是search
- str = "My age is 18.Golden age!";//年龄不是一定的,我们用indexOf不能查找它的位置
- re = /\d+/;
- alert(str.search(re));//返回查找到的字符串开始下标10
- //注意,因为查找本身就是出现第一次就立即返回,所以无需在search时使用g标志
- //下面的代码虽然不出错,但g标志是多余的
- re=/\d+/g;
- alert(str.search(re));//仍然是10
//replace方法,用于替换字符串var str ="some money";alert(str.replace("some","much"));//much money//replace的第一个参数可以为正则表达式var re = /\s/;//空白字符alert(str.replace(re,"%"));//some%money//在不知道字符串中有多少空白字符时,正则表达式极为方便str ="some some \tsome\t\f";re = /\s+/;alert(str.replace(re,"#"));//但这样只会将第一次出现的一堆空白字符替换掉//因为一个正则表达式只能进行一次匹配,\s+匹配了第一个空格后就退出了re = /\s+/g;//g,全局标志,将使正则表达式匹配整个字符串alert(str.replace(re,"@"));//some@some@some@//另一个与之相似的是splitvar str = "a-bd-c";var arr = str.split("-");//返回["a","bd","c"]//如果str是用户输入的,他可能输入a-bd-c也可能输入a bd c或a_bd_c,但不会是abdc(这样就说他输错了)str = "a_db-c";//用户以他喜欢的方式加分隔符sre=/[^a-z]/i;//前面我们说^表示字符开始,但在[]里它表示一个负字符集//匹配任何不在指定范围内的任意字符,这里将匹配除字母处的所有字符arr = str.split(re);//仍返回["a","bd","c"];//在字符串中查找时我们常用indexOf,与之对应用于正则查找的方法是searchstr = "My age is 18.Golden age!";//年龄不是一定的,我们用indexOf不能查找它的位置re = /\d+/;alert(str.search(re));//返回查找到的字符串开始下标10//注意,因为查找本身就是出现第一次就立即返回,所以无需在search时使用g标志//下面的代码虽然不出错,但g标志是多余的re=/\d+/g;alert(str.search(re));//仍然是10
注意,当search方法没有找到匹配时,将返回-1
类似于exec方法,String对象的match方法也用于将字符串与正则表达式进行匹配并返回结果数组
- var str = "My name is CJ.Hello everyone!";
- var re = /[A-Z]/;//匹配所有大写字母
- var arr = str.match(re);//返回数组
- alert(arr);//数组中只会包含一个M,因为我们没有使用全局匹配
- re = /[A-Z]/g;
- arr = str.match(re);
- alert(arr);//M,C,J,H
- //从字符串中抽取单词
- re = /\b[a-z]*\b/gi;//\b表示单词边界
- str = "one two three four";
- alert(str.match(re));//one,two,three,four
var str = "My name is CJ.Hello everyone!";var re = /[A-Z]/;//匹配所有大写字母var arr = str.match(re);//返回数组alert(arr);//数组中只会包含一个M,因为我们没有使用全局匹配re = /[A-Z]/g;arr = str.match(re);alert(arr);//M,C,J,H//从字符串中抽取单词re = /\b[a-z]*\b/gi;//\b表示单词边界str = "one two three four";alert(str.match(re));//one,two,three,four
RegExp对象实例的一些属性
- var re = /[a-z]/i;
- alert(re.source);//将[a-z]字符串输出
- //请注意,直接alert(re)会将正则表达式连同前向斜线与标志输出,这是re.toString方法定义的
var re = /[a-z]/i;alert(re.source);//将[a-z]字符串输出//请注意,直接alert(re)会将正则表达式连同前向斜线与标志输出,这是re.toString方法定义的
每个RegExp对象的实例具有lastIndex属性,它是被查找字符串中下一次成功匹配的开始位置,默认值是-1。 lastIndex 属性被 RegExp 对象的 exec 和 test 方法修改.并且它是可写的.
- var re = /[A-Z]/;
- //exec方法执行后,修改了re的lastIndex属性,
- var str = "Hello,World!!!";
- var arr = re.exec(str);
- alert(re.lastIndex);//0(???试了下,结果为1),因为没有设置全局标志
- re = /[A-Z]/g;
- arr = re.exec(str);
- alert(re.lastIndex);//1
- arr = re.exec(str);
- alert(re.lastIndex);//7
var re = /[A-Z]/;//exec方法执行后,修改了re的lastIndex属性,var str = "Hello,World!!!";var arr = re.exec(str);alert(re.lastIndex);//0(???试了下,结果为1),因为没有设置全局标志re = /[A-Z]/g;arr = re.exec(str);alert(re.lastIndex);//1arr = re.exec(str);alert(re.lastIndex);//7
当匹配失败(后面没有匹配),或lastIndex值大于字符串长度时,再执行exec等方法会将lastIndex设为0(开始位置)
- var re = /[A-Z]/;
- var str = "Hello,World!!!";
- re.lastIndex = 120;
- var arr = re.exec(str);
- alert(re.lastIndex);//0
var re = /[A-Z]/;var str = "Hello,World!!!";re.lastIndex = 120;var arr = re.exec(str);alert(re.lastIndex);//0
RegExp对象的静态属性
- //input 最后用于匹配的字符串(传递给test,exec方法的字符串)
- var re = /[A-Z]/;
- var str = "Hello,World!!!";
- var arr = re.exec(str);
- alert(RegExp.input);//Hello,World!!!
- re.exec("tempstr");
- alert(RegExp.input);//仍然是Hello,World!!!,因为tempstr不匹配
- //lastMatch 最后匹配的字符
- re = /[a-z]/g;
- str = "hi";
- re.test(str);
- alert(RegExp.lastMatch);//h
- re.test(str);
- alert(RegExp["$&"]);//i ,$&是lastMatch的短名字,但由于它不是合法变量名,所以要。。
- //lastParen 最后匹配的分组
- re = /[a-z](\d+)/gi;
- str = "Class1 Class2 Class3";
- re.test(str);
- alert(RegExp.lastParen);//1
- re.test(str);
- alert(RegExp["$+"]);//2
- //leftContext 返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符
- //rigthContext 返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符
- re = /[A-Z]/g;
- str = "123ABC456";
- re.test(str);
- alert(RegExp.leftContext);//123
- alert(RegExp.rightContext);//BC456
- re.test(str);
- alert(RegExp["$`"]);//123A
- alert(RegExp["$'"]);//C456
//input 最后用于匹配的字符串(传递给test,exec方法的字符串)var re = /[A-Z]/;var str = "Hello,World!!!";var arr = re.exec(str);alert(RegExp.input);//Hello,World!!!re.exec("tempstr");alert(RegExp.input);//仍然是Hello,World!!!,因为tempstr不匹配//lastMatch 最后匹配的字符re = /[a-z]/g;str = "hi";re.test(str);alert(RegExp.lastMatch);//hre.test(str);alert(RegExp["$&"]);//i ,$&是lastMatch的短名字,但由于它不是合法变量名,所以要。。//lastParen 最后匹配的分组re = /[a-z](\d+)/gi;str = "Class1 Class2 Class3";re.test(str);alert(RegExp.lastParen);//1re.test(str);alert(RegExp["$+"]);//2//leftContext 返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符//rigthContext 返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符re = /[A-Z]/g;str = "123ABC456";re.test(str);alert(RegExp.leftContext);//123alert(RegExp.rightContext);//BC456re.test(str);alert(RegExp["$`"]);//123Aalert(RegExp["$'"]);//C456
multiline属性返回正则表达式是否使用多行模式,这个属性不针对某个正则表达式实例,而是针对所有正则表达式,并且这个属性可写.(IE与Opera不支持这个属性)
- alert(RegExp.multiline);
- //因为IE,Opera不支持这个属性,所以最好还是单独指定
- var re = /\w+/m;
- alert(re.multiline);
- alert(RegExp["$*"]);//RegExp对象的静态属性不会因为给RegExp某个对象实例指定了m标志而改变
- RegExp.multiline = true;//这将打开所有正则表达式实例的多行匹配模式
- alert(RegExp.multiline);
alert(RegExp.multiline);//因为IE,Opera不支持这个属性,所以最好还是单独指定var re = /\w+/m;alert(re.multiline);alert(RegExp["$*"]);//RegExp对象的静态属性不会因为给RegExp某个对象实例指定了m标志而改变RegExp.multiline = true;//这将打开所有正则表达式实例的多行匹配模式alert(RegExp.multiline);
使用元字符注意事项:元字符是正则表达式的一部分,当我们要匹配正则表达式本身时,必须对这些元字符转义.下面是正则表达式用到的所有元字符
( [ { \ ^ $ | ) ? * + .
- var str = "?";
- var re = /?/;
- alert(re.test(str));//出错,因为?是元字符,必须转义
- re = /\?/;
- alert(re.test(str));//true
var str = "?";var re = /?/;alert(re.test(str));//出错,因为?是元字符,必须转义re = /\?/;alert(re.test(str));//true
使用RegExp构造函数与使用正则表达式字面量创建正则表达式注意点
- var str = "\?";
- alert(str);//只会输出?
- var re = /\?/;//将匹配?
- alert(re.test(str));//true
- re = new RegExp("\?");//出错,因为这相当于re = /\?/
- re = new RegExp("\\?");//正确,将匹配?
- alert(re.test(str));//true
var str = "\?";alert(str);//只会输出?var re = /\?/;//将匹配?alert(re.test(str));//truere = new RegExp("\?");//出错,因为这相当于re = /\?/re = new RegExp("\\?");//正确,将匹配?alert(re.test(str));//true
既然双重转义这么不友好,所以还是用正则表达式字面量的声明方式
如何在正则表达式中使用特殊字符?
- //ASCII方式用十六进制数来表示特殊字符
- var re = /^\x43\x4A$/;//将匹配CJ
- alert(re.test("CJ"));//true
- //也可使用八进制方式
- re = /^\103\112$/;//将匹配CJ
- alert(re.test("CJ"));//true
- //还可以使用Unicode编码
- re =/^\u0043\u004A$/;//使用 Unicode,必须使用u开头,接着是字符编码的四位16进制表现形式
- alert(re.test("CJ"));
//ASCII方式用十六进制数来表示特殊字符var re = /^\x43\x4A$/;//将匹配CJalert(re.test("CJ"));//true//也可使用八进制方式re = /^\103\112$/;//将匹配CJalert(re.test("CJ"));//true//还可以使用Unicode编码re =/^\u0043\u004A$/;//使用 Unicode,必须使用u开头,接着是字符编码的四位16进制表现形式alert(re.test("CJ"));
另处,还有一些其它的预定义特殊字符,如下表所示:
字符 描述
\n 换行符
\r 回车符
\t 制表符
\f 换页符(Tab)
\cX 与X对应的控制字符
\b 退格符(BackSpace)
\v 垂直制表符
\0 空字符("")
字符类 ---〉简单类,反向类,范围类,组合类,预定义类
- //简单类
- var re = /[abc123]/;//将匹配abc123这6个字符中一个
- //负向类
- re = /[^abc]/;//将匹配除abc之外的一个字符
- //范围类
- re = /[a-b]/;//将匹配小写a-b 26个字母
- re = /[^0-9]/;//将匹配除0-9 10个字符之处的一个字符
- //组合类
- re = /[a-b0-9A-Z_]/;//将匹配字母,数字和下划线
//简单类var re = /[abc123]/;//将匹配abc123这6个字符中一个//负向类re = /[^abc]/;//将匹配除abc之外的一个字符//范围类re = /[a-b]/;//将匹配小写a-b 26个字母re = /[^0-9]/;//将匹配除0-9 10个字符之处的一个字符//组合类re = /[a-b0-9A-Z_]/;//将匹配字母,数字和下划线
下面是正则表达式中的预定义类
代码 等同于 匹配
. IE下[^\n],其它[^\n\r] 匹配除换行符之外的任何一个字符
\d [0-9] 匹配数字
\D [^0-9] 匹配非数字字符
\s [ \n\r\t\f\x0B] 匹配一个空白字符
\S [^ \n\r\t\f\x0B] 匹配一个非空白字符
\w [a-zA-Z0-9_] 匹配字母数字和下划线
\W [^a-zA-Z0-9_] 匹配除字母数字下划线之外的字符
量词(下表量词单个出现时皆是贪婪量词)
代码 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
贪婪量词与惰性量词
•用贪婪量词进行匹配时,它首先会将整会字符串当成一个匹配,如果匹配的话就退出,如果不匹配,就截去最后一个字符进行匹配,如果不匹配,继续将最后一个字符截去进行匹配,直到有匹配为止。直到现在我们遇到的量词都是贪婪量词
•用惰性量词进行匹配时,它首先将第一个字符当成一个匹配,如果成功则退出,如果失败,则测试前两个字符,依些增加,直到遇到合适的匹配为止
惰性量词仅仅在贪婪量词后面加个"?"而已,如"a+"是贪婪匹配的,"a+?"则是惰性的
- var str = "abc";
- var re = /\w+/;//将匹配abc
- re = /\w+?/;//将匹配a
var str = "abc";var re = /\w+/;//将匹配abcre = /\w+?/;//将匹配a
多行模式
- var re = /[a-z]$/;
- var str = "ab\ncdef";
- alert(str.replace(re,"#"));//ab\ncde#
- re =/[a-z]$/m;
- alert(str.replace(re,"#"));//a#\ncde#
var re = /[a-z]$/;var str = "ab\ncdef";alert(str.replace(re,"#"));//ab\ncde#re =/[a-z]$/m;alert(str.replace(re,"#"));//a#\ncde#
分组与非捕获性分组
- re = /abc{2}/;//将匹配abcc
- re = /(abc){2}/;//将匹配abcabc
- //上面的分组都是捕获性分组
- str = "abcabc ###";
- arr = re.exec(str);
- alert(arr[1]);//abc
- //非捕获性分组 (?:)
- re = /(?:abc){2}/;
- arr = re.exec(str);
- alert(arr[1]);//undefined
re = /abc{2}/;//将匹配abccre = /(abc){2}/;//将匹配abcabc//上面的分组都是捕获性分组str = "abcabc ###";arr = re.exec(str);alert(arr[1]);//abc//非捕获性分组 (?:)re = /(?:abc){2}/;arr = re.exec(str);alert(arr[1]);//undefined
候选(也就是所说的“或”)
- re = /^a|bc$/;//将匹配开始位置的a或结束位置的bc
- str ="add";
- alert(re.test(str));//true
- re = /^(a|bc)$/;//将匹配a或bc
- str ="bc";
- alert(re.test(str));//true
re = /^a|bc$/;//将匹配开始位置的a或结束位置的bcstr ="add";alert(re.test(str));//truere = /^(a|bc)$/;//将匹配a或bcstr ="bc";alert(re.test(str));//true
当包含分组的正则表达式进行过test,match,search这些方法之后,每个分组都被放在一个特殊的地方以备将来使用,这些存储是分组中的特殊值,我们称之为反向引用
- var re = /(A?(B?(C?)))/;
- /*上面的正则表达式将依次产生三个分组
- (A?(B?(C?))) 最外面的
- (B?(C?))
- (C?)*/
- str = "ABC";
- re.test(str);//反向引用被存储在RegExp对象的静态属性$1—$9中
- alert(RegExp.$1+"\n"+RegExp.$2+"\n"+RegExp.$3);
- //反向引用也可以在正则表达式中使用\1 ,\2...这类的形式使用
- re = /\d+(\D)\d+\1\d+/;
- str = "2008-1-1";
- alert(re.test(str));//true
- str = "2008-4_3";
- alert(re.test(str));//false
var re = /(A?(B?(C?)))/;/*上面的正则表达式将依次产生三个分组(A?(B?(C?))) 最外面的(B?(C?))(C?)*/str = "ABC";re.test(str);//反向引用被存储在RegExp对象的静态属性$1—$9中alert(RegExp.$1+"\n"+RegExp.$2+"\n"+RegExp.$3);//反向引用也可以在正则表达式中使用\1 ,\2...这类的形式使用re = /\d+(\D)\d+\1\d+/;str = "2008-1-1";alert(re.test(str));//truestr = "2008-4_3";alert(re.test(str));//false
使用反向引用可以要求字符串中某几个位置上的字符必须相同.另外,在replace这类方法中可用特殊字符序列来表示反向引用
- re = /(\d)\s(\d)/;
- str = "1234 5678";
- alert(str.replace(re,"$2 $1"));//在这个里面$1表示第一个分组1234,$2则表示5678
re = /(\d)\s(\d)/;str = "1234 5678";alert(str.replace(re,"$2 $1"));//在这个里面$1表示第一个分组1234,$2则表示5678
其它——〉正向前瞻,用来捕获出现在特定字符之前的字符,只有当字符后面跟着某个特定字符才去捕获它。与正向前瞻对应的有负向前瞻,它用匹配只有当字符后面不跟着某个特定字符时才去匹配它。在执行前瞻和负向前瞻之类的运算时,正则表达式引擎会留意字符串后面的部分,然而却不移动index
- //正向前瞻
- re = /([a-z]+(?=\d))/i;
- //我们要匹配后面跟一个数字的单词,然后将单词返回,而不要返回数字
- str = "abc every1 abc";
- alert(re.test(str));//true
- alert(RegExp.$1);//every
- alert(re.lastIndex);//使用前瞻的好处是,前瞻的内容(?=\d)并不会当成一次匹配,下次匹配仍从它开始
- //负向前瞻(?!)
- re = /([a-z](?!\d))/;i
- //将匹配后面不包含数字的字母,并且不会返回(?!\d)中的内容
- str = "abc1 one";
- alert(re.test(str));
- alert(RegExp.$1);//one
//正向前瞻re = /([a-z]+(?=\d))/i;//我们要匹配后面跟一个数字的单词,然后将单词返回,而不要返回数字str = "abc every1 abc";alert(re.test(str));//truealert(RegExp.$1);//everyalert(re.lastIndex);//使用前瞻的好处是,前瞻的内容(?=\d)并不会当成一次匹配,下次匹配仍从它开始//负向前瞻(?!)re = /([a-z](?!\d))/;i//将匹配后面不包含数字的字母,并且不会返回(?!\d)中的内容str = "abc1 one";alert(re.test(str));alert(RegExp.$1);//one
构建一个验证电子邮箱地址有效性的正则表达式。电子邮箱地址有效性要求(我们姑且这样定义):用户名只能包含字母数字以及下划线,最少一位,最多25位,用户名后面紧跟@,后面是域名,域名名称要求只能包含字母数字和减号(-),并且不能以减号开头或结尾,然后后面是域名后缀(可以有多个),域名后缀必须是点号连上2-4位英文字母
- var re = /^\w{1,15}(?:@(?!-))(?:(?:[a-z0-9-]*)(?:[a-z0-9](?!-))(?:\.(?!-)))+[a-z]{2,4}$/;
var re = /^\w{1,15}(?:@(?!-))(?:(?:[a-z0-9-]*)(?:[a-z0-9](?!-))(?:\.(?!-)))+[a-z]{2,4}$/;
JS基础学习笔记整理
JavaScript是一种基于对象的脚本编程语言,是浏览器上的程序语言。当web容器输出内容到浏览器时,这个内容是包含js源代码的,此时,JavaScript可以操作浏览器上的一切内容,在浏览器上提供用户交互,页面美化,增加页面的智能性。
JavaScript是一种基于对象的语言,通过 JavaScript代码来操作对象――访问或者设置对象的属性,编写对象的特定的事件(方法)代码。
JavaScript中的对象是由属性(properties)和方法(methods)两个基本的元素的构成的。前者是对象在实施其所需要行为的过程中,实现信息的装载单位,从而与变量相关联;后者是指对象能够按照设计者的意图而被执行,从而与特定的函数相联。
对象从哪里来?JavaScript可以操作的对象有下列三个来源:
1.浏览器环境和 HTML标签语句所构成的现成对象(链接、图像、插件、HTML表单元素、浏览器细节等);
2.通过 JavaScript的内置类所创建的对象,比如 Data(日期)和 Number(数值);
3.通过 JavaScript编程,用户自己创建的对象;
1.JavaScript 代码的加入
a. JavaScript的代码的加入,通过在Web页中直接写入:
<Script Language="JavaScript">
//JavaScript语言代码;
//JavaScript 语言代码;
//…
</Script>
通过标识<Script> </Script>指明其中包含的是Script脚本代码;
通过Language ="JavaScript"说明标识中使用的语言,这里是JavaScript语言;
可将<Script></Script>标识放入<Head>...</Head>或<Body>...</Body>之间。将 JavaScript标识放置<Head>...</Head>在头部之间,使之在页面文档主体和其余部分代码之前装载。尤其是一些函数的代码,建议读者将这些代码放在<Head>... </Head>在头部之间。
也可以将 JavaScript标识放置在<Body>... </Body>主体之间以实现某些部分动态地创建文档
b. onclick=’javascript:函数名称()’ 直接编写代码或调用代码
c. 使用库函数<script src="指定的Js 文件位置"></script>
把一些 JavaScript代码(尤其是用户自己编写的对象的类文件)组织成可以反复使用的库,具有下列好处:
◆ 减少错误,减少 Web页面的内容。JavaScript库经过严格测试后,可以放心的反复调用,相对于通过拷贝和粘贴把 JavaScript函数插入到每个想要调用它的HTML文件而言。同时也使 HTML文件看起来清楚易读。
◆ 减少网络流量,提高响应速度。当一个 JavaScript库的第一次下载到内存,无论多少页引用该库,浏览器都能访问它。不需要再次下载。
考虑JavaScript 脚本的位置,要注意下列两点:
◆Web 内容在浏览器中是从上到下的顺序解释的。放在 HTML 的<head></head>之间脚本比插入Web 的<body></body>的脚本先处理。比较好的做法是将包含所有预定义函数的脚本放在 Web的<head></head>之间。这样,浏览器在前面遇到这些函数,确保 Web 的<body></body>中的语句能够识别这些函数。同样的道理,在一些网页下载到浏览器中,就会执行的脚本(比如Web页的onload 事件关联的脚本代码),如果这些脚本要访问 HTML 标签所定义的对象,那么要确保这些对象先于脚本执行,否则会出现“对象不存在”的错误。建议设置 IE的浏览器的高级属性中启用脚本调试,可以发现错误存在的地方。
◆ 应用外部脚本库
<script language="JavaScript"src="menu_data.js"></script>,浏览器会在该HTML文件所在的目录下查找 menu_data.js 文件,如果把js 文件存放在别的目录中,则SRC 属性值必须反映出那个目录,也就是必须确保该HTML 文件能够找到 js 文件。
JS中 常见的 陷阱 转
区分大小写:变量名、属性和方法全部都区分大小写
不匹配的引号、圆括号或花括号将抛出错误
条件语句:3个常见陷阱
换行:一直用分号结束语句来避免常见的换行问题
标点法:在对象声明的尾部逗号将导致出错
HTML id 冲突
变量作用域:全局变量对局部变量
函数重载:当重载不存在时,覆盖函数
区分string.replace()函数不是全局的
parseInt应该包含两个参数
“this”和绑定问题
为参数设置默认值,以免你遗漏它们
for each循环是用于对象而不是数组
switch语句需要点技巧
总是在检查undefined前检查null
时间处理陷阱
1.区分大小写
变量名和函数名都是区分大小写的。就像配错的引号一样,这些大家都知道。但是,由于错误是不作声的,所以这是一个提醒。为自己选择一个命名规则,并坚持它。而且,记住JavaScript中的原生函数和CSS属性都是骆驼拼写(camelCase)。
getElementById(’myId’) != getElementByID(’myId’); //它应该是“Id”而不是“ID”getElementById(’myId‘) != getElementById(’myID‘); // “Id”也不等于“ID”document.getElementById('myId').style.Color; //返回 "undefined"2.不匹配的引号、圆括号或花括号
避免陷入不匹配的引号、圆括号或花括号陷阱的最好方式是编码时一直同时写出打开和关闭这两个元素符号,然后在其中间加入代码。开始:
var myString = ""; //在输入字符串值之前写入这对引号function myFunction(){ if(){//关闭每个打开的括弧 }}//统计所有的左括号和右括号数量,并且确保它们相等alert(parseInt(var1)*(parseInt(var2)+parseInt(var3))); //关闭每个打开的圆括号每当你打开一个元素,请关闭它。 当你添加了关闭圆括号后,你再把函数的参数放进圆括号中。 如果有一串圆括号,统计所有打开的圆括号和所有关闭的圆括号,并且确保这两个数字相等。
3.条件语句(3个陷阱)
所有的条件语句都必须位于圆括号中。执行语句主体不管是一句还是多句都强烈建议用花括号包围起来,这样能避免很多因修改或嵌套而产生的潜在错误。
if(var1 == var2){//statement}
不要犯无意地使用赋值运算符的错误:把第二个参数的值赋给第一个参数。因为它是一个逻辑问题,它将一直返回true且不会报错。
if(var1 = var2){} // 返回true。把var2赋值给var1
JavaScript是弱类型,除了在switch语句中。当JavaScript在case比较时,它是非弱类型。
4. var myVar = 5;
5. if(myVar == '5'){ //返回true,因为JavaScript是弱类型
6. alert("hi"); //这个alert将执行,因为JavaScript通常不在意数据类型
7. }
8. switch(myVar){
9. case '5':
10. alert("hi"); //这个alert将不会执行,因为数据类型不匹配
11.}
4.换行
当心JavaScript中的硬换行。换行被解释为表示行结束的分号。即使在字符串中,如果在引号中包括了一个硬换行,那么你会得到一个解析错误(未结束的字符串)。
var bad = '<ul id="myId"> <li>some text</li> <li>more text</li> </ul>'; // 未结束的字符串错误 var good = '<ul id="myId">' + ‘<li>some text</li>‘ + ‘<li>more text</li>‘ +‘</ul>’; // 正确前面讨论过的换行被解释为分号的规则并不适用于控制结构这种情况:条件语句关闭圆括号后的换行并不是给其一个分号。
一直使用分号和圆括号,那么你不会因换行而出错,你的代码易于阅读,且除了那些不使用分号的怪异源码外你会少一些顾虑:所以当移动代码且最终导致两个语句在一行时,你无需担心第一个语句是否正确结束。
5.多余的逗号
在任何JavaScript对象定义中,最后一个属性决不能以一个逗号结尾。Firefox不会出错,而IE会报语法错误。
var theObj = { city : "Boston", state : "MA",//IE6和IE7中有“缺少标识符、字符串或数字”的错误,IE8 beta2修正了它 }6.HTML id 冲突
JavaScript DOM绑定(JavaScript DOM bindings)允许通过HTML id索引。在JavaScript中函数和属性共享同一个名字空间。所以,当在HTML中的一个id和函数或属性有相同的名字时,你会得到难以跟踪的逻辑错误。然而这更多是一个CSS最佳实践的问题,当你不能解决你的JavaScript问题时,想起它是很重要的。
<ul><li id="length">1</li><li id="thisLength">2</li><li id="thatLength">3</li></ul><script>var listitems = document.getElementsByTagName('li');var liCount = listitems.length; //IE下返回的是<li id="length">1</li>这个节点而不是所有<li的数量 var thisLength = document.getElementById('thisLength'); thatLength = document.getElementById('thatLength'); //IE下会出现“对象不支持此属性和方法”的错误,IE8 beta2下首次加载页面会出错,刷新页面则不会 //在IE中thisLength和thatLength直接表示以其为id值的DOM节点, //所以赋值时会出错,当有var声明时,IE会把其当着变量,这个时候就正常了。</script>如果你要标记(X)HTML,绝不要使用JavaScript方法或属性名作为id的值。并且,当你写JavaScript时,避免使用(X)HTML中的id值作为变量名。
7.变量作用域
JavaScript中的许多问题都来自于变量作用域:要么认为局部变量是全局的,要么用函数中的局部变量覆盖了全局变量。为了避免这些问题,最佳方案是根本没有任何全局变量。但是,如果你有一堆,那么你应该知道这些陷阱。
不用var关键字声明的变量是全局的。记住使用var关键字声明变量,防止变量具有全局作用域。在下面例子中,在函数中声明的变量具有全局变量,因为没有使用var关键字声明:
anonymousFuntion1 = function(){ globalvar= 'global scope'; //全局声明,因为“var”遗漏了 return globalvar;}();alert(globalvar); //弹出“global scope”,因为函数中的变量是全局声明 anonymousFuntion2 = function(){ var localvar = 'local scope'; //使用“var”局部声明 return localvar;}();alert(localvar); //错误 “localvar未定义”。没有全局定义localvar作为参数引进到函数的变量名是局部的。如果参数名也是一个全局变量的名字,像参数变量一样有局部作用域,这没有冲突。如果你想在函数中改变一个全局变量,这个函数有一个参数复制于这个全局变量名,记住所有全局变量都是window对象的属性。
var myscope = "global";function showScope(myscope){ return myscope; //局部作用域,即使有一个相同名字的全局变量}alert(showScope('local')); function globalScope(myscope){ myscope = window.myscope; //全局作用域 return myscope;}alert(globalScope(’local’));你甚至可以在循环中声明变量:
for(var i = 0; i < myarray.length; i++){}8.覆盖函数/重载函数
当你不止一次的声明一个函数时,这个函数的最后一次声明将覆盖掉该函数的所有前面版本且不会抛出任何错误或警告。这不同于其他的编程语言,像Java,你能用相同的名字有多重函数,只要它们有不同的参数:调用函数重载。在JavaScript中没有重载。这使得不能在代码中使用JavaScript核心部分的名字极其重要。也要当心包含的多个JavaScript文件,像一个包含的脚本文件可能覆盖另一个脚本文件中的函数。请使用匿名函数和名字空间。
(function(){ // creation of my namespace 创建我的名字空间 if(!window.MYNAMESPACE) { window['MYNAMESPACE'] = {}; } //如果名字空间不存在,就创建它 //这个函数仅能在匿名函数中访问function myFunction(var1, var2){ //内部的函数代码在这儿 } // 把内部函数连接到名字空间上,使它通过使用名字空间能访问匿名函数的外面 window['MYNAMESPACE']['myFunction'] = myFunction;})(); // 圆括号 = 立即执行// 包含所有代码的圆括号使函数匿名这个例子正式为了实现解决上一个陷阱“变量作用域”的最佳方案。匿名函数详细内容请看《Javascript的匿名函数》。YUI整个库只有YAHOO和YAHOO_config两个全局变量,它正是大量应用匿名函数和命名空间的方法来实现,具体请看《Javascript的一种模块模式》。
9.字符串替换
一个常见错误是假设字符串替换方法的行为会对所有可能匹配都产生影响。实际上,JavaScript字符串替换只改变了第一次发生的地方。为了替换所有发生的地方,你需要设置全局标识。同时需要记住String.replace()的第一个参数是一个正则表达式。
var myString = "this is my string";myString = myString.replace("","%20"); // "this%20is my string"myString = myString.replace(/ /,"%20"); // "this%20is my string"myString = myString.replace(/ /g,"%20"); // "this%20is%20my%20string"10.parseInt
在JavaScript得到整数的最常见错误是假设parseInt返回的整数是基于10进制的。别忘记第二个参数基数,它能是从2到36之间的任何值。为了确保你不会弄错,请一直包含第二个参数。
parseInt('09/10/08'); //0parseInt(‘09/10/08’,10); //9, 它最可能是你想从一个日期中得到的值如果parseInt没有提供第二个参数,则前缀为 ‘0x’ 的字符串被当作十六进制,前缀为 ‘0′ 的字符串被当作八进制。所有其它字符串都被当作是十进制的。如果 numString 的前缀不能解释为整数,则返回 NaN(而不是数字)。
parseInt("10"); //返回 10 parseInt("19",10); //返回 19 (10+9)parseInt("11",2); //返回 3 (10+9)parseInt("17",8); //返回 15 (8+7)parseInt("1f",16); //返回 31 (16+15)parseInt("010"); //未定:返回8第二个参数表示进制十进制 二进制 八进制 十六进制
11. ‘this’
另一个常见的错误是忘记使用“this”。在JavaScript对象中定义的函数访问这个对象的属性,但没有使用引用标识符“this”。例如,下面是错误的:
function myFunction() { var myObject = { objProperty: "some text", objMethod: function() { alert(objProperty); } }; myObject.objMethod();} function myFunction() {var myObject = { objProperty: "some text", objMethod: function() { alert(this.objProperty); } }; myObject.objMethod();}有一篇AList Apart文章用通俗易懂的英文表达了this绑定的问题。
对this使用最大的陷阱是this在使用过程中其引用会发生改变:
<input type="button" value="Gotcha!" id="MyButton"><script>var MyObject = function () { this.alertMessage = "Javascript rules"; this.ClickHandler = function() { alert(this.alertMessage ); //返回结果不是”JavaScript rules”,执行MyObject.ClickHandler时, //this的引用实际上指向的是document.getElementById("theText")的引用 }}();document.getElementById(”theText”).onclick = MyObject.ClickHandler</script>其解决方案是:
var MyObject = function () { var self = this; this.alertMessage = “Javascript rules”; this.OnClick = function() { alert(self.value); }}();类似问题的更多细节和解决方案请看《JavaScript作用域的问题》。
12. 遗漏的参数
当给函数增加一个参数时,一个常见的错误是忘记更新这个函数的所有调用。如果你需要在已经被调用的函数中增加一个参数来处理一个特殊情况下的调用,请给这个函数中的这个参数设置默认值,以防万一在众多脚本中的众多调用中的一个忘记更新。
function addressFunction(address, city, state, country){country = country || “US”; //如果没有传入country,假设 “US” span>//剩下代码}你也能通过获取arguments来解决。但是在这篇文章我们的注意力在陷阱上。同时在《Javascript风格要素(2)》也介绍了||巧妙应用。
13. for关键字
在JavaScript中关键字for有两种使用方式,一个是for语句,一个是for/in语句。for/in语句将遍历所有的对象属性(attribute),包括方法和属性(property)。决不能使用for/in来遍历数组:仅在当需要遍历对象属性和方法时才使用for/in。
for(var myVar in myObject)语句用一个指定变量无任何规律地遍历对象的所有属性。如果for/in循环的主体删除了一个还没有枚举出的属性,那么该属性就不在枚举。如果循环主体定义了新属性,那么循环是否枚举该属性则是由JavaScript的实现决定。
for(var 1=0; i < myArray.length; i++)语句会遍历完一个数组的所有元素。
为了解决这个问题,大体上你可以对对象使用 for … in,对数组使用for循环:
listItems = document.getElementsByTagName('li');
for (var listitem in listItems){
//这里将遍历这个对象的所有属性和方法,包括原生的方法和属性,但不遍历这个数组:出错了!
}
//因为你要循环的是数组对象,所用for循环
for ( var i = 0; i < listItems.length; i++) {
//这是真正你想要的
}
对象的有些属性以相同的方式标记成只读的、永久的或不可列举的,这些属性for/in无法枚举。实际上,for/in循环
会遍历所有对象的所有可能属性,包括函数和原型中的属性。所有修改原型属性可能对for/in循环带来致命的危害,所以需要采用hasOwnProperty和typeof做一些必要的过滤,最好是用for来代替for/in。
14. switch语句
EstelleWeyl写了一篇switchstatement quirks,其要点是:
没有数据类型转换
一个匹配,所有的表达式都将执行直到后面的break或return语句执行
你可以对一个单独语句块使用多个case从句
15. undefined ≠ null
null是一个对象,undefined是一个属性、方法或变量。存在null是因为对象被定义。如果对象没有被定义,而测试它是否是null,但因为没有被定义,它无法测试到,而且会抛出错误。
if(myObject !== null && typeof(myObject) !== 'undefined') { //如果myObject是undefined,它不能测试是否为null,而且还会抛出错误}if(typeof(myObject) !== 'undefined' && myObject !== null) { //处理myObject的代码}HarishMallipeddi对undefined和null有一个说明。
16. 事件处理陷阱
刚接触事件处理时最常见的写法就是类似:
window.onclick = MyOnClickMethod这种做法不仅非常容易出现后面的window.onclick事件覆盖掉前面的事件,还可能导致大名顶顶的IE内存泄露问题。为了解决类似问题,4年前Simon Willison就写出了很流行的addLoadEvent():
function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = func; }else { window.onload = function() { oldonload(); unc(); } }}addEvent(window,'load',func1,false);addEvent(window,'load',func2,false);addEvent(window,'load',func3,false);当然在JavaScript库盛行的现在,使用封装好的事件处理机制是一个很好的选择,比如在YUI中就可以这样写:
YAHOO.util.Event.addListener(window, "click", MyOnClickMethod);来自:http://dancewithnet.com/2008/10/27/javascript-gotchas/
Figure 3: JavaScript 文档对象模型图
◆ 分析代码行 var Userid =document.forms[0].UserId.value;
该语句的功能是将 Web页面上的名称为 UserId的 Text对象的值赋给一个变量 Userid。JavaScirpt访问HTML上标签所定义的对象,最常常采用的是一种层层限定的逐步收缩法。
在 JavaScript的文档对象模型(DOM)中,窗口(Window)是对象模型的顶端对象,通常来说窗口就是你的浏览器。HTML页面文档是在浏览器的窗口中显示的。目前我们假设页面不包含帧结构,这里假设浏览器窗口中只显示一个 Web页的情景。
浏览器的窗口(Window)有它的属性,比如它显示的页面,窗口(Window)底部的状态条上的文字等等;它也有方法,比如打开和关闭。通常来说,因为窗口在 JavaScript的文档对象模型(DOM)对象层次的顶层,JavaScript就假设 Window已经存在了,你不必去在 JavaScript程序中刻意写上它,也就是说 “window.location”和“location”的作用是相同的。窗口里是 Web页面,它的对象层次从文档(document)开始。可以用 Window.document来引用它,或者就是简单的 document,这同我们在国内邮件通信时,地址一般都不写“中国”。每个窗口只有一个文档(document)的时候
一般情况下,有收集用户输入信息的文档(document)包含至少一个表单(form),但是可以包含多个。可以通过 document.forms[0]来访问第一个表单。当然表单一般都有名称(Name)属性,也可以通过表单的名称来访问,比如:上面的一句 JavaScript也可以写成
var Userid =document.InputForm.UserId.value;
在Microsoft的 IE浏览器环境下,可以不指明表单,还是直接用 all替代(作者建议尽量不要采用这种办法),如:
var Userid =document.all.UserId.value;
表单中当中会包含很多 Input对象,比如单行文本输入框(类型为 Text)、文本区域(类型为TextArea)、普通按钮(类型为 Button)、提交按钮(类型为 Submit)、重置按钮(类型为 Reset)、选择框(类型为 Select)等等。
要访问例子中的用户名称录入的文本框 UserId的 value属性,可以通过
document.InputForm.UserId.value;
如果要将鼠标焦点停留该文本输入框中,可以通过该对象的 focus方法:
document.InputForm.UserId.focus();
比如图 2-2中“调用提交按钮”的 onclick事件所关联的函数的语句为:
document.forms[0].BtnSubmit.click();
含义是:访问到 document(文档)下的forms[0](表单)下的BtnSubmit按钮,调用该按钮的 Click事件。
◆ 分析代码 document.forms[0].reset();
关于表单中的 Submit和 Reset类型的按钮: HTML的表单有个 Action属性,该属性的值为某个页面的地址,当表单提交后,表单当中的用户输入内容将发送给 Action所指定的页面,该页面做相应的处理,比如获得用户的输入,存入到数据库系统中去。
对于表单对象来说,有下列两个方法 submit()和 reset()方法。前者对应表单的提交,后者对应表单内容的复位(初始状态),以便重新录入。图 2中的“重写”按钮所关联的函数的代码document.forms[0].reset();就是调用表单的 Reset()方法;
表单中的 Input对象有两种特别的按钮对象:类型为 Submit的按钮对象和类型为 Reset的按钮对象,点击这种按钮,它的动作就是触发表单的 submit()事件或者reset()事件。在图 2的例子中,我们采用类型为 Button的普通按钮对象来完成这种功能。比如图 2的“重写”按钮如果要用 Reset类型的按钮替代的话,只需要直接<input type="Reset"name="Reset" value="重写">,不需要写它的 Onclick事件代码函数,因为这种按钮的动作默认就是表单 reset()事件。
顺便提一下,尽管我们常常采用逐步收缩的方法来访问 HTML标签所定义的对象。有时候我们也可以采用下列方法:通过对象的 ID或者对象的名称来获得该对象。比如:在图 2中的用户名称的输入框 Text的名称为UserId,它的 ID为 txtUserId,那么可以通过
var UserId=document.getElementById("txtUserId").value;
或者
var UserId =document.getElementByName("UserId").value
来取得该对象的 Value的值。
使用单选钮 (Radio)和多选钮 (Checkbox)的例子:
function Select_check(objName){
varobj=document.getElementsByName(objName);
var selArray = new Array();
for(var i=0;i<obj.length;i++){
if(obj[i].checked){
selArray[i]=obj[i].value;
}
}
return selArray;
}
对于相关成组单选钮和多选钮,在 Web上总是以同名的一组对象出现,在函数中,遍历对象组的每个元素,如果该元素的是否Checked,如果是,则把该元素的值存入到数组selArray中,最后,函数返回值为数组selArray。
3.4.1 字符串对象
创建字符串对象,一般可以通过: varstrTemp =”This is a string”
请看下列检测用户浏览器信息的例子:
function dispBrowser(){
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf("msie 6.0")==-1){
alert("你的浏览器不是 IE6.0的,本网页需要 IE6.0才能得到理想显示效果!");
}
}
简要注释:
如果用户的浏览器为 IE6.0的版本,通过
var userAgent = navigator.userAgent.toLowerCase();
可以得到变量 userAgent的值为“mozilla/4.0 (compatible; msie 6.0;windows nt 5.0; i-navfourf)”,通过toLowercase()方法,将字符串转化为小写字母,有助于下面的判断字符串是否包含“msie 6.0”,不需要考虑大小写的问题。navigator对象是浏览器环境所构成的对象。
检查用户字符串是否是为整数:
if (isNaN(strTemp)) {
alert("包含有非数字字符!");
return false;
}
对这种应用,还有一个办法就是,在用户输入的时候就限制用户只能输入数字字符(“事先预防机制”比“事后审核机制”是否更好一些呢?通过 JavaScript来对用户录入进行有效性验证,对 Web服务器来说,也是“事先预防机制”,防止不符要求,不完整的数据信息提交到服务器端),可以采用下面的 Input对象:
<input type="text" name="PageNum"
onkeypress="var k=event.keyCode; returnk>=48&&k<=57||k==46"
onpaste="return !clipboardData.getData('text').match(/\D/)"
ondragenter="return false"
style="ime-mode:Disabled"
/>
JavaScript onpaste事件,禁止粘贴,如果你想像支付宝的注册页面,整个表单都是禁止粘贴的话可以在body标签上加onpaste=”return false”;oncopy="return false;" oncut="return false;" 防止复制和剪切3.4.2 日期对象
JavaScript提供了特殊的内部对象――Date对象。创建日期类型的对象的方法有:
1。 vard_today = new Date(); 创建一个包含当前时间和日期的 Data对象;
2。通过 vard_time = new Date(2004,2,14,20,30,01) 表示创建一个 d_time的 Data对象,它的值为 2004年2月 14号 20点30分 01秒。其中的有些参数如果省略的话,JavaScript会自动以零值补充。
日期对象的常用方法例举:
getDate() 根据当地时间,返回指定日期的天
getDay() 根据当地时间,返回指定日期的星期几
getHours() 根据当地时间,返回指定日期的小时
getMonth() 根据当地时间,返回指定日期的月份
getMinutes() 根据当地时间,返回指定日期的分钟
getYear() 根据当地时间,返回指定日期的年份
setDate() 根据当地时间,设置日期变量的天
setHours() 根据当地时间,设置日期变量的小时
var isnMonths=newinitArray("1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月")
var isnDays=new initArray("星期日","星期一","星期二","星期三","星期四","星期五","星期六","星期日");
isnMonths[today.getMonth()] getMonth()坐标从零开始
isnDays[today.getDay()] getDay() 坐标星期三返回3,星期日在最前面
函数initArray()用来构造一个数组,该函数使用了JavaScript的 Arguments对象,Arguments对象可以获得一个函数的所有参数集。
★桢结构和框架窗口 (Frame,IFrame)
3.5.1 了解链接的Target属性
<frameset name=framesetnamecols="180,*" FRAMEBORDER=no border="0"
framespacing="0">
<frame name="Directory" src="left.htm"SCROLLING=AUTO
NORESIZE=yes MarginHeight=0 MarginWidth=0
leftMargin=0 target="right">
<frame name="Content" src="right.htm" SCROLLING=AUTO
NORESIZE=yes>
</frameset>
从上面代码可以看出,HTML语句中定义了两个框架窗口,一个名称为 Directory,它对应于文件left.htm,另一个框架窗口为 Content,它对应于文件 right.htm (该文件源代码不包含任何内容,为一张“空白”的 Web页面)。
上图左边的帧 Directory的 Src指向的 Left.htm页面的源文件如下:
<HTML><head>
<STYLE type=text/css>
BODY {FONT: 14px 宋体;}
a {color:#ffffff}
</style>
</head>
<bodybgcolor="#000000"><br>
<a href="Js_1.htm"target="Content">1.JavaScritp概述</a><br>
<ahref="Js_2.htm" target="Content">2.JS对象的简单介绍</a><br>
<ahref="JsTest2.htm" target="Content">3.验证用户输入</a><br>
<inputtype="text" name="DispInfo">
</body>
</HTML>
注释:
在HTML中,链接的HTML标签有Target属性,该属性用来确定该链接的响应的位置。Target属性的有效值可以是当前浏览器显示内容的任何框架窗口(Frame或者 Iframe)的名称,本例子中,表示链接在名称为Content的帧中显示。
3.5.2 由JavaScript,在不同的桢 (窗口 )间访问对象
如果一个浏览器显示内容包含多个(帧)Frame,在不同的(帧)Frame中的Web页如何通过JavaScript访问其他帧中的 Web页的对象呢?
假设右边页面中有个按钮,该按钮onclick的所关联的JavaScript代码为:
top.Directory.document.forms[0].DispInfo.value="测试测试";
实际上,上述内容也是层层限定的逐步收缩法。对于处于帧 Content页面,top代表浏览器的根窗口,该窗口中包含有 Directory和 Content窗口,top.Directory.document表示:浏览器根窗口下的帧 Directory所定义的窗口中的文档。
对于不包含帧或者 Iframe的窗口,我们往往直接通过 document来作为对象访问的顶部层次,这意味着“当前窗口下的当前文档”。当浏览器窗口中包含有帧(或者 Iframe时),而且需要从一个窗口访问另外一个帧所定义的窗口中的对象时,我们就需要在 document之前,来限定究竟是访问哪个框架(Frame或者
IFrame)下的文档。
Iframe比帧结构集更加灵活,我们可以在一个 Web页面的任何位置,加入 Iframe,在标签中设置参数(从设定大小,到指定边框样式等等),通过 SRC的值来指定连接到某个 Web页面。
4.正则表达式和模式匹配
正则表达式描述了字符串的一个模式,可以用来验证用户输入数据的格式。正则表达式可以让用户通过使用一系列的特殊字符构建匹配模式,然后把匹配模式与数据文件、程序输入以及 WEB 页面的表单输入等目标对象进行比较,根据比较对象中是否包含匹配模式,执行相应的程序。
4.1 定义正则表达式
类似于字符串被定义在引号内,正则表达式被定义在一对“/”中间。
varfilter =/m$/
该句创建了一个正则表达式,可以匹配任意以字母 m 结尾的字符串。其中位于“/”定界符之间的部分就是将要在目标对象中进行匹配的模式。用户只要把希望查找匹配对象的模式内容放入“/”定界符之间即可。为了能够使用户更加灵活的定制模式内容,正则表达式提供了专门的“元字符”。所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。
较为常用的元字符包括:“+”,“*”,以及“?”。其中,“+”元字符规定其前导字符必须在目标对象中连续出现一次或多次,“*”元字符规定其前导字符必须在目标对象中出现零次或连续多次,而“?”元字符规定其前导对象必须在目标对象中连续出现零次或一次。
除了元字符之外,用户还可以精确指定模式在匹配对象中出现的频率。例如,
/jim{2,6}/
上述正则表达式规定字符 m 可以在匹配对象中连续出现 2-6 次,因此,上述正则表达式可以同jimmy或jimmmmmy 等字符串相匹配。
对如何使用正则表达式有了初步了解之后,我们来看一下其它几个重要的元字符的使用方式。
\s:用于匹配单个空格符,包括 tab 键和换行符;
\S:用于匹配除单个空格符之外的所有字符;
\d:用于匹配从 0 到 9 的数字;
\w:用于匹配字母,数字或下划线字符;
\W:用于匹配所有与\w 不匹配的字符;
(说明:我们可以把\s 和\S 以及\w 和\W 看作互为逆运算)
除了我们以上所介绍的元字符之外,正则表达式中还具有另外一种较为独特的专用字符,即定位符。定位符用于规定匹配模式在目标对象中的出现位置。
较为常用的定位符包括:“^”, “$”, “\b” 以及 “\B”。其中,“^”定位符规定匹配模式必须出现在目标字符串的开头,“$”定位符规定匹配模式必须出现在目标对象的结尾,\b定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一,而“\B”定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内,即匹配对象既不能作为目标字符串的开头,也不能作为目标字符串的结尾。同样,我们也可以把“^”和“$”以及“\b”和“\B”看作是互为逆运算的两组定位符。
/\bbom/
因为上述正则表达式模式以“\b”定位符开头,所以可以与目标对象中以 “bomb”, 或 “bom”开头的字符串相匹配。
/man\b/
因为上述正则表达式模式以“\b”定位符结尾,所以可以与目标对象中以“human”,“woman”或“man”结尾的字符串相匹配。
4.2 字符类
字符类是括在方括号中的文字字符组合。因此,正则表达式/[xyz]/可以匹配任意包括 x、y、z 中一个字符。在字符类中经常出现下列符号“^”、“-”、“|”符号。如下例子:
/[^A-C]/
上述字符串将会与目标对象中除 A,B,和 C 之外的任何字符相匹配。一般来说,当“^”出现在 “[]”内时就被视做否定运算符;而当“^”位于“[]”之外,或没有“[]”时,则应当被视做定位符。
/Th\*/
上述正则表达式将会与目标对象中的“Th*”而非“The”等相匹配。反斜杠“\”表示转义字符序列,比如“\*”表示字符*,“\n”表示换行。
下列式子表示可以匹配3 个数字或者4 个小写字母:
varfilter =/\d{3}|[a-z]{4}/;
4.2 正则表达式的应用例子
我们可以使用正则表达式的test 或者 search 方法来发现字符中是否符合某个模式。比如:
varResultFlag = forms[0].UserName.value.search(/[a-z]|[A-Z]/);
if(ResultFlag==-1){alert(表单中的UserName 没有包含任何字符!)};
下列为一个检查用户邮件地址格式的例子
<scriptlanguage="Javascript">
<!--
functionvertifyMailAddress(obj){
varemail = obj.email.value;
var pattern =
/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
flag =pattern.test(email);
if(flag){
alert("恭喜!邮件地址输入正确,表单将提交!");return true;
}else{
alert("失败!邮件地址格式不正确!表单不会提交"); return false;
}
}
--></script>
<body>
<formonSubmit="return vertifyMailAddress(this);">
<inputname="email" type="text">
<inputtype="submit">
</form>
</body>
如何动态加载js文件
如果使用ajax开发页面,可能会遇到需要加载很多js文件的情况。每个js文件需要耗费一些重
新连接的时间,所以会导致页面显示过慢的情况。如果采用动态加载js的方式,先把几个重要
的js下到客户端,然后跟据需要再加在相关的js可以提高页面显示的速度和效率。
下面介绍几种动态加载的方法:
1、直接document.write
<script language="javascript">
document.write("<script src='test.js'><//script>");
</script>
2、动态改变已有script的src属性
<script src='' id="s1"></script>
<script language="javascript">
s1.src="test.js"
</script>
3、动态创建script元素
<script>
var oHead = document.getElementsByTagName('HEAD').item(0);
var oScript= document.createElement("script");
oScript.type = "text/javascript";
oScript.src="test.js";
oHead.appendChild( oScript);
</script>
这三种方法都是异步执行的,也就是说,在加载这些脚本的同时,主页面的脚本继续运
行,如果用以上的方法,那下面的代码将得不到预期的效果。
要动态加载的JS脚本:a.js,以下是该文件的内容。
var str = "中国";
alert( "这是a.js中的变量:" + str );
主页面代码:
<script language="JavaScript">
function LoadJS( id, fileUrl )
{
var scriptTag = document.getElementById( id );
var oHead = document.getElementsByTagName('HEAD').item(0);
var oScript= document.createElement("script");
if ( scriptTag ) oHead.removeChild( scriptTag );
oScript.id = id;
oScript.type = "text/javascript";
oScript.src=fileUrl ;
oHead.appendChild( oScript);
}
LoadJS( "a.js" );
alert( "主页面动态加载a.js并取其中的变量:" + str );
</script>
上述代码执行后 a.js 的 alert 执行并弹出消息,
但是 主页面产生了错误,没有弹出对话框。原因是 'str' 未定义,为什么呢?因为主页面在取
str 的时候 a.js 并没有完全加载成功。遇到需要同步执行脚本的时候,可以用下面的第四种方
法。
4、原理:用XMLHTTP取得要脚本的内容,再创建 Script 对象。
注意:a.js必须用UTF8编码保存,要不会出错。因为服务器与XML使用UTF8编码传送数据。
主页面代码:
<script language="JavaScript">
function GetHttpRequest()
{
if ( window.XMLHttpRequest ) // Gecko
return new XMLHttpRequest() ;
else if ( window.ActiveXObject ) // IE
return new ActiveXObject("MsXml2.XmlHttp") ;
}
function AjaxPage(sId, url){
var oXmlHttp = GetHttpRequest() ;
oXmlHttp.OnReadyStateChange = function()
{
if ( oXmlHttp.readyState == 4 )
{
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 )
{
IncludeJS( sId, url, oXmlHttp.responseText );
}
else
{
alert( 'XML request error: ' + oXmlHttp.statusText + ' (' + oXmlHttp.status + ')'
) ;
}
}
}
oXmlHttp.open('GET', url, true);
oXmlHttp.send(null);
}
function IncludeJS(sId, fileUrl, source)
{
if ( ( source != null ) && ( !document.getElementById( sId ) ) ){
var oHead = document.getElementsByTagName('HEAD').item(0);
var oScript = document.createElement( "script" );
oScript.language = "javascript";
oScript.type = "text/javascript";
oScript.id = sId;
oScript.defer = true;
oScript.text = source;
oHead.appendChild( oScript );
}
}
AjaxPage( "scrA", "b.js" );
alert( "主页面动态加载JS脚本。");
alert( "主页面动态加载a.js并取其中的变量:" + str );
</script>
用ajax同步加载JS代码,加载一个还好,两三个或者更多的时候,还是用异步加载比较快。
我使用第三种方法,每个JS我都为其命名,当某个JS加载完成后,则置一个代表其已经加载
完成的标志。
//所有的JS文件
var jsM = {
page : false ,
dhtmlXTree : false ,
photo_tree : false
};
function getJSM(f)
{
var reg = ///(/w+)/./;
jF = f.match(reg);
return jF[jF.length-1];
}
function loadJS(js)
{
id = getJSM(js);
var scriptId = document.getElementById(id);
var head = document.getElementsByTagName('head').item(0);
if(scriptId)
{
//head.removeChild(id);
}
else
{
script = document.createElement('script');
script.src = js;
script.type = 'text/javascript';
script.id = id;
head.appendChild(script);
}
}
//JS时候,判断jsM中,代表其模块的标识是否为true,如果为false,则尚未加载
loadJS("page.js")
- js代码规范和动态加载js
- 动态加载js和css
- 动态加载JS和CSS
- 动态加载js和css
- 动态加载JS和CSS
- 动态加载JS和CSS
- 动态加载js和css
- JS动态加载JS
- js动态加载js
- 动态加载原创js的代码
- 动态加载js文件的jsLoader代码
- JS 动态加载 CSS 文件和JS文件,加载图片
- js代码注释规范
- js代码规范
- js代码规范
- js常用代码规范
- 前端js代码规范
- JS代码规范笔记
- HDU1011Starship Troopers(DP+DFS)深度优先搜索+动态规划
- android Toast
- [Python]用正则表达式进行word Count
- HDU 4279 2012网络赛Number(数论 欧拉函数结论约数个数)
- ORDER BY
- js代码规范和动态加载js
- C 二维数组(指针)动态分配和释放
- POJ1850&&POJ1496
- ios发推广码
- sql*plus 常用命令
- 考研日记2013.10.05
- 一个简单的登陆界面程序
- 关于野指针(迷途指针),空指针,通用指针
- ZOJ:1203 Swordfish