第一章 JavaScript概述

document.write("<h2>Table of Factorials</h2>");
javascript: s=""; for(i in document) s+=i+":"+document[i]+"/n"; alert(s);

第二章 词法结构
在HTML中,事件处理程序性质onclick通常被声明为onClick,但是在JavaScript代码中就只能使用onclick。

在JavaScript中,如果语句放置在不同的行中,就可以省去分号(不是一个好的编程习惯)。例如:
a = 3
b = 4;
JavaScript允许在任意两个记号至间放置换行符,但实际上JavaScript会自动为你插入分号,例如:
break
outerloop;会报错。

保留字和避免使用的其他标识符 p36

第三章 数据类型和值
要调用一个数值直接量的toString()的方法,就必须使用括号,这样才能避免将“.”解释为小数点:var y = (257).toString(0x10);

特殊的字符:isNaN() = NaN; isFinite() = -Infinity,Infinity;
值NaN永远不会与其他值等同,包括它自身。

字符串直接量必须写在一行中,如果将他们放在两行中,可能会将他们截段。如果你必须在字符串直接量中添加一个换行符,可以使用字符序列/n。

JAVAScript 转义字符
序 转义字符  使用说明 
1  /b        后退一格(Backspace) 
2  /f        换页(Form Feed) 
3  /n        换行(New Line) 
4  /r        返回(Carriage Return) 
5  /t        制表(Tab) 
6  /'        单引号 
7  /"        双引号 
8  //        反斜线(Backslash) 
/xXX         有两位十六进制数值指定的Latin-1字符.
/uXXXX       有四位十六进制数值指定的Unicode字符.
/XXX         有一位到三位八进制数指定的Latin-1字符.

JavaScript中的函数是一个真正的数据类型,这一点给语言带来了很大的灵活性。这就意味着函数可以被存储在变量、数组和对象中,而且函数还可以作为参数传递给其他函数,这是非常有用的。

函数直接量:var square = function(x) {return x*x;}
JavaScript中的对象可以作为关联数组使用,例如:image.width可以写成image["width"]
创建对象
var o = new Object();
var now = new Date();
var pattern = new RegExp("//sjava//s","i");
设计使用他的属性:
var point = new object();
point.x = 2.3;
point.y = -1.2;
对象直接量
var point = {x:2.3, y:-1.2};数组可以存放任何一种JavaScript数据类型,包括对其他数组、对象或函数的引用,数组元素不必具有相同内容。
数组的创建与赋值
var a = new Array();
a[0] = 1.2;
a[1] = "JavaScript";
a[2] = true;
a[3] = {x:1, y:3};
或通过构造函数初始化数组: var a = new Array(1.2, "JavaScript", true, {x:1, y:3});
如果只给Array()构造函数传递一个参数,那么该参数指的是数组的长度。数组直接量: var a = [1.2, "JavaScript", true, {x:1,y:3}];
prototype 属性
返回对象类型原型的引用。
objectName.prototype
objectName 参数是对象的名称。 
说明
用 prototype 属性提供对象的类的一组基本功能。 对象的新实例“继承”赋予该对象原型的操作。 
例如,要为 Array 对象添加返回数组中最大元素值的方法。 要完成这一点,声明该函数,将它加入 Array.prototype, 并使用它。 
function array_max( ){
   var i, max = this[0];
   for (i = 1; i < this.length; i++)
   {
   if (max < this[i])
   max = this[i];
   }
   return max;
}
Array.prototype.max = array_max;
var x = new Array(1, 2, 3, 4, 5, 6);
var y = x.max( );
该代码执行后,y 保存数组 x 中的最大值,或说 6。JavaScript不仅支持数字、字符串、和布尔值这些数据类型,还支持Number、String、Boolean包装类。
第四章 变量
如果尝试给一个未用var 声明的变量赋值,JavaScript会隐式声明该变量。但是要注意,隐式声明的变量总是被创建为全局变量。局部变量在整个函数体中都是有定义的,但是在执行var语句之前,它是不会被初始化的。如:
var scope = "global";
function f(){
  alert(scope);  //显示“undefined”,而不是“global”
  var scope = "local";  //变量在此被初始化,但到处都有定义
  alert(scope);    //显示“local”
}

