第1章——JavaScript简介
一、JavaScript实现
JavaScript是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
核心(ECMAScript) 由ECMA-262定义,提供核心语言功能。
文档对象模型(DOM) 提供访问和操作网页内容的方法和接口。
浏览器对象模型(BOM) 提供与浏览器交互的方法和接口。
第2章——在HTML中使用JavaScript
一、<script>标签
1、<scripot>元素
向HTML页面中插入JavaScript的主要方法,就是使用<script>元素。
使用<script>元素的方式有两种:直接在页面中嵌入js代码和包含外部的js文件。
包含在<script>元素内部的JavaScript代码将被从上至下依次解释。在解释器对<script>元素内部的所有代码求值完毕之前,页面中的其余内容都不会被浏览器加载或显示。 注意:在使用嵌入js代码时,代码中不能出现“</script>”字符串,浏览器会认为那结束标签。"<\/script>"可解决('\' '/'符号)
通过<script>元素来包含外部js文件,src属性是必须的。属性的值时指向外部js文件的链接。与嵌入式一样,在解析外部js文件(包括下载该文件)时,页面的处理也会暂时停止。若果在XHTML中,结束标签可以省略。需注意:带有src属性的<script>元素标签之间不能再包含额外的js代码,否则将被忽略。src的值也可以是来自外部域的js文件。
只要不存在defer和async属性,浏览器就会按照<script>元素在页面中出现的先后顺序对他们依次进行解析。
2、标签的位置
(1)、<head>元素中:若js代码过多,页面会出现明显的延迟,延迟期间页面呈现空白。
(2)、<body>元素中页面的内容后面:先解析html代码,再解析js代码。
3、延迟脚本
defer属性:脚本会被延迟到整个页面都解析完毕后在运行。(按出现的先后顺序执行)
注:只适用于外部脚本文件。 放在页面底部仍是最佳选择。
4、异步脚本
async属性:与defer作用类似,不同点是async的脚本不能保证按照指定他们的先后顺序执行。
二、嵌入代码和外部文件
虽然嵌入式js代码没有问题,但是最好还是用调用外部文件。优点如下:
可维护性:把所有js文件放在一个文件夹下,便于维护。在不触及HTML标记的情况下编辑js代码。
可缓存:若两个页面都是用同一个文件,那么文件只用下载一次。加快页面加载速度。
适应未来:通过外部文件来包含js无需使用XHTML或注释hack。html和xhtml包含外部文件的语法是相同的。
三、文档模式
混杂模式:会让ie的行为与ie5相同。
标准模式:会让ie的行为更接近标准行为。 例:<! DOCTYPE html >
虽然两种模式主要影响css,但在某种情况下回影响js的解释执行。
四、<noscript>元素
为了让不支持js的浏览器平稳退化。这个元素可以包含能够出现在文档<body>中的任何html元素(<script>元素除外)。
包含的内容只有在浏览器不支持脚本,或脚本被禁用的情况下才会显示。
五、小结
第3章——基本概念
任何语言的核心都会描述这门语言最基本的工作原理。而描述的内容通常要涉及这门语言的语法、操作符等基本概念。
ECMA-262通过叫做ECMAScript的‘伪语言’为我们描述了JavaScript的所有这些基本概念。
1.1 语法
ECMAScript的语法大量借鉴C及其他类C语言(java等)的语法。但ECMAScript的语法更加宽松。
1.1.1 区分大小写
ECMAScript中的一切(变量、函数名、操作符)都区分大小写。
1.1.2 标识符
所谓标识符,就是指 变量、函数、属性的名字,或者函数的参数。可按下列格式规则组合的一个或多个字符:
□ 第一个字符必须是一个字母、下划线、或一个美元符号($);
□ 其他字符可以是字母、下划线、美元符号或数字。
按照惯例,ECMAScript 标识符采用驼峰大小写格式,为了与ECMAScript内置函数和对象命名格式保持一致,可以将其当作一种最佳实践。 注:不能把关键字、保留字、true、false、null作为标识符。
1.1.3 注释
ECMAScript使用C风格的注释,包括单行注释和块级注释。
// 单行注释
/* 块级注释 */
1.1.4 严格模式
严格模式是为js定义了一种不同的解析与执行模型。在严格模式下,对某些不安全的操作会抛出错误。
在整个脚本中启用严格模式,只需在顶部添加 " use strict";
这是一个编译指示,告诉支持的js引擎切换到严格模式。
也可以指定函数与在严格模式下执行 在函数体中第一行添加 " use strict";
在严格模式下,js的执行结果会有很大的不同。
1.1.5 语句
ECMAScript中的语句以一个分号结尾;没有分号,则由解析器确定语句的结尾。(最好加上分号)
可以使用C风格的语法把多余的语句组合到一个代码块中{}
在控制语句中使用代码块可以让编码意图更加清晰,而且也能降低修改代码时出错的几率。
1.2 关键字和保留字
一般来说,最好都不要使用关键字和保留字作为标识符和属性名,以便于将来的ECMAScript版本兼容。
1.3 变量
ECMAScript的变量是松散类型的,即可以用来保存任何类型的数据。换句话说,每个变量仅仅是一个用来保存值得占位符而已。定义变量时要用var操作符(关键字),后跟变量名(一个标识符)。
var message; 该行代码定义了一个名为message的变量,该变量可以用来保存任何值。(像这样未经过初始化的变量,会保存一个特殊的值——undefined)
var message = 'hi'; 再此,变量中保存了一个字符串值‘hi’。这样初始化变量并不会把他标记为字符串类型;初始化的过程就是给变量赋一个值。
注意:使用var操作符定义的变量将成为定义该变量的作用域中的局部变量。即若在一个函数中使用var定义一个变量,那么这个变量在函数退出后就会被销毁。 若省略var操作符,将会创建一个全局变量。在函数外部任何地方被访问到。
在严格模式下,不能定义名为eval或arguements的变量,否则会导致或语法错误。
1.4 数据类型
ECMAScript中有5简单数据类型(也成为基本数据类型):undefined、null、boolean、number、string。
还有1中复杂数据类型——Object,Object本质上是由一种无序的名值对组成的。ECMAScript不支持任何创建自定义类型的机制。而所有值都是上述6中数据类型之一。由于ECMAScript数据类型具有动态性,因此没有定义其他数据类型的必要。
1.4.1 typeof操作符
检测给定变量的数据类型。
□ 'undefined'——如果这个值未定义;
□ 'boolean'——如果这个值是布尔值;
□ 'string'——如果这个值是字符串;
□ 'number'——这个值是数值;
□ 'object'——这个值是对象或null;
□ 'function'——这个值是函数。
typeof操作符的操作数可以是变量,也可以是自面量。
typeof null会返回‘object’,因为特殊值null被认为是一个空的对象引用。Safari5及之前版本chrome7及之前版本在对正则表达式调用typeof 时会返回‘function’,而其他浏览器在这种情况下会返回‘object’。
1.4.2 undefined类型
undefined类型只有一个值,即特殊的undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。
包含undefined值的变量与尚未定义的变量是不一样的。
对于尚未声明过的变量,只能执行一项操作,即用typeof操作符检测其数据类型。然而对未初始化的变量和未声明的变量执行typeof操作符同样也会返回undefined值。
1.4.3 null类型
null类型是第二个只有一个值的数据类型。这个特殊值是null。从逻辑角度看,null值表示一个空对象指针,而这也是使用typeof操作符检测null值时会返回‘object’的原因。
如果定义的变量准备在将来用于保存对象,那么最好将变量初始化为null而不是其他值。这样,只要直接检查null值就可以知道相应的变量是否保存了一个对象的引用。
实际上,undefined值时派生自null值得,因此ECMA-262规定对他们的相等测试要返回true
尽管他们有这样的关系,但他们的用途完全不同。无论什么情况下都没必要把一个变量的值显式的设置为undefined,可是同样的规则对null却不适用。只要意在保存的对象的变量还没有真正的保存对象,就应该明确的让该变量保存null值。这样不仅可以体现null作为空对象指针的惯例,而且有助于进一步区分null和undefined。
1.4.4 boolean类型
Boolean类型是ECMAScript中使用的最多的一种类型,该类型只有两个字面量:true和false。这两个值与数字之不是一回事,因此true不一定等于1,而false不一定等于0。而布尔值是区分大小写的,例:True不是布尔值,而是一个标识符。
在ECMAScript中所有类型的值都有与这两个boolean值等价的值。可以用转型函数Boolean()将一个值转换为对应的Boolean值。转换规则如下:
这些转换规则对理解流控制语句(如if语句)自动执行相应的Boolean转换非常重要,因此确切的知道在流控制语句中使用的是什么变量至关重要
1.4.5 number类型
这种类型使用IEEE754格式来表示整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。为支持各种数值类型,ECMA-262定义了不同的数值字面量格式。
最基本的数值字面量格式是十进制整数。 例:var num = 55;
js中保存数值的方式,可以保存正零和负零,且两者相等。
(1)浮点数值
所谓浮点数值,就是该数值中必须包含一个小数点,且小数点后面必须至少有一位数字。 例:
浮点数值需要阿德内存空间是保存整数值的两倍,因此ECMAScript会恰当地将浮点数值转换为整数值。例:
二对于极大或极小的值可以用e表示法(即科学计数法)表示的浮点数值表示。即前面是数值(可整可浮点),中间大写或小写的e,后面是10的幂中的指数。例:
极小数后面的数为负,即加一个符号。
默认情况下,ECMAScript会将那些小数点后面带有6个零以上的浮点数值转换为e表示法表示的数值。
(2)数值范围
由于内存限制,ECMAScript能够表示的最小值是5e-324,最大值是1.7976931348623157e+308。若计算结果超出数值范围的值,这个数值将被自动转换为特殊的Infinity值。具体来说是-Infinity(负无穷),Infinity(正无穷),且该值无法参与下一次的计算。想确定一个数值是否有穷,isFinite()函数,是的话会返回true。
(3)NaN
NaN,即非数值(not a number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况。例:在别的编程语言中,任何数值除以0都会导致错误,从而停止执行。而在ECMAScript中,任何数值除以0返回NaN,不会影响程序其他代码的执行。
NaN的特点:涉及NaN的操作都会返回NaN; NaN与任何数值都不相等,包括他本身。
(4)数值转换
有三个函数可以把非数值转换为数值:Number()、parseInt()、parseFloat()。
Number()可以用于任何数据类型,后两个则专门用于把字符串转换成数值。
在处理整数的时候更常用parseInt()函数。它会忽略字符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt()就会返回NaN。如果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续的字符或者遇到了一个非数字字符。
与parseInt函数类似,parseFloat也是从第一个字符开始解析每个字符,一直到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。比如:字符串中的第一个小数点是有效的,第二个小数点就是无效的了。
1.4.6 string类型
String类型用于表示由零或多个16位Unicode字符组成的字符序列,即字符串。字符串可以由双引号或单引号组成。
(1)字符字面量
String数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符或者有其他用途的字符。
转义序列表示一个字符,任何字符串的长度都可以通过访问其length属性取得。若字符串中含有双字节字符,length属性可能不会精确地返回字符串中的字符数目。
(2)字符串的特点
ECMAScript中的字符串是不可变的。要改变某个变量保存的字符串,首先要销毁原来的字符串,再用一个新值的字符串填充该变量。
(3)转换为字符串
把一个值转换为一个字符串有两种方式。几乎每个值都有toString()方法,这个方法唯一要做的就是返回相应值的字符串表现。 数值、布尔值、对象和字符串值都有toString()方法。但null和undefined值没有这个方法。
toString()方法可以传递一个参数:输出数值的基数。默认情况下是以十进制格式返回数值的字符串表示,还可以通过传递参数,输出以二进制,八进制,十六进制,以及其他任意有效进制格式表示的字符串值。
在不知道要转换的值是不是null或undefined的情况下,还可以使用转型函数String(),这个函数能够将任何类型的值转换为字符串,以下是转换规则:
1.4.7 object类型
ECMAScript中的对象其实就是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型的名称来创建。而创建object类型的实例并为其添加属性和方法,就可以创建自定义对象,例: var o = new Object()。 在ECMAScript中,如果不给构造函数传递参数,则可以省略后面的圆括号。(不推荐省略)
在ECMAScript中,Object类型是所有它的实例的基础,也就是说,Object类型所具有的任何属性和方法也同样存在于更具体的对象中。
1.5 操作符
ECMA--262描述了一组用于操作数据值得操作符,包括算术操作符、位操作符、关系操作符和相等操作符。ECMAScript操作符适用于很多值,包括字符串、数字值、布尔值、对象等。不过应用对象时,操作符会调用对象的valueof()或toString()方法,取得可操作的值。
1.5.1 一元操作符
只能操作一个值的操作符叫做一元操作符。
(1)递增和递减操作符
分别为前置型和后置型。顾名思义,位于要操作的变量之前或者之后。
执行前置递增递减的操作时,变量的值都是在语句被求值以前改变的。而后置型则相反。
(2)一元加和减操作符
再对非数值应用一元加操作时,操作符会像Number()转型函数一样对这个值执行转换。 而减操作符同理,不过最后再将得到的值转换为负数。
一元加和减操作符主要用于基本运算,也可以用于转换数据类型。
1.5.2 位操作符
位操作符用于在最进本的层次上,即按内存中表示数值的位来操作数值。JavaScript中的所有数值以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换为32位的整数,然后执行操作,最后将结果转回64位。
对于有符号的整数,32位中的前31位表示整数的值,最后一位表示数值的符号:0表示整数,1表示负数。表示符号的位叫做符号位,符号位的值决定了数值的格式。其中,整数易二进制格式存储。31位中每一位都表示2的幂,第一位是2^0,第二位是2^1,没用用到的位用0补充,可以忽略。如数值123,二进制表示为00000000000000000000000011110110,也可以表示为11110110。1*2^6+1*2^5+1*2^4+1*2^3+0*2^2+1*2^1+1*2^0.
负数也是以二进制来表示,但是使用的是二进制的补码。计算一个数值的二进制补码需要经过以下步骤:
1.先求这个数值的绝对值的二进制编码;
2.求二进制反码,将二进制码的0替换1,1替换为0
3.将二进制的反码加1.
在以二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码前面加上了一个负号。例:
在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。
如果对非数值应用位操作符,会先使用Number()函数将该值转换为数值再应用位操作。
(1)按位非(NOT)
按位非操作符由一个波浪线~表示,执行按位非的结果就是返回数值的反码。
(2)按位与(AND)
按位与操作符由一个和号字符(&)表示,它有两个操作符。按位与操作只在两个数值的对应位都是1时才返回1,任何一位,是0,结果都是0。
(3)按位或(OR)
按位或操作符由一个竖线符号 | 表示,同样有两个操作数。有一位是1时就返回1,两位都是0的情况下才返回0
(4)按位异或(XOR)
按位异或操作符由一个插入符号 ^ 表示,两个操作数。只有一个1时才返回1,两个1或两个0则会返回0。
(5)左移
左移操作符由两个小于号 <<表示 ,会将数值的所有位向左移动指定的位数。
注:左移不会影响操作数的符号位。例:-2左移5位,结果是-64,而不是64。
(6)有符号的右移
由两个大于号 >>,这个操作符会将数值向右移动,但保留符号位(即正负号标记)
(7)无符号右移
由三个大于号表示>>> ,会将所有的32位都向右移动。
对正数来说,无符号右移的结果与有符号右移相同。对负数来讲,无符号右移是以0来填充空位。
其次,无符号右移操作符会把负数的二进制码当成正数的二进制码。且负数以其绝对值的二进制补码形式表示,会导致无符号右移的而结果非常大。
1.5.3 布尔操作符
布尔操作符一共有3个:非(NOT)、与(AND)、或(OR、)
(1)逻辑非
由一个!表示,可应用于任何值,都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反。规则:
同时使用两个逻辑非操作符,实际上会模拟Boolean()转型函数的行为。最终结果与之相同。
(2)逻辑与(AND)
&&表示 两个操作数 。两个都为true时才为true,有一个或者两个false 都为false。如果有一个操作数不是布尔值,逻辑与也不一定返回布尔值。
逻辑与操作属于短路操作,如果第一个操作数能决定结果,就不会再对第二个操作数求值。例:第一个为false,无论第二个值是什么,结果都是false。注:不能使用未定义的值,会导致错误
(3)逻辑或(OR)
两个竖线 || 表示 只有两个值都为false时结果才为false,有一个是true,最终结果就是true。如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值。
var myObject = preferredObjeect || backupObject
变量myObject被赋予等号后两个值中的一个。 变量preferredObjeect包含优先赋给变量myObject的值,若preferredObjeect中不包含有效值(null),backupObject 则提供后备值。
1.5.4 乘性操作符
ECMAScript定义了3个乘性操作符:乘法、除法、求模。操作数为非数值的情况下会自动执行类型转换。Number()。
(1)乘法
* 表示 ,用于计算乘积
(2)除法
/ 表示
(3)求模
%
1.5.5 加性操作符
(1)加法 (+)
(2)减法(-)
1.5.6 关系操作符
> 、 < 、 >= 、 <=常用与对两个值的进行比较 ,都后返回一个布尔值。
任何数与NaN比较都会返回false。
1.5.7 相等操作符
相等和不相等——先转换再比较 。 全等和不全等——仅比较转换。
(1)相等和不相等(== and !=)
成立返回true。这两个操作符都会现转换操作数(通常称为强制转型),然后再比较相等性。
(2)全等和不全等(=== and !==)
只在两个操作数未经转换就相等的情况下返回true。(全等会比较数据类型)
1.5.8 条件操作符
z?a:b z如果是true ,则把a赋给z,反之b赋给z。
1.5.9 赋值操作符
= 表示,其作用是把右边的值赋给左侧的变量。
复合赋值:在=前添加乘性操作符、加性操作符或位操作符 例:num+=10 num=num+10
其作用是简化赋值操作。
1.5.10 逗号操作符
使用逗号操作符可以再一条语句中执行多个操作。可用于声明多个变量。
在赋值时,逗号操作符会返回表达式中的最后一项。
1.6 语句
语句定义了ECMAScript中的主要语法,语句通常使用一或多关键字来完成给定任务。
1.6.1 if语句
if (condition) statement1 else statement2
其中condition可以是任意表达式,且求值结果不一定是布尔值。ECMAScript会自动调用Boolean()转换函数将这个表达式的结果转换为一个布尔值。若是true执行statement1,若是false,执行statement2。 推荐使用代码块。
1.6.2 do-while 语句
一种后测试循环语句,之有在循环体中的代码执行之后,才会测试出口条件。话句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次。
1.6.3 while语句
while语句属于前测试循环语句。即循环体代码被执行之前,就会对出口条件求值。
1.6.4 for语句
前测试循环语句,具有在执行循环之前初始化变量和定义循环后要执行的代码的能力
由于ECMAScript中不存在块级作用域,因此在循环内部定义的变量也可以在外部访问到。
此外,for语句中的初始化表达式,控制表达式和循环后表达式都是可选的,若全部省略则是一个无限循环。
1.6.5 for-in 语句
for-in语句是一种精准的迭代语句,可用用来枚举对象的属性。
ECMAScript对象的属性没有顺序,所以for-in循环输出的属性名的顺序是不可预测的,具体因浏览器而异。若值为null或undefined会抛出错误。ECMAScript5是不执行循环体。所以使用for-in之前先确定值不是null或undefined。
1.6.6 label语句
使用label语句可以在代码中添加标签。加标签的语句一般都要与for语句等循环语句配合使用。
1.6.7 break和continue语句
用于在循环中精确地控制代码的执行。区别:break是结束循环。 continue是跳过本次循环,执行下一次循环。
break和continue与label语句联用,从而返回代码中特定的位置。例:
1.6.8 with语句
将代码的作用域设置到一个特定的对象中。
1.6.9 switch语句
case的含义:如果表达式等于这个值,则执行后面的语句。最后的default用于表达式不匹配前面任何一种case时执行的。break:执行语句之后跳出switch语句。若忽略break,会导致继续执行后面的case。
case值可以使常量或表达式。 注:switch语句在比较值时使用的是全等操作符。(不会发生类型转换)
1.7 函数
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。ECMAScript中的函数使用function关键字来声明,后跟一组参数以及函数体。
可以通过其函数名来调用,后面还要加上一堆圆括号和参数(参数若有多个,要用逗号隔开)。
ECMAScript中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过return语句后跟要返回的值来实现返回值。函数再执行return语句之后停止并立即退出,所以return语句后面的代码不会被执行。return语句也可以不带有任何返回值。这时,函数再停止执行后返回undefined。
1.7.1 理解参数
ECMAScript函数不介意传递进多少个参数,也不在乎传进来参数是什么数据类型。原因是ECMAScript中的参数在内部是用一个数组表示的。函数接受的始终都是这个数组,而不关心数组中包含哪些参数。在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。
arguments对象只是与数组类似,可以用方括号的语法访问他的每一个元素。(arguments[0]。。。)使用length属性来确定传递多少个参数。 注:命名的参数只提供便利,但不是必须的。 arguments对象可以与命名参数一起使用。
关于arguments:他的值永远与对应命名参数的值保持同步。 修改了arguments[0]也就修改了第一个命名参数的值。不过并不是说读取这两个值会访问相同的内存空间,他们的内存空间是独立的,但值会同步,且是单向的。修改命名参数不会改变arguments中对应的值。 注:没有传递值得命名参数将自动被赋予undefined值。例:如果只给函数传递了一个参数,出现的第二个参数就会保存undefined值。
1.7.2 没有重载
ECMAScript函数不能像传统意义上那样实现重载。没有签名,其参数是由包含零或多个值的数组来表示的。没有函数签名,真正的重载是做不到的
函数被定义了两次,但后定义的函数覆盖了先定义的函数。 通过检查传入函数中的参数的类型和数量并作出不同的反应,可以模仿方法的重载。
小结:
JavaScript的核心语言特性在ECMA-262中是以名为ECMAScript的伪语言的形式来定义的,ECMAScript中包含了所有基本的语法、操作符、数据类型以及完成基本的计算任务所必需的对象。但没有对取得输入和产生输出的机制做出规定。理解ECMAScript及其纷繁复杂的各种细节,是理解其在Web浏览器中的实现——JavaScript的关键。