3.6 语句
3.6.1 if语句
- 语法:
if(condition) statement1 else statement2
- 注意:condition可以是任何值。ECMAScript会自动调用Boolean()转换函数
3.6.2 do-while语句
3.6.3 while语句
3.6.4 for语句
注意:在循环内部定义的变量可以在外部访问
3.6.5 for-in语句
语法:
for (property in expression) statement
-
示例:
for (var proName in window) { ... }
在这个例子中,使用for-in循环来显示BOM中window对象的所有属性。每次执行循环时,都会将对象中存在的一个属性名赋值给变量proName。这个过程会一直持续到对象中的所有属性都被枚举一遍为止。
ECMAScript对象的属性没有顺序。因此for-in循环输出的属性名的顺序不可预测
如果表示要迭代的对象的变量值为null或undefined,for-in语句会抛出错误。ECMAScript5更正了这一行为;对这种情况不再跑出错误(不执行循环体)。嫁衣先检测该对象的值是不是null或undefined
3.6.6 label语句
语法:label:statement
-
示例:
start:for(var i = 0; i < count; i++){ alert(i); }
3.6.7 break和continue语句
3.6.8 with语句
语法:with (expression) statement
作用:将代码的作用域设置到一个特定的对象中
-
示例:
var qs = location.search.substring(1);
可以改为
with(location){
var qs = search.substring(1);
}
在with语句的代码块内部,每个变量首先被认为是一个局部变量,而如果在局部环境中找不到该变量的定义,就会查询location对象中是否有同名的属性。如果发现了同名属性,则以location对象属性的值作为变量的值。严格模式下不允许使用with语句。with语句会导致性能下降,不建议使用with语句。
3.6.9 switch语句
- expression可以使用任何数据类型
- case的值不一定是常量,可以是变量甚至是表达式
- switch语句在比较时使用的是全等操作符,因此不会发生类型转换
3.7 函数
严格模式对函数的一些限制:1.不能把函数命名为eval或arguments;2.不能把参数命名为eval或arguments;3.不能出现两个明明参数同名的情况
3.7.1 理解参数
ECMAScript中的参数在内部都是用一个数组来表示的。ECMAScript不介意传几个参数,也不介意参数的数据类型。在函数体内可以通过arguments对象来访问这个参数数组。
比如第一个参数就是arguments[0]
arguments对象的length属性可以获知有多少个参数传递给了函数
-
arguments的值永远和对应明命名参数的值保持同步
function doAdd(num1, num2){ ... }
这里当改变arguments[0]=1后,num1就会自动改变。但是在函数内修改num1并不会使arguments[0]改变。另外,如果只传一个参数,修改arguments[1]也不会改变num2的值
3.7.2 没有重载
如果定义了两个名字相同的函数。就以后定义的函数为准
3.8 小结
- 基本数据类型:Undefined、Null、Boolean、Number、String
- 没有定义整数和浮点数。Number类型用于表示所有数值
- 复杂数据类型:Object
- 严格模式为这门语言中容易出错的地方加了限制
- 算术操作符、布尔操作符。关系操作符、相等操作符、赋值操作符
- if、for、switch
- 无须指定函数返回值
- 未指定返回值的函数返回的是一个特殊的undefined值
- 没有函数签名的概念
- 可以向ECMAScript函数传递任意数量的参数,通过arguments对象来访问这些参数
- 不能重载
第4章 变量、作用域和内存问题
4.1 基本类型和引用类型的值
4.1.2 复制变量值
- 如果一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上
- 如果是引用类型,两个变量将引用同一个对象。
4.1.3 传递参数
所有参数都按值传递。基本类型的传递和基本类型变量的复制一样,引用类型的传递和引用类型变量的复制一样
4.1.4 检测类型
- 检测基本数据类型:typeof操作符
- 检测引用类型:instanceof操作符
person instanceof Array;//变量person是Array吗
person instanceof Object;//变量person是Object吗
4.2 执行环境及作用域
一个函数就是一个执行环境
4.2.1 延长作用域链
- try-catch的catch语句块:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明
- with语句:会将指定的对象添加到作用域链中
4.2.2 没有块级作用域
注意不是像C语言那样用{}来区分作用域
比如说for(var i = 0; i < 5; i++)
这里的i在外面也能访问。
-
声明变量
- 使用var声明的变量会自动被添加到最接近的环境中。在函数内部就是局部环境,with语句中就是函数环境。
- 不使用var声明,变量自动添加到全局环境
-
查询标识符
- 从作用域链前端开始,向上逐级查询
4.3 垃圾收集
4.3.1 标记清除
- 最常用的垃圾收集方式
- 给所有存储在内存中的变量加上标记,再去掉环境中的变量以及被环境中的变量引用的标记
4.3.2 引用计数
- 不太常见
- 跟踪记录每个值被引用的次数
- 循环引用会导致错误
4.3.3 性能问题
- 确定垃圾收集的时间间隔
4.3.4 管理内存
- 一旦数据不再有用,最好通过将其值设置为null来释放其因引用(适用于大多数全局变量和全局变量的属性)
4.4 小结
基本类型和引用类型:
- 基本类型值保存在栈内存中,在内存中占据固定大小的控件
- 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本
- 引用类型的值是对象,保存在堆内存中
- 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针
- 从一个变量向另一个变量复制引用类型的值,复制的其实是指针。两个变量最终都指向同一个对象
- typeof,instanceof
执行环境:
- 全局执行环境、函数执行环境
- 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链
- 局部环境有权访问其包含(父)环境
- 全局环境只能访问全局环境
- 变量的执行环境有助于确定应该合适释放内存
垃圾收集:
- 离开作用域的值将被自动标记为可以回收
- 标记清除
- 引用计数。JavaScript引擎目前不再使用这种算法;但在IE中访问非原生JavaScript对象(如DOM)时,这种算法仍然可能导致问题
- 循环引用
- 及时解除变量的引用
第5章 引用类型
5.1 Object类型
- 创建Object实例
new
-
对象字面量表示法
var person = { //花括号表示表达式的开始 name : "Nicholas", //逗号分隔不同的属性 age : 29 //最后一个属性不能加逗号 }
注意:
属性名可以用字符串表示。
-
可以留空:
var person = {}; //与new一个对象相同 person.name = "Nicholas"; person.age = 29;
最适合需要向函数传入大量可选参数的情形
用这个方法时不会调用构造函数
最好的做法是对那些必需值使用命名参数,使用对象字面量来封装多个可选参数
- 访问对象属性:一般使用点表示法
- 方括号:
person["name"]
-
优点:可以通过变量来访问属性
var propertyName = "name"; alert(person[propertyName]);
属性名中包含会导致语法错误的字符,或属性名使用的是关键字或保留字
-
- 点表示法:
person.name
- 方括号:
5.2 Array类型
ECMAScript数组的每一项可以保存任何类型的数据
大小可以动态调整
创建数组:
- new
var colors = new Array();
var colors = new Array(20);
var colors = new Array("red","blue","green");
- 也可以省略new
- 数字字面量表示法
var colors = ["red","blue","green"];
var colors = [];
- 不要在最后加逗号
读取和设置数组:
- 方括号:
colors[0];
length属性:
不是只读的。所以通过设置这个属性。可以从数组的末尾移除项或向数组中添加新项
-
不存在的项是undefined
var colors = ["red","blue","green"]; colors[99] = "black";
这时候length会变成100,colors[3]——colors[98]都是undefined
5.2.1 检测数组
- Array.isArray()方法
- 一个全局作用域可以用instanceof操作符
5.2.2 转换方法
- toString():返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。调用的是数组每一项的toString()
- valueOf():返回数组。
- toLocaleString():也是逗号分隔。调用的是每一项的toLocaleString()
注意:
- alert()调用的是每一项的toString()
- 想要改变分隔符可以用join()方法:
people.join("||");
5.2.3 栈方法
push()方法和pop()方法实现的是类似栈的行为(后进先出,在顶部操作)
- push():可以接收任意数量的参数,并逐个添加到数组末尾,返回修改后的数组长度
- pop():从数组末尾移除最后一项,返回移除的项
5.2.4 队列方法
队列:在末端添加项,从前端移除项。shift()和push()模拟了队列的行为。unshift()和pop()模拟的事相反方向的队列
- shift():移除数组的第一个项并返回该项
- unshift():在数组前端添加任意个项并返回新数组长度
5.2.5 重排序方法
reserve():反转数组原来的顺序,返回排序后的数组
sort():先调用每一项的toString(),再比较得到的字符串。返回排序后的数组
-
最佳方案:给sort()方法一个比较函数作为参数
var values = [0, 1, 5, 10, 15]; values.sort(compare); functiong compare(value1, value2){ return value2 - value1; //降序 }
5.2.6 操作方法
concat():先创建当前数组的一个副本然后将接收到的参数添加到这个副本的末尾,返回新构建的数组
-
slice():基于当前数组的项创建新数组。接收两个参数:返回项的起始位置和结束位置。返回起始和结束位置之间的项(不包括结束位置的项)
- 如果参数出现负数,则length+该参数
- 如果结束位置<起始位置,则返回空数组
-
splice():主要用途是向数组的中部插入项
- 删除:2个参数:要删除的第一项的位置和要删除的项数。
- 插入:3个参数:起始位置、0(要删除的项数)和要插入的任意数量的项。
splice(2,0,"red","green")
- 替换:3个参数:起始位置、要删除的项数和要插入的任意数量的项
- 返回一个数组,包含从原数组中删除的项。如果没有删除,则返回一个空数组
5.2.7 位置方法
- indexOf()和lastIndexOf()
- 参数:要查找的项和表示查找起点位置(可选)的索引
- indexOf()从数组的开头开始找,lastIndexOf()从末尾开始找
- 返回值:要查找的项在数组中的位置。-1表示没找到
- 参数与项严格相等(全等操作符)
5.2.8 迭代方法
5个迭代方法的参数:要在每一项上运行的函数和运行该函数的作用域对象
传入函数接收的参数:数组项的值、该项在数组中的位置和数组对象本身
以下方法都不改变数组中包含的值
every():如果传入的函数对每一项都返回true,则返回true
filter():返回 能返回true的项组成的 数组
forEach():数组的每一项都运行给定函数。没有返回值
map():返回每次函数调用的结果组成的数组
-
some():给定函数对任一项返回true,则返回true
var numbers = [1, 2, 3, 4, 5]; var everyResult = numbers.every(function(item, index, array){ return (item>2); });
5.2.9 缩小方法
reduce()和reduceRight()的参数:一个在每一项上调用的函数和作为缩小基础的初始值(可选)。ruduce()从第一项开始,reduceRight()从最后一项开始
传入函数的参数:前一个值,当前值,项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。
var values=[1, 2, 3, 4, 5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
5.3 Date类型
自1970.1.1开始经过的毫秒数
创建日期对象:var now = new Date();//自动获得当前时间,是一个字符串
Date.parse():
- 参数:表示日期的字符串
- 返回:相应日期的毫秒数
- 格式:2/28/2017、February 28,2017、Tuesday February 28 2017 00:00:00 GMT-0700、2017-02-28T00:00:00
- 字符串不正确返回NaN
- 直接将字符串传给Date()函数,后台以同样会调用Date.parse()
Date.UTC():
- 参数:年份、基于0的月份(0-11)、月中的哪一天(1-31)、小时数(0-23)、分钟、秒、毫秒。年和月必须
- 默认天数1,其他0
Date.now():返回调用这个方法时的日期和时间的毫秒数
还有一种方法是用+操作符与把Date()对象转换成毫秒数
5.3.1 继承的方法
- toLocaleString():按照与浏览器相适应的格式返回日期和时间
- toString():通常返回带有时区信息的日期和时间,一般以军用时间表示(小时是0-23)
- valueOf():返回毫秒数
5.3.2 日期格式化方法
- toDateString()
- toTimeString()
- toLocaleDateString()
- tolocalTimeString()
- toUTCString()
5.3.3 日期/时间组件方法
很多..很多..
5.4 RegExp类型
正则表达式的两种创建方法
-
字面量
语法:
var expression = / pattern / flags ;
-
flag:
- g:global。全局模式
- i:case-insensitive。不区分大小写模式
- m:multiline:多行模式。
注意转义
-
RegExp构造函数
- 参数:要匹配的字符串模式,可选的标志字符串
- 要双重转义
正则表达式字面量始终共享同一个RegExp实例,而构造函数创建的每一个新RegExp实例都是一个新实例。使用正则表达式字面量必须像直接调用RegExp一样,每次都创建新的RegExp实例
5.4.1 RegExp实例属性
- global:是否设置g
- ignoreCase:是否设置i
- lastIndex:整数,表示开始搜索下一个匹配项的起始位置
- multiline:是否设置m
- source:正则表达式的字符串表示,按照字面量形式
5.4.2 RegExp实例方法
-
exec()
- 参数:要应用模式的字符串
- 返回:包含第一个匹配项信息的数组。没有匹配项则返回null
- 返回数组的两个额外属性:index(位置)、input(输入的字符串)
- 返回的书组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串
- 不设置g时,每次都从0开始查询。设置g时,会接着上次查询。但是都是只返回一个匹配项
-
test()
- 参数:字符串
- 用来测试字符串和某个模式是否匹配
toLocaleString()/toString():返回正则表达式的字面量
valueOf():返回正则表达式本身
5.4.3 RegExp构造函数属性
- input:最近一次要匹配的字符串
- leftContext:字符串匹配项左边的部分
- RightContext:字符串匹配项右边的部分
- lastMatch:最近一次的匹配项
- lastParen:最近一次的匹配的捕获组
- multiline:是否所有表达式都使用多行模式
- $1——$9:第1-9个匹配的捕获组
5.4.4 模式的局限性
不支持许多高级正则表达式的特性
5.5 Function类型
函数是对象,函数名是指针。每个函数都是Function类型的实例。一个函数可能会有多个名字
定义函数:
- function sum (num1, num2){
...
} - var sum = function(num1, num2){
...
}
5.5.1 没有重载
后定义的将覆盖前面的
5.5.2 函数声明与函数表达式
-
函数声明:
- 形式:
function sum(num1, num2){...}
- 函数声明会提前,解析器会将函数声明提前添加到执行环境
- 形式:
-
函数表达式:
- 形式:
var sum = function(num1, num2){...};
- 在执行到函数所在语句之前,变量sum不会保存对函数的引用
- 形式:
5.5.3 作为值的函数
可以像传递参数一样把一个函数传递给令一个函数。可以将一个函数作为令一个函数的结果来返回
5.5.4 函数内部属性
-
arguments
- 类数组对象,包含着传入函数中的所有参数
- callee:指向拥有这个arguments对象的函数
this
caller:保存调用当前函数的函数的引用。如果在全局模式下,则是null
5.5.5 函数属性和方法
-
属性
- length:表示函数希望接收的命名参数的个数
- prototype
-
方法
-
Functin.apply(obj, args)
- 参数:
- obj:这个对象将代替Function类里的this对象
- args:这个是数组,它将作为参数传递给Function(也可以是arguments)
- 参数:
-
call()
- 与apply()类似。只是传递给函数的参数必须逐个列举出来。比如
sum.call(this, num1, num2);
- 与apply()类似。只是传递给函数的参数必须逐个列举出来。比如
作用:这两种方法最主要的就是能扩充函数的作用域。第一个参数可以是this、window等等
-
bind()
- 也是同理,设置函数的this值的
var oSayColor = sayColor.bind(o);
- 以上代码会将函数oSayColor的this值设为对象o
toLocaleString()、toString()、valueOf()返回函数的代码
-
5.6 基本包装类型
要从内存中读取字符串的值时,后台会自动:1.创建String类型的一个实例。2.在实例上调用指定的方法。3.销毁这个实例
引用类型和基本包装类型的主要区别就是对象的生存期。new一个实例在执行流离开作用域前一直保存在内存中;而基本包装类型的对象是自动创建的,只存在一行代码的执行瞬间,然后立即销毁
5.6.1 Boolean类型
Boolean类型的实例。valueOf()返回基本类型值true或false。toString()返回字符串"true"或"false"
5.6.2 Number类型
- valueOf():返回基本类型的数值。另外两个返回字符串类型的数值
- toFixed():按照指定的小数位返回数值的字符串表示(四舍五入)
- toExponential():返回e表示法表示的数值的字符串形式。接收一个小数位数的参数(四舍五入)
- toPercision():返回数值的最合适格式。接收一个表示数值的所有数字的位数的参数。也就是说会自动决定调用toFixed()还是toExponential()
5.6.3 String类型
toString()等三个方法都返回字符串值
属性:length
-
字符方法
- charAt()、charCodeAt()
- 参数:字符位置
- 返回:前者单字符字符串,后者返回字符编码
- 方括号也可以访问单个字符
- charAt()、charCodeAt()
-
字符串操作方法
-
concat()
- 参数:任意多个字符串
- 作用:拼接字符串
- 返回:拼接得到的新字符串,原字符串保持不变
- 一般还是用+操作符
-
slice()、substr()、substring()
- 参数:第一个参数指定子字符串的开始位置。第二个参数(可选)slice()和substring()指定子字符串最后一个字符后面的位置;substr()指定返回的字符个数
- 作用:基于字符串创建新字符串
- 返回:新的字符串,原字符串不变
- 在传入负值的情况下。slice()负值+length;substr()第一个参数+length,第二个=0;substring()都=0
-
-
字符串位置方法
- indexOf()、lastIndexOf()
- 参数:要搜索的子字符串,从哪个位置搜索(可选)
- 返回:子字符串位置。没有则返回-1
- 一个从前往后,一个从后往前
- indexOf()、lastIndexOf()
-
trim()
- 作用:创建一个字符串副本,删除前置和后置空格
- 返回:新字符串
- trimLeft()和trimRight()分别删除开头和结尾
字符串大小写转换方法
toLowerCase()、toLocaleLowerCase()、toUpperCase()、toLocaleUpperCase()-
字符串的模式匹配方法
-
match()
- 参数:一个。正则表达式或RegRxp对象
- 返回:和RegExp的exec()类似,返回一个数组
-
search()
- 参数:一个。正则表达式或RegRxp对象
- 返回:第一个匹配项的索引。没有则返回-1
- 始终从开头向后查找
-
replace()
- 参数:两个。RegExp对象或字符串,字符串或一个函数
- 如果第一个是字符串,那么只替换第一个字符串。
- 第一个参数提供一个正则表达式,替换所有字符串,记得指定g
- 如果第二个参数是字符串,可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中
- 传入的函数的参数:模式的匹配项,模式匹配项的位置,原始字符串。返回字符串
-
split()
- 参数:字符串或RegExp对象,数组的大小(可选)
- 作用:基于指定的分隔符将一个字符串分割成多个子字符串,将结果放在一个数组中
- 返回:数组
-
-
localeCompare()
- 如果字符串在字母表中排在字符串参数之前,返回一个负数
- 如果相等,返回0
- 如股票在之后,返回正数
-
fromCharCode()
- 参数:一或多个字符编码
- 返回:字符串
- 和charCodeAt()相反的操作
- 这是一个String本身的静态方法
HTML方法
尽量不用
5.7 单体内置对象
5.7.1 Global对象
-
URI编码方法
- encodeURI()、enceodeURIComponent()
- 前者主要用于整个URI,不会对本身属于URI的特殊字符进行编码
- 后者主要用于URI的某一段,会对任何非标准字符进行编码
- decodeURI()、deceodeURIComponent()
-
eval()
- 在eval()中创建的任何变量或函数都不会被提升。
- eval()就是用来解析ECMAScript语句的。
Global对象的属性
很多-
window对象
-
访问Global对象的两种方法
- 就是访问window。在全局中声明的所有变量和函数,都是window对象的属性
-
用this
var global = function(){ return this; }();
-
5.7.2 Math对象
Math对象的属性
很多-
min()和max()方法
参数:任意多个
-
数组中的最大值或最小值:
var values = [1, 2, 3, 4, 5]; var max = Math.max.apply(Math, values); //apply是一个很有用的东西!
-
舍入方法
- Math.ceil():向上舍
- Math.floor():向下舍
- math.round():四舍五入
-
random()
- 返回0-1间的一个随机数,不包括0和1
- 值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)
其他方法
很多
5.8 小结
引用类型与类相似,但实现不同
Object
Array类型是一组值的有序列表,同时提供了操作和转换这些值的功能
Date
RegExp
函数实际上是Function类型的实例,因此函数也是对象
-
JavaScript中的基本类型值可以被当作对象访问。三种基本包装类:Boolean、Number、String。
- 每个包装类型映射到同名的基本类型
- 读取模式下访问基本类型,就会创建对应基本包装类型的一个对象
- 包装对象会立即被销毁
内置对象:Global、Math