数值、布尔值、null和未定义的值属于基本类型。对象、数组和函数属于引用类型,字符串是使用引用类型的内部功能实现的基本类型。

在程序的顶层代码中(例如,不属于函数的JavaScript代码),你可以使用JavaScript的关键字this来引用这个全局对象。在函数内部,this则有别的用途。在客户端JavaScript中,Window对象代表浏览窗口,它是包含在该窗口中的所有JavaScript代码的全局对象。这个全局对象具有自我引用的window属性,它代替了this属性,可以用来引用这个全局对象。

如果全局变量是特殊的全局对象的属性,那么局部变量(包括函数参数和局部变量)也是一个对象的属性,这个对象被称为调用对象(call object)。

第五章 表达式和运算符

结合性    运算符     运算数类型     所执行的操作
从右到左  new        构造函数调用   创建新对象
从右到左  delete     lvalue         删除一个属性(一元的)的定义,删除成功返回true,否则返回false。
从右到左  typeof     任意           返回数据类型(一元的)
从左到右  instanceof 对象、构造函数 检查对象类型         
从左到右  in         字符串、对象   检查一个属性是否存在  例var point = {x:1, y:1}; var has_x_coord = "x" in point;  //值为true
从左到右  ===        任意           测试等同性
从左到右  !==        任意           测试非等同性
说明:

new,如果函数调用是没有参数,就可以省去括号,如 o = new Object;  o = new Date();
delete,由var语句创建的一个特性或多个特性不能用delete运算符来删除。
typeof如果typeof的运算数是数字、字符串或者布尔值,它返回的结果就是“number”、“string”或“boolean”。对对象(包括Number、String或Boolean对象)、数组和null,它返回的是“object”。对函数运算数它返回的是“function”。如果运算数是未定义的,它将返回“undefined”。
instanceof左边的运算数是一个对象,右边的运算数是对象类的名字  
   var d = new Date(); 
   d instanceof Date  //true   
   d instanceof Object; //true,所有对象都是Object类的实例   
   d instanceof Number;  //false
对于基本类型===和==达到的效果是一样的,对于引用类型(对象、数组和函数)===类似java语言中的equals()函数。第六章 语句
for (variable in object)
      statement
variable应该是一个变量名,声明一个变量的var语句,数组的一个元素或者是对象的一个属性。object是一个对象名,或者计算结果为对象的表达式。throw expression;
expression的值可以是任何类型的。但通常它是一个Error对象或Error子类的一个实例。如:if(x<0) throw new Error("x must not be negative");异常处理,注意和java的不同
try{
}
catch(e){
}
finally{
}

第七章 函数
如果函数不包含return语句,返回给调用者的是undefined,否则返回return后面的表达式值。

因为JavaScript是一种无类型语言,所以你不能给函数的参数指定一个数据类型。而且JavaScript也不会检测传递的数据是不是那个函数所要求的类型。如果参数的数据类型很重要,那么可以用运算符typeof对它进行检测。JavaScript也不会检测传递给它的参数个数是否正确。如果传递的参数比函数需要的个数多,那么多余的值会被忽略掉。如果传递的参数比函数需要的个数少,那么多余的几个参数就会被赋予undefined。这里和java有点不同好像没有函数重载,形参和实参的个数也可以不同。

函数直接量可以出现在任何JavaScript表达式中,但函数定义被限制在顶层全局代码和顶层函数代码中即不能出现在循环和条件语句中。

