Javascript学习笔记
参考《JavaScript高级程序设计(第三版)》,版权归原书作者所有
绪论
一个完整的JavaScript由三个部分组成:
- 核心(ECMAScript )
- 文档对象模型(DOM )
- 浏览器对象模型(BOM)
在HTML文件中使用<script>标签定义JavaScript脚本。<script>元素定义了六个属性:async表示立即下载脚本;charset表示字符集,一般被忽略;defer表示延迟到整个脚本解析完毕在执行;language已废弃;src表示外部文件路径;type表示脚本文件的MIME类型。具体用法如下:
<!-- 直接嵌入 -->
<script type="text/javascript">
function sayHi(){
alert("Say Hi");
}
</script>
<!-- 外部文件嵌入 -->
<script type="text/javascript" src="sample.js"></script>
文档模式:混杂模式(默认)、标准模式、准标准模式
<noscript>…</noscript>在JavaScript不受支持或禁用时显示信息。
基本语法
1、标识符命名、注释风格、语句写法、关键字与保留字与C语言基本相同,松散类型变量。
2、5种基本数据类型和一种复杂数据类型:undefined、null、boolean、number、string和object,不支持创建自定义类型,没有类、结构体、枚举类型等概念,使用typeof操作符返回数据类型。
- undefined:未定义类型,不存在或未初始化时的类型
- null:空对象指针类型,注意 typeof null == object,undefined == null
- boolean:布尔类型,字面值true与false,转型函数Boolean()
boolean值转换规则:null、""、undefined、0、NaN、undefined转换成false,其他一律为true。 - number:数值类型,字面值记法与c语言一致。
重要常量:Number.MAXVALUE、Number.MINVALUE、Infinity、-Infinity、NaN
判断无穷 isFinite(),判断NaN isNaN()
数值转换函数:Number()、parseInt()、parseFloat()
Number函数转换规则:true与false转换为1和0,null转换为0,undefined转换为NaN,不同类型的数字字符串按照对应规则解析,空串转换为0,其他字符串转换为NaN,如果是对象,先调用valueOf方法,如果返回NaN再调用toString方法并按字符串处理。
parseInt方法可以附加基数转换成不同进制,parseFloat会优先尝试整数解析。 - string:字符串类型,调用toString方法转型,数值类型的toString方法可以附加基数。
- object:功能与数据的集合。包含constructor、hasOwnProperty(propertyName)、isPrototypeOf(object)、propertyIsEnumerable(propertyName)、toLocaleString()、toString()、valueOf()等方法。
3、操作符
一元操作符:包括自增和自减操作符、一元加和减操作符,非Number类型会先转型。
位运算操作符:与c语言类似,注意区分>>与>>>。
逻辑运算操作符:逻辑非运算符单纯返回逻辑值。对于逻辑或运算符,如果左操作数转型的boolean值为true,那么直接返回左操作数,否则返回右操作数。对于逻辑与运算符,如果左操作数为false,直接返回右操作数,否则返回左操作数。逻辑非一定返回boolean值,逻辑与和逻辑或返回值不一定是boolean值。
四则运算操作符:与c语言类似,但注意整数的除法运算不是带余除法。
关系运算符:注意区别相等与全等。相等(==)与不相等(!=)先转换再比较,全等(===)与不全等(!==)只比较不转换。特殊情况的比较结果:
null == undefined | true | true == 1 | true |
"NaN" == NaN | false | true == 2 | false |
5 == NaN | false | undefined == 0 | false |
NaN == NaN | false | null == 0 | false |
NaN != NaN | true | "5" == 5 | true |
false == 0 | true |
4、语句
if-else/switch语句、三大循环、for-in语句、with语句、带标签的continue/break语句。
注意Javascript没有块作用域,循环内部定义的变量循环外也能访问。
switch语句采用全等性判断,且case分支可以是变量和表达式。
5、函数
函数声明:
function myFunc(arg0,arg1,...,argn){
//...
}
函数对象:
var myFunc = function(arg0,arg1,...,argn){
//...
}
(1)使用arguments可以访问参数,命名参数不是必需的,解析器不会验证命名参数,使用arguments的length属性可以获得参数个数,arguments与命名参数永远保持同步,严格模式下不能通过arguments进行赋值。
(2)不存在函数重载,新的函数定义会直接覆盖旧的函数定义。
变量、作用域与内存问题
1、基本类型和引用类型的值
基本类型没有属性和方法,引用类型可以动态添加和删除属性和方法。
基本类型执行深拷贝,引用类型执行浅拷贝。
传递参数的方式为值传递。
使用instanceof操作符判断对象的具体类型。
“typeof 函数”返回“function”。
在safari 5和chrome 7之前的版本中“typeof 正则表达式”返回"function",而在IE和firefox中返回“object"。
2、执行环境及作用域
执行环境定义了变量和对象有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和对象都保存在该对象中。
全局执行环境是最外侧的执行环境。
函数执行环境定义了函数有权访问的其他数据。函数执行时,函数执行环境被推入环境栈,函数执行完毕后被销毁。函数执行环境对应的变量对象是活动对象。
当代码在环境中执行时,会创建变量对象的作用域链,作用域链中的下一个变量对象来自外部包含环境,作用域链的最后一个元素是全局执行环境的变量对象。而标识符解析的过程则是沿着作用域链逐级寻找标识符的过程。
延长作用域链:当执行try-catch语句的catch块或with语句时,会在作用域链头部临时增添一个执行环境,达到延长作用域链的目的,执行完毕后再移除。
JavaScript中没有块级作用域。
3、垃圾回收
类似java的垃圾回收机制。
IE浏览器中一部分对象不是原生JavaScript对象,采用了引用计数机制,为了防止循环引用导致内存泄露,应当通过将值设为null来解除引用。
引用类型
1、Object
创建object实例:
var person = new Object();
person.name = "Zhang San";
person.age = 29;
或者
var person = {
name:"Zhang San",
age:29
};
访问对象属性:
alert(person.name);
alert(person["name"];
//使用方括号访问属性的优点在于可以使用变量,属性名也可以不遵循标识符规范
2、Array类型
(1)创建数组:
//使用构造函数
var colos = new Array();
var colors = new Array(20);//长度为20的数组
var colors = new Array("red","blue","green");//包含三个元素的数组
//省略new操作符
var colors = Array(20);
var colors = Array(20);
var colors = Array("red","blue","green");
//使用数组字面值表示
var colors = ["red","blue","green"];
var names = [];//创建空数组
var values = [1,2,];//不要这样!会创建一个包含2或3项的数组
var options = [,,,,,];//不要这样!会创建一个包含5或6项的数组
(2)访问数组成员:
alert(colos[0]);//访问数组成员
colors[2]="black";//修改数组成员
colors[3]="brown";//添加数组成员
var length = colors.length;//获得数组长度
colors.length = 5;//将数组长度修改为5
(3)检测数组:
当只有一个全局执行环境时,可以直接使用instanceof操作符。
当有多个全局执行环境时,不同执行环境的构造方法Array()不同,就不能使用instanceof了,调用Array.isArray(obj)确定是否为数组。
转换方法:
toString()返回以逗号分隔数组成员的字符串。
valueOf()返回的是还是数组。
toLocaleString()返回的还是以逗号分隔的字符串,只是每个数组成员调用的不再是toString(),而是toLocaleString()。
使用join(sep)可以指定sep为分隔符。
(4)栈方法与队列方法:
push(插入元素列表),在数组末尾插入元素,返回插入的个数。
unshift(插入元素列表),在数组起始插入元素,返回插入的个数。
pop(),返回数组末尾元素并从数组中删除。
shift(),返回数组起始元素并从数组中删除。
(5)重排序方法:
reverse(),反转数组项的顺序。
sort(),按照数组元素对应字符串的字典顺序升序排序。
sort(排序函数),按照自定义比较函数排序。
排序函数的格式为
function compare(value1,value2){
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
}
//对于数值类型或者valueOf方法返回数值类型的对象类型,可以采用简化的版本
function compare(value1,value2){
return value1-value2;
}
(6)操作方法:
concat(多个数组或值),按照顺序将数组中的每个元素和指定值添加在原数组的末尾。
slice(起始位置),返回从起始位置及其之后所有元素构成的新数组。
slice(起始位置,结束位置),返回由[起始位置,结束位置)半开半闭区间上的元素构成的新数组。
slice方法中的参数可以是负数,表示倒数第几个位置,等价于正数第(length+参数)个位置。
splice(),删除、插入、替换数组元素,用法如下:
var colors = ["red","green","blue"];
var removed = colors.splice(0,1);//删除第一项
alert(colors);//green,blue
alert(removed);//red
removed = colors.splice(1,0,"yellow","orange");//从位置1开始插入两项
alert(colors);//green,yellow,orange,blue
alert(removed);//空数组
removed = colors.spice(1,1,"red","purple");//从位置1开始先删除1项再插入2项
alert(colors);//green,red,purple,orange,blue
alert(removed);//yellow
(7)索引方法
indexOf(查找对象,起始位置),从起始位置向后查找特定值的位置,起始位置可选,默认为0,查找成功返回所在位置,查找失败返回-1。
lastIndexOf(查找对象,起始位置),从起始位置向前查找特定值的位置,起始位置可选,默认为length-1,查找成功返回所在位置,查找失败返回-1。
(8)迭代方法
every(函数),对数组每一项调用传入函数,并将返回值逻辑与的结果作为最终返回值。
filter(函数),对数组的每一项调用传入函数,并将返回值为true的项构成的新数组作为最终返回值。
forEach(函数),对数组的每一项调用传入函数,最终不返回任何值。
map(函数),对数组的每一项调用传入函数,并将返回值构成的数组作为最终返回值。
some(函数),对数组的每一项调用传入函数,并将返回值逻辑或的结果作为最终返回值。
以上5个方法传入函数的格式为:
function func(item,index,array){
//item表示每一项的值,index表示每一项的下标,array则是数组本身的引用
}
(9)归并方法
reduce(函数,归并初始值),从头开始向后遍历数组,并构建一个最终返回的值,初始值是可选的。
reduceRight(函数,归并初始值),从末尾开始向前遍历数组,并构建一个最终返回的值,初始值是可选的。
传入函数的格式为:
function func(prev,cur,index,array){
//prev是对数组前一项调用本函数的返回值,cur是当前项的值,index是当前项的下标,array则是数组本身的引用
//...
return 下一次调用的prev;//对数组最后一项调用本函数的返回值作为最终的返回值
}
3、Date类型
(1)创建对象:
var now = new Date();//创建当前时间和日期对应的Date对象
var date = new Date(毫秒数);//创建距离unix元年1970年1月1日的毫秒数对应的Date对象
Date.parse(格式化时间字符串),计算某个时间对应的距离Unix元年的毫秒数。字符串的格式与所处的国家和地区有关,格式错误不能解析时返回NaN。
Date.UTC(年,月,日,时,分,秒),同样用于计算距离Unix元年的毫秒数。月份从0开始,采用24小时制。
Date.now(),返回当前时刻距离Unix元年的毫秒数。
(2)继承的方法:
toLocaleString(),toString(),valueOf()
(3)日期格式化方法:
toDateString(),以特定于实现的格式显示日期。
toTimeString(),以特定于实现的格式显示时间。
toLocaleDateString(),以特定于国家和地区的格式显示日期。
toLocaleTimeString(),以特定于国家和地区的格式显示时间。
toUTCString(),以特定于实现的格式显示UTC时间。
(4)日期/时间 get/set方法:
get/setTime、get/setFullYear、get/setUTCFullYear、get/setMonth、get/setUTCMonth、get/setDate、get/setUTCDate、get/setDay、get/setUTCDay、get/setHours、get/setUTCHours、get/setMinutes、get/setUTCMinutes、get/setSeconds、get/setUTCSeconds、get/setMilliSeconds、get/setUTCMilliSeconds、getTimezoneOffset()(地方时与UTC时间相差分钟数)
注意,如果设置秒数达到60,分钟数会加1,其他情况类似。
4、正则表达式类型
(1)创建正则表达式
var expression = /pattern/flags;
var expression = new RegExp("[pattern]","[flags]");
//注意字符串要双重转义
flags可以是g、i、m,分别表示全局模式、忽略大小写、多行模式。
正则表达式的元字符包括:( [ { \ ^ $ | ) ? * + . ] }
相同正则表达式字面值常量会共享同一个RegExp实例,而通过构造函数创建的RegExp实例都是新生成的。每次调用test函数匹配字符串时,都要使用新生成的RegExp实例。
(2)实例属性
global:是否设置了g标志
ignoreCase:是否设置了i标志
multiline:是否设置了m标志
lastIndex:开始搜索下一个匹配项的位置
source:正则表达式的字符串表示,按照字面值常量的格式
(3)实例方法
exec(text),专为捕获组设计,返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。在不设置g标志的情况下,每次调用exec都只返回第一个匹配项的信息;反之,每次调用exec,都会继续向下匹配。
var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);
alert(matches.index);//0
alert(matches.input);//"mom and dad and baby"
alert(matches[0]);//"mom and dad and baby"
alert(matches[1]);//" and dad and baby"
alert(matches[2]);//" and baby"
test(text),只返回匹配是否成功。
valueOf(),只返回正则表达式本身。
(4)RegExp的构造函数属性
长属性名 | 短属性名 | 说明 |
---|---|---|
input | $_ | 最近一次要匹配的字符串,Opera未实现 |
lastMatch | $& | 最近一次的匹配项,Opera未实现 |
lastParen | $+ | 最近一次匹配的捕获组,Opera未实现 |
leftContext | $` | input中lastMatch之前的文本 |
multiline | $* | 是否所有表达式都使用多行模式,IE与Opera均未实现 |
rightContext | $’ | input中lastMatch之后的文本 |
$1,$2,$3,…,$9 | 存储第1,2,…,9个匹配的捕获组 |
5、函数类型
(1)函数的定义
//函数声明
function myFunc(value1,value2){
//...
}
//函数表达式
var myFunc = function(value1,value2){
//...
}
//Function构造函数,不推荐使用
var myFunc = new Function("value1","value2","//...");
(2)函数的性质
没有重载函数,同名函数新的定义将会覆盖就的定义。
函数声明与函数表达式的区别:解析器优先读取函数声明,确保在执行任何代码之前函数可用;函数表达式必须等到解释器执行到代码所在行才能够解释执行。
函数本身也可以作为值来使用,而可以以作为函数的参数或返回值被传递。<