JavaScript是一种脚本语言,主要功能是:动态修改html页面内容,包括创建、删除html页面元素、修改html页面元素的内容、外观、位置、大小等。
数据类型和变量
任何语言都离不开数据类型和变量,虽然JavaScript语言是弱类型的语言,但它一样支持变量声明,变量一样存在作用范围,即有局部变量和全局变量之分。
定义变量的方式
因为JavaScript是弱类型的脚本语言,所以使用变量之前,可以无须定义,想使用某个变量直接使用即可,JavaScript支持两种方式来引入变量:
1)隐式定义:直接给变量赋值
2)显示定义:使用var关键字定义变量
隐式定义的方式简单、快捷、需要使用变量时,直接给变量赋值即可。如:
-
<!DOCTYPE html>
-
<html>
-
<body>
-
<script type=
"text/javascript">
-
<!-- 隐式定义变量a -->
-
a =
"Hello JavaScript"
-
<!-- 使用警告框输出a的内容 -->
-
alert(a);
-
</script>
-
</body>
-
</html>
执行效果
这里涉及到了在html中使用JavaScript,在html页面中嵌入执行JavaScript代码有两种方式:
1)使用javascript:前缀构建执行JavaScript代码的URL。
对于这种方式,所有可以设置URL的地方都可以使用这种方式来执行,当用户触发该URL的时候,javascript:之后的JavaScript代码会获得执行。如:
-
<!DOCTYPE html>
-
<html>
-
<body>
-
<a href="javascript:alert('hello JavaScript')">run javaScript
</a>
-
</body>
-
</html>
2)使用<script.../>元素来包含JavaScript代码,<script.../>元素既可以作为<head.../>子元素,也可以作为<body.../>子元素,上面的代码我们就是使用了第二种方式。
在实际的开发中,为了让html页面和JavaScript脚本更好的分离,我们可以将JavaScript脚本单独保存为一个*.js文件,在html页面倒入该*.js文件即可。导入的语法方式如下:
<script src="test.js" type="text/javascript">
src指定了JavaScript脚本文件所在的URL。OK,说了这么多,继续我们的定义变量。
显示声明的方式说采用var关键字声明变量,声明时变量可以没有初始值,变量的变量数据类型是不确定的。当第一次给变量赋值时,变量的数据类型菜确定下来,而且使用过程中数据类型也可随意改变。
-
<script type=
"text/javascript">
-
//显示声明变量a
-
var a;
-
//给变量a赋值
-
a =
true;
-
//弹出警告框
-
alert(a);
-
</script>
与其它变成语言类似,JavaScript也允许一次定义多个变量,并可以指定初始值,如:
var a, b=0, c;
类型转换
Javascript支持自动类型转换,并且类型转换的功能非常强大。如:
-
<script type="text/javascript">
-
var a =
"3.145"
-
var b = a -
2
-
var c = a +
2
-
alert(b +
"\n" + c)
-
</script>
执行结果
上面的代码中a是字符串,其值为3.145,让a和数值执行减法,则自动执行算术运算,并将a的类型转换为数值;让a和数值执行加法,则a的值转换为字符串,使用加号相当于给字符串进行拼接操作,这就是自动类型转换。
虽然自动类型转换非常方便,但是持续的可读性非常差,而且有时候我们就是希望让字符串和数值进行加法运算,那么就需要使用强制类型转换了。JavaScript提供了以下几个函数来执行强制类型转换。
toString():将布尔值、数值等转换为字符串
parseInt():将字符串、布尔值等转换为整数
parseFloat():将字符串、布尔值等转换为浮点数
如:我们想要让“3.145”+2执行表达式之后结果为5.145
-
<script type=
"text/javascript">
-
var a =
"3.145"
-
var b = a -
2
-
var c =
parseFloat(a) +
2
-
alert(b +
"\n" + c)
-
<
/script>
但是并不是所有的转换都是成功的,对于包含其它字符的字符串,将转换为NaN。对于使用toString()函数将各种类型的值向字符串转换,结果全部是object。
变量
JavaScript是弱类型语言,同一个变量可以一会存储数值,一会存储字符串。变量有个重要的概念:作用范围。根据变量定义的作用范围不同,变量有全局变量和局部变量之分。直接定义的变量是全局变量,全局变量可以被所有的脚本访问,在函数内定义的变量为局部变量,局部变量只能够在函数内有效,如果全局变量和局部变量有相同的变量名,则局部变量将覆盖全局变量。
-
<!DOCTYPE HTML>
-
<html>
-
<body>
-
<script type="text/javascript">
-
var test =
"全局变量";
-
function checkScope() {
-
var test =
"局部变量";
-
alert(test)
-
checkScope();
-
</script>
-
</body>
-
</html>
上面局部变量test覆盖了全局变量,所以执行方法checkScope()之后,会alert局部变量的值。注意:JavaScript的变量没有块范围,比如:
-
<script type="text/javascript">
-
function test(o) {
-
var i =
0;
-
if (
typeof o ==
"object") {
-
var j =
5;
-
for(
var k=
0; k <
10; k++) {
-
document.write(k);
-
}
-
}
-
alert(k +
"\n" + j);
-
}
-
test(
document);
-
</script>
执行结果
即k的值为10,j的值为5,是不是有点奇怪,k和j怎么会有值?因为JavaScript的变量没有块范围,所以变量i,j,k的作用域是整个函数内而不是在对应的块范围内。也正是因为变量没有块范围,所以有时候会出现一些奇怪的结果,在看个例子:
-
<script type="text/javascript">
-
//1
-
var scope =
"全局变量";
-
function test() {
-
//2
-
document.writeln(scope +
"<br />");
-
//3
-
var scope =
"局部变量";
-
//4
-
document.writeln(scope +
"<br />");
-
}
-
test();
-
</script>
执行结果:
undefined
局部变量
第一次使用scope并没有使用全局变量而是undefined,第二次使用局部变量,因为
1、定义全局变量scope
2、使用scope变量,但并不是全局变量,因为全局变量被test函数中scope被覆盖了,局部变量在整体test函数内部都是有效的,但是此时scope还没有被赋值,所以会输出undefined。
3、定义局部变量并赋值,所以输出局部变量。
注意:定义变量使用var和不使用var是有差异的,如果使用var定义变量,那么程序会强制定义一个新变量。如果没有使用var定义变量,系统会优先在当前上下文中搜索是否存在该变量,只有在该变量不存在的前提下,系统才会重新定义一个新变量。
基本数据类型
JavaScript的基本数据类型有5个:
数值类型:包含整数和浮点数
布尔类型:只有true或false两个值
字符串类型:字符串变量必须使用引号括起来,引号可以是单引号,也可以是双引号
undefined类型:专门用来确定一个已经创建但是没有初值的变量
null类型:用于表达某个变量的值为空
数值类型
JavaScript的数值类型不仅包括所有的整型变量也包括所有的浮点型变量,JavaScript语言中的数值都以IEEE 754-1985双精度浮点数格式保存。JavaScript中的数值类型非常丰富,完全支持科学计数法表示,格式如下:
<num1>E<num2>
这种形式的值为:num1*10的num2次方。E为间隔符号,E不区分大小写.
-
<script type="text/javascript">
-
var a,b;
-
a =
5E2;
-
b =
2e-2;
-
alert(a +
"\n" + b);
-
</script>
执行结果
字符串类型
JavaScript的字符串必须是要引号,此处的引号既可以是单引号,也可以是双引号。例如:
a = 'Hello JavaScript' b = "Hello JavaScript"
上面a,b两个变量完全相等,JavaScript没有字符类型。JavaScript以String内建类来表示字符串,String类里包含了一系列方法操作字符串:
String():类似于面向对象语言的构造器,使用该方法可以构造一个字符串
charAt():获取字符串特定索引处的字符
charCodeAt():返回字符串中特定索引处的字符所对应的Unicode值
toUpperCase():返回字符串的长度,JavaScript中文字符算一个字符
toLowerCase():将字符串的所有字母转换为大写字母
fromCharCode():静态方法,直接通过String类调用该方法,将一系列Unicode值转换为字符串
indexOf():返回字符串中特定字符串第一次出现的位置
lastIndexOf():返回字符串中特定字符串最后一次出现的位置
substring():返回字符串的某个子字符串
slice():返回字符串的某个子字符串,功能比substring更强大支持负数参数
match():使用正则表达式搜索目标子字符串
search():使用正则表达式是谁目标子字符串
concat():用于将多个字符串拼接成为一个字符串
split():将某个字符串分割成为多个字符串,可以指定分割符号
replace():将字符串中某个子串以特定字符串替代
-
var a =
"abc";
-
var b = a.length;
-
var c =
String.fromCharCode(
97,
98,
99);
-
-
console.log(b +
"---" + a.charAt(
2) +
"---" + a.charCodeAt(
2) +
"---" + c);
执行如下:
3---c---99---abc
布尔类型
布尔类型的值只有两个:true和false,通常用于逻辑判断。
-
var numberOne =
200
-
var numberTwo =
100
-
-
if (numberOne > numberTwo) {
-
console.log(numberOne);
-
}
else {
-
console.log(numberTwo);
-
}
undefined和null
undefined类型的值只有一个undefined,该值用于表示某个变量不存在,或者没有为其分配值,也用于表示对象的属性不存在。null用于表示该变量的值为空。undefined于null之间的差别在于:undefined表示没有为变量设置值或者不存在而null表示变量有值,只是其值为null。注意:很多时候null和undefined是相等的,即null==undefined,如果要区分,那么需要使用===进行判断。
-
var x , y =
null;
-
if (x ===
undefined) {
-
console.log(
"声明变量后默认值为undefined");
-
}
-
if (x ===
null) {
-
console.log(
"声明变量后默认值为null");
-
}
-
if (x == y) {
-
console.log(
"x: (undefined) == y: (null)");
-
}
-
if (
String.xy ===
undefined) {
-
console.log(
"不存在的属性值默认是undefined");
-
}
-
if (x === y) {
-
console.log(
"x等于y");
-
}
else {
-
console.log(
"x不等于y");
-
}
执行结果:
声明变量后默认值为undefined
x: (undefined) == y: (null)
不存在的属性值默认是undefined
x不等于y
复合类型
复合类型是由多个基本数据类型(也可以包括复合类型)组成的数据体,JavaScript中的复合类型大致有如下3种:
Object:对象
Array:数组
Function:函数
对象
对象是一系列命名变量、函数的集合。其中命名变量的类型既可以是基本数据类型,而可以是复合类型。对象中的命名变量称为属性,而对象中的函数称为方法。对象访问属性和函数的方法都是使用“.”(点)实现。JavaScript是基于对象的脚本语言,它提供了大量的内置对象供用户使用,JavaScript提供了如下常用的内置类。
Array:数组类
Date:日期类
Error:错误类
Function:函数类
Math:数学类,该对象包含相当多的执行数学运算的方法
Number:数值类
Object:对象类
String:字符串类
数组
数组是一系列的变量,于其他强类型语言不同的是,JavaScript中数组元素的类型可以不同。定义应该数组由如下3种方法:
-
var a = [
3,
5,
20];
// 定义的时候初始化数组
-
var b = [];
// 创建一个空数组
-
var c =
new
Array();
// 创建一个空数组
简单使用
-
var a = [
3,
5,
20];
// 定义的时候初始化数组
-
var b = [];
// 创建一个空数组
-
var c =
new
Array();
// 创建一个空数组
-
-
b[
0] =
"你好";
-
b[
1] =
100;
-
b[
2] =
true;
-
-
c[
3] =
true;
-
-
console.log(a +
"\n" + b +
"\n" + c);
执行结果
3,5,20
你好,100,true
,,,true
JavaScript作为动态、弱类型语言,归纳起来,其数组有如下3个特征:
1)JavaScript的数组长度可变,数组长度总等于所有元素索引最大值+1
2)同一个数组中的元素类型可以互不相同
3)访问数组元素时不会产生数组越界,访问并未赋值的数组元素时,该元素的值为undefined。
函数
函数可以包含一段可执行的代码,也可以接收调用者传入参数,正如弱类型语言一样,JavaScript的函数声明中,参数列表不需要数据类型声明,函数的返回值也不需要数据类型声明,函数定义的语法格式如下:
-
function functionName(param1, param2,...) {
-
-
}
简单使用
-
function judgeAge(age)
-
{
-
if (age >
60)
-
{
-
console.log(
"老人");
-
}
-
else
if (age >
40 )
-
{
-
console.log(
"中年人");
-
}
-
else
if (age >
15)
-
{
-
console.log(
"年轻人");
-
}
-
else
-
{
-
console.log(
"儿童");
-
}
-
}
-
-
judgeAge(
26);
//年轻人
虽然调用judgeAge(26)程序能够正常运行,但是如果传入的不是数值那么程序就会有问题,所以最好先对参数类型进行判断,判断变量的数据类型可以使用typeof运算符,该函数用于返回变量的数据类型。
-
function judgeAge(age)
-
{
-
if (
typeof age ===
"number")
-
{
-
if (age >
60)
-
{
-
console.log(
"老人");
-
}
-
else
if (age >
40 )
-
{
-
console.log(
"中年人");
-
}
-
else
if (age >
15)
-
{
-
console.log(
"年轻人");
-
}
-
else
-
{
-
console.log(
"儿童");
-
}
-
}
else
-
{
-
console.log(
"must be number")
-
}
-
}
运算符
JavaScript提供了相当丰富的运算符,包括了赋值运算符、算术运算符、逻辑运算符、位运算符等。
赋值运算符
赋值运算符用于位变量指定变量值,于Java, C类似,也使用“=”作为赋值运算符,通常使用赋值运算符将一个常量值赋给变量。
-
var a =
"JavaScript"
-
var pi =
3.14
-
var visited =
true
也可以使用赋值运算符将一个变量的值赋给另一个变量
var b = a;
算术运算符
JavaScript支持所有的基本算数运算符:
1)加法运算符
-
var a =
5;
-
var b =
10;
-
-
var sum = a + b;
2)减法运算符
-
var a =
5;
-
var b =
10;
-
-
var sub = b - a;
3)乘法运算符
-
var a =
5;
-
var b =
10;
-
-
var sub = b * a;
4)除法运算符
-
var a =
5;
-
var b =
10;
-
-
var sub = b / a;
5)取余运算符
-
var a =
5;
-
var b =
10;
-
-
var sub = b % a;
6)自加(++)运算符
++既可以出现在操作数的左边也可以出现早操作数的右边,但是效果不一样,跟c语言中的自增效果是一样的
-
var a =
5;
-
var b =
10;
-
-
var sum = b++ + a;
-
console.log(sum);
// 15
++在前
-
var a =
5;
-
var b =
10;
-
-
var sum = ++b + a;
-
console.log(sum);
// 16
7)自减(--)
--运算符在前
-
var a =
5;
-
var b =
10;
-
-
var sum = --b + a;
-
console.log(sum);
// 14
--运算符在后
-
var a =
5;
-
var b =
10;
-
-
var sum = b-- + a;
-
console.log(sum);
// 15
位运算符
JavaScript支持的位运算符有如下几种:
&:按位与
|:按位或
~:按位非
^:按位异或
<<:左移位运算符
>>:右移位运算符
>>>:无符号右移位运算符
简单使用
-
console.log(
5 &
9);
//1
-
5 ->
00000101
-
9 ->
00001001
-
=
-
00000001
比较运算符
比较运算符用于判断两个变量或者常量的大小,比较运算的结果是一个布尔值,JavaScript支持的比较运算符如下:
1)>:大于,如果前面变量的值大于后面变量的值,则返回true
2)>=:大于等于,如果前面变量的值大于等于后面变量的值,则返回true
3)<:小于,如果前面变量的值小于后面变量的值,则返回true
4)<=:小于等于,如果前面变量的值小于等于后面变量的值,则返回true
5)==:等于,如果前面两个变量的值相同,则返回true
6)!=:不等于,如果前后两个变量的值不相等,则返回true
7)===:严格等于,前后两个变量的值必须相同并且类型也相同才会返回true。
8)!==:严格不等于,如果前后两个变量的值不相等,或者数据类型不同,都江返回true.
-
if (
5 ==
"5")
-
{
-
console.log(
"==")
-
}
-
if (
5 ===
"5")
-
{
-
console.log(
"===")
-
}
else
-
{
-
console.log(
"not equal")
-
}
执行结果:
==
not equal
逻辑运算符
逻辑运算符用于操作两个布尔值的变量或者常量,主要有以下3个:
&&:与,必须前后两个操作数都为true才返回true,否则返回false
||:或,只要两个操作法中有一个为true,就可以返回true,否则返回false
!:非,只操作一个操作数,如果操作数为true,则返回false,如果操作数为false,则返回true
-
var a =
10;
-
var b =
12;
-
-
if (a >
10 || b <
14)
-
{
-
console.log(
"true")
-
}
三目运算符
三目运算符的格式如下:
(expression) ? if-true-statement : if-false-statement;
运算规则很简单,先对逻辑表达式expression求值,如果逻辑表达式返回true,则执行第二部分的语句,如果逻辑表达式返回false,则返回第三部分的语句。
-
var a =
10;
-
var b =
12;
-
-
var result = (a >
10) ? a : b;
-
console.log(result)
// 12
typeof和instance运算符
typeof前面简单了解过,用于判断某个变量的数据类型,它既可以作为函数来使用,例如:typeof(a),返回变量a的数据类型,也可以作为一个运算符来使用,例如:typeof a 可以返回变量a的数据类型。不同类型参数使用typeof运算符的返回值类型如下:
undefined值:object
null值:object
布尔型值:boolean
数字型值:number
字符串值:string
对象:object
函数:function
-
var a =
5;
//number
-
var b =
true;
//boolean
-
var str =
"hello";
// string
-
console.log(
typeof(a) +
"\n" +
typeof(b) +
"\n" +
typeof(str));
与typeof类似的运算符还有instanceof,该运算符用于判断某个变量是否为指定类的实例,如果是,则返回true,否则返回false。
-
var a = [
3];
-
console.log(a
instanceof
Array);
//true
-
console.log(a
instanceof
Object);
//true,JS中所有类都是object的子类
逗号运算符
逗号运算符允许将多个表达式排在一起,整个表达式返回最右边表达式的值。
-
var a, b, c, d;
-
a = (b =
5, c =
7, d =
10);
-
console.log(a);
// 10
void运算符
void运算符用于强制指定表达式不会返回值
-
var a, b, c, d;
-
a = (b =
5, c =
7, d =
10);
-
console.log(a);
// undefined
语句
语句时JavaScript的基本执行单位.JavaScript要求所有的语句都以分号(;)结束。语句既可以是简单的赋值语句,也可以是算法运算语句,还可以是逻辑运算语句。除此之外还有一些特殊的语句:
异常抛出语句
JavaScript支持异常处理,支持手动抛出异常,JavaScript的所有异常都是Error对象,当JavaScript需要抛出异常总是通过throw语句抛出error对像,语法如下:
throw new Error(errorString);
JavaScript既允许再代码执行的过程中抛出异常,也允许再函数定义中抛出异常,在代码执行过程中,一旦遇到异常,立即寻找对应的异常捕获块(catch块),如果没有对应的异常捕获块,异常将传播给浏览器,程序非正常中止。
-
for (
var i =
0; i <
10; i++) {
-
if (i >
4) {
-
throw
new
Error(
"用户自定义错误");
-
}
-
}
捕获异常
当程序异常出现时,这种异常不管是用户手动抛出的异常还是系统本身的异常,都可以使用catch捕获异常,JavaScript代码运行中一旦出现异常,程序就跳转到对应的catch块,语法如下:
-
try
-
{
-
statement
-
}
-
catch
-
{
-
statement
-
}
-
finally
-
{
-
statement
-
}
上面的捕获语句,finally块是可以省略的,如果指定了finally块,那么finally代码块就会总获得执行的机会。
-
try
-
{
-
for (
var i =
0; i <
10; i++) {
-
console.log(i);
-
if (i>
5)
-
{
-
throw
new
Error(
"error");
-
}
-
}
-
}
-
catch (error)
-
{
-
console.log(
"system wrong: " + error.message);
-
}
-
finally
-
{
-
console.log(
"finally");
-
}
执行结果:
0
1
2
3
4
5
6
system wrong: error
finally
简单总结:
1)JavaScript只有一个异常类,Error,无须在定义函数时声明抛出该异常,所以没有throw关键字
2)JavaScript是弱类型语言,所以catch语句后括号里的异常实例无须声明类型
3)JavaScript只有一个异常类,所以try块最多只能有一个catch块
4)获取异常的描述信息是通过异常对象message属性,而不是通过getMessage()方法实现
with语句
with语句的作用是避免重复书写同一个对象。语法格式如下
-
with(object)
-
{
-
statements
-
}
如果with后的代码块只有一行语句,则可以省略花括号。
流程控制
JavaScript支持的流程控制丰富,有基本的分支语句if,if-else,也有循环语句for,while,for-in等
分支语句
分支语句主要有if和switch语句,其中if有三种格式:
-
// 形式1
-
if (expression)
-
{
-
statement
-
}
-
-
// 形式2
-
if (expression)
-
{
-
statement
-
}
-
else
-
{
-
statement
-
}
-
-
//形式3
-
if (expression)
-
{
-
statement
-
}
-
else
if (expression)
-
{
-
statement
-
}
-
else
-
{
-
statement
-
}
通常情况下不要省略if、else、else if后执行块的花括号,但是如果语句执行块只有一行代码时,则可以省略花括号。
-
var a =
5;
-
-
if (a >
4)
-
console.log(
"a大于4");
-
else
-
console.log(
"a小于4");
switch语句的语法如下:
-
switch (expression)
-
{
-
case condition
1: statemnt
-
break;
-
case condition
2: statemnt
-
break;
-
default: statemnt
-
}
先执行expression表达式,然后依次匹配条件condition1,condition2,遇到了匹配的条件就执行相应的代码,如果前面的条件都没有正常匹配,则执行default后的执行体。
-
function inputScore(score)
-
{
-
switch (score)
-
{
-
case
'A':
console.log(
"优秀");
-
break;
-
case
'B':
console.log(
"良好");
-
break;
-
case
'C':
console.log(
"及格");
-
break;
-
case
'D':
console.log(
"不及格");
-
break;
-
default:
console.log(
"error");
-
}
-
}
注意2点:
1)JavaScript的switch语句可以省略case块后面的break;如果省略了,那么就会一直执行case之后的代码,直到遇见break语句为止
2)switch语句的条件变量不仅可以是数值类型也可以是字符串类型。
while语句
while语句的语法格式如下:
-
while (expression)
-
{
-
statement
-
}
当循环体只有一行语句时,循环体的花括号可以省略,while循环语句的作用是:先判断expression逻辑表达式的值,当expression表达式的值为true时,执行循环体,如果微false则结束循环。但是要注意:一定要有false的时候,不然会造成死循环。
do-while循环
do-while循环跟while的区别在于:while是先判断循环条件,只有条件为真才会执行循环体,但是do-while则先执行循环体,然后判断循环条件,如果条件为真,则执行下一次循环。否则中止循环。
-
do
-
{
-
statement
-
}
-
while (expression)
for循环
for循环是常用的循环语句,大部分情况下,for循环可以代替while循环、do-while循环。基本语法格式如下:
-
for (
var i =
0; i < Things.length; i++) {
-
}
循环中两个分号分开了三个语句,其中第一个语句是循环的初始化语句,每个循环语句只会执行一次,而且完全可以省略,因为初始化语句可以放在循环语句之前完成,第二个语句是一个逻辑表达式,用于判断是否执行下一次循环,第三个语句是循环体执行完后最后执行的语句。for in 循环
for in循环的本质是一种foreach循环,它主要有两个作用:
1)遍历数组里的所有数组元素
2)遍历JavaScript对象的所有属性
语法格式:
-
for (index
in object)
-
{
-
statement
-
}
如果循环体只有一行代码,则可以省略循环体的花括号,当遍历数组时,for in 循环的循环计数器是数组元素的索引值。
break和continue
break和continue都可用于中止循环,区别在于continue只是中止本次循环,接着开始下一次循环,而break则是完全中止整个循环,开始执行循环体后面的语句。
函数
JavaScript是一种基于对象的脚本语言,JavaScript代码复用的单位是函数,但它的函数比结构化程序设计语言的函数功能更加丰富,JavaScript语言中的函数是“一等公民”,它可以独立存在,而且JavaScript的函数完全可以作为一个类使用,而且它还是该类唯一的构造器,函数本身也是一个对象,函数本身是Function实例。
定义函数的3种方式
JavaScript是弱类型语言,因此定义函数时,既不需要声明函数的返回值类型,也不需要声明函数的参数类型。
定义命名函数
定义命名函数的语法格式:
-
function functionName(parameter-list)
-
{
-
statements
-
}
-
function greeting(name)
-
{
-
console.log(
"hello " + name);
-
}
-
greeting(
"Jack");
//hello Jack
函数最大作用是提供代码复用,所以应该将需要重复使用的代码块定义成为函数,提供更好的代码复用。函数可以有返回值也可以没有返回值,函数的返回值使用return语句返回,在函数的运行过程中,一旦遇到了第一条return语句,函数就返回返回值,函数运行结束。
定义匿名函数
JavaScript提供了定义匿名函数的方式,语法格式如下:
-
function(parameter list)
-
{
-
statements
-
};
这种函数定义语法无须指定函数名,而是将参数列表紧跟function关键字,在函数定义语法的最后不要忘记紧跟分号(;)。当通过这种语法格式定义函数之后,实际上就是定义了一个函数对象(即Function实例),接下来可以将这个对象赋给另一个变量,之后可以通过变量来执行调用函数。
-
var f =
function(name)
-
{
-
console.log(name);
-
};
-
f(
"Jack");
//Jack
使用Function类匿名函数
JavaScript提供了Function类,该类可以用于定义函数,Function类的构造器的参数个数可以不受限制,Function可以接受一系列的字符串参数,其中最后一个字符参数是函数的执行体,执行体的各语句可以以分号(;)隔开,而前面的各字符串参数则是函数的参数。
-
var fun =
new
Function(
'name',
"console.log(name);");
-
fun(
'hua');
上面代码使用了new Function语法定义了一个匿名函数,并将匿名函数赋给fun变量,从而允许通过fun来访问匿名函数。调用Function类的构造器来创建函数虽然能够明确地表示创建一个Function对象,但由于Function()构造器的最后一个字符代表函数执行体,当函数执行体的语句很多时,Function的最后一个参数将变得十分臃肿,因此可读性也差。
局部变量和局部函数
在函数里定义的变量成为局部变量,在函数外定义的变量成为全局变量,如果局部变量和全局变量的变量名相同,则局部变量会覆盖全局变量,局部变量只能够在函数里访问,而全局变量可以在所有的函数里面访问。局部函数即在函数里面定义的函数,并且在在函数内部有效。
-
function outer()
-
{
-
function inner1()
-
{
-
console.log(
"inner1");
-
}
-
-
function inner2() {
-
console.log(
"innner2");
-
}
-
inner1();
-
inner2();
-
}
-
outer();
// inner1 innner2
函数、方法、对象和类
函数:就像JavaScript的方法一样,这个函数可以被调用,JavaScript的函数不仅是一个函数更是一个类
方法:定义一个函数时,该函数通常都会附加给某个对象,作为该对象的方法
类:在定义函数的同时,也得到了一个与函数同名的类
下面程序定义了一个Person函数,也就是定义了一个Person类,该Person函数也会作为Person类的唯一构造器。
-
function Person(name, age)
-
{
-
this.name = name;
// 将参数name值赋值给name属性
-
this.age = age;
// 将参数age赋值给age属性
-
-
this.info =
function() // 为info创建一个匿名函数
-
{
-
console.log(
"My name is: " +
this.name);
-
console.log(
"age = " +
this.age);
-
};
-
}
-
-
var p =
new Person(
"Jack",
26);
-
p.info();
-
-
// My name is: Jack
-
// age = 26
上面程序中使用了this关键字,被this关键字所修饰的变量不再是局部变量,它是该函数的实例属性。而且info属性是一个函数,即JavaScript定义的函数可以被赋值给对象,作为对象的方法,如果没有明确指定赋值的对象将被赋值到window对象上,作为window对象的方法。
函数的实例属性和类属性
前面也讲到了JavaScript函数不仅仅是一个函数,而且是一个类,该函数还是此类唯一的构造器,只要在调用函数时使用new关键字,就可以返回一个Object,这个Object不是函数的返回值,而是函数本身产生的对象。因此在JavaScript中定义的变量不仅有局部变量,还有实例属性和类属性两种。根据函数中声明变量的方式,函数中的变量有3种:
局部变量:在函数中以普通方式声明的变量,包括以var或者不加任何前缀声明的变量
实例属性:在函数中以this前缀修饰变量
类属性:在函数中以函数名为前缀修饰变量
-
function Person(name, age)
-
{
-
this.name = name;
// 将参数name值赋值给name属性
-
Person.age = age;
// 将参数age赋值给age属性
-
-
this.info =
function() // 为info创建一个匿名函数
-
{
-
console.log(
"My name is: " +
this.name);
-
console.log(
"age1 = " +
this.age);
-
console.log(
"age2 = " + Person.age);
-
};
-
}
-
-
var p =
new Person(
"Jack",
26);
-
p.info();
-
-
p.age =
"30";
-
p.info();
-
-
// result:
-
My name is: Jack
-
age1 =
undefined
-
age2 =
26
-
-
My name is: Jack
-
age1 =
30
-
age2 =
26
可以看到刚刚开始没有实力属性age,但是当我们执行p.age = "30";之后,自动为对象增加了age属性,这是因为JavaScript是动态语言,它允许为对象增加属性和方法,当我们直接为对象的某个属性赋值时,即可视为给对象增加属性。
调用函数的3种方式
定义一个函数之后,JavaScript提供了3种方式来调用函数。
直接调用函数
直接调用函数是最常见的方式,这种方式直接以函数附加的对象作为调用者,在函数括号内传入参数来调用函数,前面已经大量使用了。
以call()方法来调用函数
直接调用函数的方式简单,但是不够灵活,有时候调用函数时需要动态地传入一个函数引用,此时为了动态的调用函数,就需要使用call()方法来调用函数。
假如我们需要定义一个形如each(array, fn)的函数,这个函数可以自动迭代处理array数组元素,而fn函数则负责对数组元素进行处理,此时需要在each函数中调用fn函数,但目前fn函数并未确定,因此无法采用直接调用的方式来调用fn函数,需要通过call()方法来调用函数。
-
var each =
function(array, fn)
-
{
-
for (
var index
in array) {
-
fn.call(
null, index, array[index]);
-
}
-
};
-
-
each([
5,
10 ,
3],
function(index, element)
-
{
-
console.log(
"第" + index +
"个元素是:" + element +
"\n");
-
});
上面的代码使用call()动态的调用函数,call()方法的语法格式如下:
函数引用.函数(调用者,参数1,参数2...),
这里也可以得到直接调用函数与通过call()方法调用函数的关系:
调用者.函数(参数1,参数2...) = 函数.call(调用者,参数1,参数2...)
apply()方法调用函数
apply()方法与call()方法功能基本相似,它们都可以动态地调用函数。apply()与call()的区别如下:
1)通过call()调用函数时,必须在括号中详细的列出每个参数
2)通过apply()动态地调用函数时,可以在括号中以arguments来代表所有参数。
-
var example =
function (num1, num2)
-
{
-
myfun.apply(
this,
arguments);
-
};
-
example(
20,
40);
// 直接调用
-
example.apply(
null, [
10,
15]);
// 使用apply方法调用函数
函数的参数
对于基本类型参数,JavaScript采用值传递的方式,当通过实参调用函数时,传入函数里的并不是实参本身,而是实参的副本,因此在函数中修改参数值并不会对实参有任何影响。
-
function change(paramter)
-
{
-
paramter =
20;
-
console.log(paramter);
//20
-
}
-
var x =
10;
-
change(x);
-
console.log(x);
//10
对于复合类型的参数,实际上采用的依然是值传递的方式
-
function changeAge(person)
-
{
-
person.age =
10;
-
console.log(person.age);
// 10
-
person =
null;
// 将person对象设置为null
-
-
}
-
var person = {
age:
5};
// 使用JSON语言创建对象
-
changeAge(person);
-
console.log(person.age);
// 10
-
console.log(person);
// { age: 10 }
上面代码和结果可知,person对象的age属性其值是发生了改变,但是person对象被设置为null之后却依然存在,这表明person对象本身并没有被传入函数中,传入的只是person对象的副本而已,这里可能很容易让人混淆。
复合类型的变量本身并未持有对象本身,复合类型的变量只是一个引用,该引用指向实际的JavaScript对象,当把person复合类型的变量传入changeAge()函数时,传入的依然是person变量的副本,只是该副本和原person变量指向同一个JavaScript对象,因此不管是修改副本所引用的JavaScript对象,还是修改person变量所引用的JavaScript对象,实际上修改的是同一个对象。
空参数
-
function changeAge(person)
-
{
-
if (
typeof person ==
'object')
-
{
-
person.age =
10;
-
console.log(person.age);
// 10
-
}
-
else
-
{
-
console.log(
"参数类型不符合");
-
}
-
}
-
changeAge();
//参数类型不符合
由上面的代码可知,函数声明中包含了一个参数,但是调用函数时并没有传入任何参数,这种情况对于强类型语言,如:Java,C那是绝对不允许的,但是对于JavaScript却没有任何语法问题,因为JavaScript会将没有传入实参的参数值自动设置为undefined。
由于JavaScript调用函数时对传入的实参并没有要求,即使定义函数时声明了多个形参,调用函数时也并不强制要求传入相匹配的实参。因此JavaScript没有所谓的函数“重载”,对于JavaScript而言函数名就是唯一的标识。