函数的三种定义方法
function f(x) {return x*x;} //function 语句
var f = new Function("x", "return x*x;"); //Function()构造函数
var f = function(x) {return x*x;};  //函数直接量,调用方式如下var f = (function(x) {return x*x;})(10); 虽然函数直接量创建的是未命名函数,但是它的语法也规定它可以指定函数名,这在编写调用自身的递归函数时非常有用。
var f = function fact(x) {if (x <= 1) return 1; else return x*fact(x-1);};作为数据的函数,函数可以是数据,这意味着能够把函数赋给变量、存储在对象的属性中或存储在数组的元素中、传递给函数,等等。这是和java的不同之处。
function square(x) {return x*x;}
var a = square(4); //a存放数字16
var b = square; //现在b引用的函数和square的作用相同
var c = b(5); //c存放数字25
将函数赋给对象的属性,在这种情况下,我们称函数为方法:
var o = new Object;
o.square = new Function("x", "return x*x");
y = o.square(16);//y等于256var a = new Array(3);
a[0] = function(x) {return x*x;}
a[1] = 20;
a[2] = a[0](a[1]);
下面说明了如何将函数作为参数传递给其他函数,还说明了如何将他们存储在关联数组中。例7-2见附件Arguments对象,arguments是调用对象的一个特殊属性,用来引用Arguments对象。尽管定义JavaScript函数时有固定数目的命名参数,但当调用这个函数时,传递给它的参数数目却可以任意的。arguments[]允许完全的存取那些实际参数值,即使某些参数还没有被命名。arguments具有length属性,表示它所含有的元素个数。这些特性使得可以编写函数,使之能够使用任意数目的实际参数
function max(){
  var m = Number.NEGATIVE_INFINITY;
  for(var i = 0; i < arguments.length; i++)
    if(arguments[i] > m) m=arguments[i];
    return m;
}
var largest = max(1, 10, 100, 2, 3, 1000);callee,除了数组元素,Arguments对象还定义了callee属性,用来引用当前正在执行的函数。这对未命名的函数调用自身非常有用。如:计算阶乘
function(x){
  if(x <= 1) return 1;
  return x* arguments.callee(x-1);
}函数的属性
length属性,length表示函数的形参个数用arguments.callee.length调用,这个属性在函数体的内部和外部都有效,在外部可以直接用函数名.length调用。
定义自己的函数属性,它比定义全局变量更方便:
uniqueInteger.counter = 0;//因为函数声明在执行代码之前处理,所以在函数声明前不能真正实行这个赋值运算。
function uniqueInteger(){
  return uinqueInteger.counter++;
}apply()和call()方法
他们的第一个参数都是要调用的函数的对象,在函数体内这一参数使关键字this的值,call()剩余参数是传递给要调用的函数的值。例如,要把两个数字传递给函数f(),并将它最为对象o的方法调用:
f.call(o,1,2);这与下面的代码类似
o.m = f;
o.m(1,3);
delete o.m;
apply()方法和call()相似,只不过要传递给函数的参数是由数组指定:f.apply(o,[1,2]);

第八章 对象
见附件ObjOriented.js,ObjOriented.htm,ObjOriented.txt

第九章 数组

第十章 使用正则表达式的模式匹配

第十一章 JavaScript的更多主题

第二部分 客户端JavaScript
第十二章 Web浏览器中的JavaScript

客户端的对象层次如下结构:
parent.frames[0].document.forms[0].elements[3].options[2].text,具体见本书图12-1:客户端的对象层次和0级DOM(p214)。

在HTML中嵌入JavaScript
放置在标记对<script>和</script>之间,该标记即可出现在HTML文档的<head>部分,也可出现在<body>部分,且允许有任意多个不重叠的<script>和</script>标记对。尽管在装载和解析
HTML文件的过程中,各个脚本在不同时刻执行,但是这些脚本却是同一个JavaScript程序的组成部分,因为在一个脚本中定义的函数和变量适用于随后出现的同一个文件中所有的脚本。
方置在由<script>标记的src属性指定的外部文件中
放置在事件处理程序中,该事件处理程序由onclick或onmouseover这样的HTML属性指定,可以包含多个JavaScript语句。
作为URL的主体,这个URL使用特殊的javascript:协议

如果用document.write()输出脚本,不能直接输出“</script>”,而需要用表达式"</"+"script>"或转义符"<//script>"。

<script defer>指示浏览器可以继续解析HTML文档,推迟执行脚本,直到他遇到了不能推迟执行的脚本为止。

通常我们想用javascript:URL执行某些不改变当前显示的文档的JavaScript代码。要做到这一点,必须确保URL中的最后一条语句没有返回值。可以这样做:在javascript:URL的结尾使用语句void 0;。

