1 JavaScript实现
一个完整的JavaScript实现应该由三部分组成:ECMAScript、DOM、BOM。
ECMAScript(核心):
① 语法
② 类型
③ 语句
④ 关键字
⑤ 保留字
⑥ 操作符
⑦ 对象
DOM(文档对象模型):
DOM把整个页面映射成一个多层节点结构。HTML或XML页面中的每个组成部分都是某种类型的节点,这些节点又包含这不同类型的数据。借助DOM提供的API,开发人员可以轻松自如地删除、添加、替换或修改任何节点,API类型有以下几种:
① DOM视图(DOM Views):定义了跟踪不同文档(例如、应用CSS之前和之后的文档)视图的接口;
② DOM事件(DOM Events):定义了事件和事件处理的接口;
③ DOM样式(DOM Style):定义了基于CSS为元素应用样式的接口;
...
BOM(浏览器对象模型):
开发人员使用BOM可以控制浏览器显示的页面以外的部分。一般而言,BOM只处理浏览器窗口和框架;但人们习惯上也把所有针对JS扩展算作BOM的一部分。如:
① 弹出新浏览器窗口的功能;
② 移动、缩放和关闭浏览器窗口的功能;
③ 提供浏览器详细信息的navigator对象;
④ 提供浏览器所加载页面的详细信息的location对象;
⑤ 提供用户显示器分辨率详细信息的screen对象;
⑥ 对cookies的支持;
⑦ 像XMLHttpRequest 和 IE 的ActiveXObject这样的自定义对象。
2 在HTML中使用JavaScript
向HTML页面中插入JS的主要方法,就是使用,HTML4.01为不需要再写额外代码,写了也不执行,而且
src
还可包含外部域的JS文件,如http://www.abc.com/foo.js
;
⑥ type
:可选。
现在一般把JS引用放在标签中,放在页面代码的后面。
2.1 嵌入代码与外部文件
推荐尽可能使用外部文件来包含JS代码:
① 可维护性;
② 可缓存,浏览器能够根据具体的设置缓存链接的所有外部JS文件,如果有两个页面都使用同一个JS文件,那么只需要下载一次。 ★
3 文档模式
使用文档类型切换实现。
4 语法
① 区分大小写;
② 标识符最好使用驼峰命名法;
③ 严格模式;
④ 语句结束时最好带分号,如果省略,则由解析器确定语句的结尾;
⑤ { }
最好不要省略;
⑥ 关键字与保留字不可以用作变量、标签或者函数名;
⑦ 变量:ECMAScript的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。
⑧ 使用var
操作符定义的变量将成为定义该变量的作用域中的局部变量:
function test(){
var message = "hi"; // 局部变量
}
test();
alert(message); // 错误!
function test(){
message = "hi"; // 全局变量
}
test();
alert(message); // "hi"
也可以这样连续定义多个变量,用逗号隔开:
var message = "hi",
found = false,
age = 29;
5 数据类型
① NaN
,在ECMAScript中,任何数值除于0会返回NaN
,和其他语言不同;
② string类型中的字符字面量;
③ ECMAScript中的字符串是不可变的,要改变某个变量保存的字符串,首先就要创建新的字符串,再在内存里销毁原来的字符串;
④ 转换成字符串:
var age = 11;
var ageAsString = age.toString(); // 字符串11
var found = true;
var foundAsString = found.toString(); // 字符串true
还可以带参去转换成不同进制的字符串:
var num = 10;
alert(num.toString()); // 10
alert(num.toString(2)); // 1010
alert(num.toString(8)); // 12
alert(num.toString(10)); // 10
alert(num.toString(16)); // a
其他:
var value1 = 10;
var value2 = true;
var value3 = null;
var value4;
alert(String(value1)); // 10
alert(String(value2)); // true
alert(String(value3)); // null
alert(String(value4)); // undefined
6 操作符
① --a
++a
(一元递减递增操作符):
var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2; // 等于21
var num4 = num1 + num2; // 等于21
执行前置型递减递增时,变量的值都是在语句被求值前改变的;而后置型递增或递减a--
a++
,不会立即影响到当前包含它们的语句求值,但实际上a
已经发生增或减操作:
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 等于22
var num4 = num1 + num2; // 等于21
var num5 = (num1--) + num1; // 等于1 + 0
这四种递减递增操作符,不仅对整数有效,对其他的数据类型也有效:
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1. 1;
var o = {
valueOf: function() {
return -1;
}
};
s1++; // 值变成数值3
s2++; // 值变成NaN
b++; // 值变成数值1
f--; // 值变成0.10000000000000009(由于浮点舍入错误所致)
o--; // 值变成数值-2
② -a
+a
(一元加和减操作符):
对非数值应用一元加操作符时,该操作符会像Number()
转型函数一样对这个值执行转换;如果是对象的话,则会先调用它们的valueOf()
和(或)toString()
方法,再转换得到的值:
var s1 = "01";
var s2 = "1. 1";
var s3 = "z";
var b = false;
var f = 1. 1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = +s1; // 值变成数值1
s2 = +s2; // 值变成数值1.1
s3 = +s3; // 值变成NaN
b = +b; // 值变成数值0
f = +f; // 值未变,仍然是1.1
o = +o; // 值变成数值-1
对非数值应用一元减操作符时,规则和加法是一样的,只是会把得到的数值最后再转化一次,转成负数。
③ 位操作符: ★
1> 计算一个负数的反码 -
JS虽然用的是IEEE-754 64位格式存储,但实际操作时,是把64位转为32位,执行操作后,再转回64位。计算-18的二进制补码(负数存储格式是二进制补码)时,先求出18的二进制码10010(五个有效位),将0替换成1、1为0;再将得到的二进制反码加1,成功得到111111111111111111111111111101110。
2> 按位非(NOT) ~
var num1 = 25; // 二进制
00000000000000000000000000011001
var num2 = ~num1; // 二进制
11111111111111111111111111100110
alert(num2); // -26
求操作数的负值再减去1,也可以得到相同结果:
var num1 = 25;
var num2 = -num1 - 1;
alert(num2); // "-26"
3> 按位与(AND) &
使用&
操作两个数值时,会将两个数值的每一位对齐,然后根据下表的操作,对相同位置上的两个数执行and操作:
只有都是1才返回1:
var result = 25 & 3;
alert(result); //1
因为25和3的对应的32个位置,只有最后一位上下都是1,其余上下执行and操作都得0。
4> 按位或(OR) |
规则同&
:
5> 按位异或(XOR) ^
规则同&
:
6> 左移操作符 <<
将数值所有位整体向左移,右侧多出的5个空格用0来填,2 << 5
等于64。
7> 有符号的右移操作符 >>
与左移正好相反,64 >> 5
等于2,会用符号位的值填补空格,原本是1就用1,是0用0。
8> 无符号的右移操作符 >>>
与>>
的区别是,>>>
不会用符号位的值填补空格,而是用0,这样的话,如果转化的是负数,出来的结果区别会很大。
④ 布尔操作符: ★
1> !
(NOT)
转化任意值,再求反:
alert(!false); // true
alert(!"blue"); // false
alert(!0); // true
alert(!NaN); // true
alert(!""); // true
alert(!12345); // false
2> &&
(AND)
var result = true && false;
需要两个值,不会转化值,除了数值和bool值,但如果第一个值是false
,那么第二个值是什么都不重要,不管也不去求值,直接返回false
,即便是错误的,&&
是个短路操作符。
另外,如果有一个数不是布尔值,那&&
不只是能返回布尔值,它遵循以下规则:
如果第一个数是对象,则返回第二个数;
如果第二个数是对象,那么只有第一个数的求值结果为true
的情况下才会返回该对象;
如果两个数都是对象,则返回第二个数;
如果有一个数是null
,则返回null
;
如果有一个数是NaN
,则返回NaN
;
如果有一个数是undefined
,则返回undefined
;
3> ||
(OR) ★
||
也是个短路操作符,第一个值是true
就不管了,也同样不只返回布尔值:
如果第一个数是对象,则返回第一个数;
如果第一个数的求值结果为false
,则返回第二个数;
如果两个数都是对象,则返回第一个数;
如果两个数都是null
,则返回null
;
如果两个数都是NaN
,则返回null
;
如果两个数都是undefined
,则返回undefined
;
可以利用这些特性来赋值:
var preferredObject;
var backupObject = '2';
var myObject = preferredObject || backupObject;
⑤ 乘性操作符 *
:
*
如果乘的不是数值,会调用Number()
将其转为数值;/
除法同乘法相似;求模(余数)用%
:
var result = 26 % 5; // 等于 1
⑥ 加性操作符 +
:
+
分三种情况:数值相加、字符串相加(字符串拼接)、其余的(对象、数值、布尔调用toString()
,undefined
和null
调用String()
);
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message); //"The sum of 5 and 10 is 15"
不加括号会输出...510;
-
的话分两种情况:数值相减、其余的(数值、布尔、undefined
和null
调用Number()
,对象用valueOf()
)。
⑦ 关系操作符 <
、>
、<=
和>=
:
<
、>
、<=
和>=
,会返回布尔值,其规则:
如果两个操作数都是数值,则执行数值比较;
如果两个操作数都是字符串,则比较两个字符串对应的字符编码值;
如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较;
如果一个操作数是对象,则调用这个对象的valueOf()
方法,用得到的结果按照前面的规则执行比较;
如果对象没有valueOf()
方法,则调用toString()
方法,并用得到的结果根据前面的规则执行比较;
如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较;
任何操作数与NaN
进行关系比较,结果都是false
。
⑧ 条件操作符 ?
: ★
variable = boolean_ expression ? true_ value : false_ value;
对boolean_ expression
求值,若为true
,variable
赋true_value
;若为false
,variable
赋true_value
。
⑨ 赋值操作符 =
:
var num = 10;
num = num + 10;
可简化为:
var num = 10;
num += 10;
这样的简化还有*=
、/=
、%=
、<<=
等
⑩ 逗号操作符 ,
:
简化操作:
var num1 = 1,
num2 = 2,
num3 = 3;
总返回表达式最后一项:
var num = (5, 1, 4, 8, 0); // num 的值为 0
这玩意不是(x,y)...
优先级从高到底
① ()
的优先级最高;
② 一元运算符,++
--
!
;
③ 算数运算符,先*
/
%
后+
-
;
④ 关系运算符,>
>=
<
<=
;
⑤ 相等运算符,==
!=
===
!==
;
⑥ 逻辑运算符,先&&
再||
。