如何写安全的JavaScript代码:
在文档被完全装载之前事件处理程序就有可能被调用这一事实有两点含义。首先,如果事件处理程序要调用一个函数,那么必须确保在处理程序调用这个函数之前,该函数就已经被定义了。要做到这一点,一个方法是在HTML文档的<head>部分定义所有函数。由于定义事件处理程序的所有对象自身都是在<body>部分定义的,因此就能确保定义在调用事件处理程序之前。
其次,必须确保事件处理程序不会操作还没有创建和解析的HTML对象。
    解决这一问题的策略是在定义网页用户界面时,采用一种只允许事件处理程序引用前面定义的对象的方式。例如,假如定义了一个表单,其中只有Submit按钮和Reset按钮使用事件处理程序,那么只需要将这些按钮放在表单底部即可。
    还有一种解决方法是在操作一个对象之前检测它的存在性。如果不存在则抛出一个异常,使用try/catch语句捕捉这个异常。
    还可以使用另外一种方法,在一个HTML文件的<body>标记或<frameset>标记中定义onload事件,当文档或框架设置完全被装载进来时就会调用它。可以在onload事件处理程序中设置一个标志。如

<body οnlοad="window.fullyLoaded = true;">
  <form>
    <input type="button" value="Do It!" οnclick="if (window.fullyLoaded) doit();">
  </form>
</body>

在使用多框架时要格外注意,各个框架的onload事件处理程序的调用顺序不能确定,只是父框架的处理程序在所有子框架的处理程序之后调用。

第十三章 窗口和框架

Window对象和变量的生命周期
一个新文档被装载的窗口或框架中时,那个窗口和框架的Window对象会被恢复为它的默认状态,即由前一个文档中的脚本定义的所有属性和函数都将被删除,所有被改变或覆盖了的标准系统属性都会被恢复。只要浏览器的顶级窗口存在,那么代表它的Window对象就会一直存在。无论这个窗口装载和卸载了多少页面。
代表一个框架的Window对象仍然有效,只要那个框架仍然存在于包含它的框架或窗口中。这意味着,无论Window对象代表的是顶级窗口还是框架,他的存在都是相当持久的。Window对象的生存期可能比它包含和显示的网页长,也可能比它显示的网页所包含的脚本长。

多窗口和多框架
Window对象的open()方法返回代表新创建的窗口的Window对象。而且这个新窗口具有opener属性,该属性可以打开它的原始窗口。这样,两个窗口就可以互相引用,框架也是一样。一个窗口中的任何框架都可以使用Window对象的属性frames,parent和top属性来引用其他的框架。如图13-4(p253)。

第十四章 Document对象

在JavaScript中,可以直接把函数赋予事件处理程序属性,如:document.myform.onsubmit = validateform;注意,函数名后没有括号,这是因为此处我们不想调用函数,只想把一个引用赋予它。

使用document.write(),只能在当前文档正在解析时使用write()方法向其输出HTML代码。简而言之,就是只能在标记<script>中调用方法document.write()。如果是从一个事件处理程序中调用,那么结果将会覆盖当前文档,而不是将文本添加到其中。

创建全新文档

<script>
//开始一个新文档,擦掉frames[0]中已有的内容,该语句可选
parent.frames[0].document.open();
//给新文档添加内容
parent.frames[0].document.write("<hr>hello from your sibling frame!<hr>");
//添加完毕后,关闭该文档,该语句必须
parent.frames[0].document.close();
</script>

除了HTML文本之外,Web浏览器还可以显示很多其他格式的数据,使用方法是给open()传递一个参数,指定想要使用的MIME类型。如document.open("text/plain");

Document对象的fgColor属性,linkColor属性,alinkColor属性和vlinkColor属性虽然是可读写的,但是只能在解析<body>标记之前设置它们。可以在文档的<head>部分使用JavaScript代码对它们进行动态设置,也可以将它们作为标记<body>的性质进行静态设置。除此之外,不能在别的地方设置这些属性。而bgColor属性可以随时进行设置。

referrer的小技巧,可以使对页面的未授权链接不能进行正确操作。例:

<script>
//如果从外部站点链接,首先去主页
if(document.referrer == "" || document.referrer.indexOf("mysite.com") == -1)
  window.location = "http://home.mysite.com";
<script>

第十五章 表单和表单元素
在事件处理程序的代码中,关键字this引用触发该事件的文档元素。表单元素的事件处理程序可以用this.form引用form对象。进一步来说,这意味着表单元素的事件处理程序可以用this.form.x引用名为x的兄弟表单元素

Button是最常用的表单元素之一,因为它给用户触发脚本的动作提供了一种清晰可见的方法。Button对象没有自己默认的行为,除非它具有onclic(或其他)事件处理程序,否则它在表单中没有用处。
Submit元素和Reset元素与Button元素相似,只是它们有相关的默认动作(提交和重置表单)。所以即使没有onclick事件处理程序,它们也有用。另一方面,因为它们的默认动作,所以它们对提交给Web服务器的表单比对纯客户端的JavaScript程序更有用。如果onclick程序返回false,这两种按钮的默认动作就不会被执行。

切换按钮:Checkbox元素和Radio元素是切换按钮,它们可以具有相同的name性质值。用这种方法创建的Radio元素是互斥的。在使用名字引用这些元素时,必须记住用名字引用的对象是与元素同名的数组,如document.everything.peripherals。要单独引用Checkbox元素,必须使用数组下标:document.everything.peripherals[0]。

第十七章 文档对象模型
Node对象的childNodes属性将返回子节点的列表,firstChild,lastChild,nextSibling,previousSibling和parentNode属性提供了遍历树的方法。appendChild()、removeChild()、replaceChild()、insertBefore()方法使你能给文档树添加节点或从文档树中删除节点。还可以用appendData(),insertData()、deleteData()和repalceData()方法添加插入删除或替换一个Text节点的文本。

常用节点类型:

Element            Node.ELEMENT_NODE           1
Text               Node.TEXT_NODE              3
Document           Node.DOCUMENT_NODE          9
Comment            Node.COMMENT_NODE           8
DocumentFragment   Node.DOCUMENT_FRAGMENT_NODE 11
Attr               Node.ATTRIBUTE_NODE

2
可是IE不支持Node接口定义的节点类型常量。所以在IE中可以这样写if (n.nodeType == 1 /*用直接量代替Node.ELEMENT_NODE常量*/)如果你想可移植的做这点,可以添加如下代码,在没有这些常量时可以定义它们:

if(!window.Node){
  var Node ={
    ELEMENT_NODE:1;
    TEXT_NODE:3;
    DOCUMENT_NODE:9;
    COMMENT_NODE:8;
    DOCUMENT_FRAGMENT_NODE:11;
    ATTRIBUTE_NODE:2;
  }
}

用Element接口的getAttribute()方法、SetAttribute()方法和removeAttribute()方法可以查询设置并删除一个元素的性质。HTMLInputElement接口定义了focus()和blur()方法,HTMLFormElement接口定义了submit()和reset()方法

DOM的命名规则,<input>标记的maxlength性质将被转换成HTMLInputElement的maxLength属性。当该命名规则与JavaScript关键字发生冲突时,应在属性前加前缀“html”来避免冲突。如htmlFor。这一规则的例外是class性质,它可以转换成HTMLElement的className属性。

由于DOM标准定义了接口,而不是类,所以它没有定义任何构造函数方法。所以,如果想创建一个新的Text对象
var t = new Text("this is a new text node");是错误的,可以这样写:var t = document.createTextNode("this is a new text node");

遍历文档

<head>
<script>
function countTags(n) {                        // n is a Node 
    var numtags = 0;                           // Initialize the tag counter
    if (n.nodeType == 1 /*Node.ELEMENT_NODE*/) // Check if n is an Element
        numtags++;                             // Increment the counter if so
    var children = n.childNodes;               // Now get all children of n
    for(var i=0; i < children.length; i++) {   // Loop through the children
        numtags += countTags(children[i]);     // Recurse on each one
    }
    return numtags;                            // Return total number of tags
}
</script>
</head>
<!-- Here's an example of how the countTags() function might be used -->
<body οnlοad="alert('This document has ' + countTags(document) + ' tags')">
This is a <i>sample</i> document.
</body>
另一种遍历文档的方法
<head>
<script>
function countCharacters(n) {               // n is a Node 
    if (n.nodeType == 3 /*Node.TEXT_NODE*/) // Check if n is a Text object
        return n.length;                    // If so, return its length.
    // Otherwise, n may have children whose characters we need to count
    var numchars = 0;  // Used to hold total characters of the children
    // Instead of using the childNodes property, this loop examines the
    // children of n using the firstChild and nextSibling properties.
    for(var m = n.firstChild; m != null; m = m.nextSibling) {
 numchars += countCharacters(m); // Add up total characters found
    }
    return numchars;                    // Return total characters
}
</script>
</head>
<body οnlοad="alert('Document length: ' + countCharacters(document.body))">
This is a sample document.<p>How long is it?
</body>
在使用DOM时,在装载完文档前,不能遍历或操作文档树。搜索文档中的特定的元素
可以用getElementsByTagName()方法获取任何类型的HTML元素的列表。例如要找文档中的所有的表,可以用如下代码:
var tables = document.getElementsByTagName("table");
alert("This document contains" + tables.length + " tables");
注意参数不区分大小写。如果参数是“*”,它将返回文档中所有元素的列表。
如果想处理文档中的第四个段落,<p id="specialParagraph">,可以用如下方法
var myParagraph = document.getElementsByTagName("p")[3];
var myParagraph = document.getElementsById("specialParagraph");
var myParagraph = document.getElementsByName("top")[3];//因为name值可能不唯一,所以getElementsByName()方法返回的是元素的数组。给文档添加内容
document.createElement()、document.createTextNode()方法创建必要的Element节点和Text节点。第十八章 级联样式表和动态HTML
样式表规则
body {margin-left:30px;margin-right:15px;background-color:#ffffff;}   其中body是一个标记选择器,它指定要应用这条样式规则的文档元素。
h1,h2{text-align:center;} 逗号用于分割要应用样式的标记名。如果省略了逗号,那么选择器指定了一条环境规则,只在一个标记嵌套在另一个标记中时应用。例如下面的规则指定用斜体字显示<blockquote>标记,但<blockquote>标记中嵌套的<i>标记中的文本仍然以纯文本、非斜体的样式显示:
blockquote{font-style:italic;}
blockquote i{font-style:normal;}另一种样式表规则使用不同的选择器,指定要应用样式的元素的类。元素的类由HTML标记的class性质定义。例如,下面规则规定以粗体字显示所有class性质为“attention”的标记:
.attention{font-weight:bold;}
类选择器可以和标记名选择器联合使用。下面的规则规定,在<p>标记有class = "attention"性质时,除了以粗体字显示该标记(前面规则设置的)外,还要用红色来显示:
p.attention{color:red;}
样式表还有只应用于具有指定的id性质的元素规则。下面的规则规定,不显示id性质为p1的元素:#p1 {visibility:hidden;}

关联样式表和文档

可以把样式表放置在文档<head>部分中的<style type="text/css">和</style>标记之间。还可以用link标记引用
<link rel="STYLESHEET" type="text/css" href="<%=JspLib.getStaticContent("rumba/css/enterprisesite.css")%>"/>

用户样式表覆盖默认的浏览器样式表,作者样式表覆盖用户样式表,内联样式表覆盖所有样式表。
这条通用规则的一个特例是,值包括!inportant修饰符的用户样式性质覆盖作者样式。在一个样式表中,如果一个元素上应用了多条样式规则,最详细的规定定义的样式将覆盖不太详细的规定定义的发生冲突的样式。指定元素id的规则最详细,其次是指定class属性的规则。仅指定一个标记名的规则最不详细,指定多个篏套标记名的规则比指定一个标记名的规则详细。

CSS的定位和可见性性质

position      设置元素应用的定位类型
top,left     设置元素上边界和左边界的位置
bottom,right 设置元素下边界和右边界的位置
width,height 设置元素的大小
z-index       设置元素相对于其他重叠元素”堆叠顺序“,定义元素位置的第三维
display       设置如何和是否显示一个元素
visibility    设置元素是否可见
clip          定义元素的”裁剪区“,只显示元素在这个区域中的部分
overflow      设置当元素比分配给它的空间大时应该采取什么操作命名规范:JavaScript中的CSS性质
CSS性质border-left-width和JavaScript的CSS2Properties属性borderLeftWidth对应。在使用CSSProperties对象的样式属性时,要记住,所有值必须是字符串,如e.style.position="absolute";


所有定位属性都要求有单位,如e.style.left="300px";

在从HTMLElement的style属性获取了一个CSS2Properties对象时,这个对象的属性表示该元素的内联样式性质。换句话说,设置这些属性就象在元素的style性质中设置了CSS性质一样,它只影响一个元素,在CSS级联中比其他来源的冲突样式设置优先级高。但在读这些CSS2Properties属性时,只有以前用JavaScript代码设置它们,或在使用的HTML元素具有设置了它们需要的style内联性质时,它们的返回值才有意义。