web前端之javascript详解
函数、初始作用域
函数的诞生——声明函数的基本作用及形式
(1)基本作用:比如一下代码
if (1 > 0){
document.write(‘a’)
document.write(‘b’)
document.write(‘c’)
}
if (2 > 0){
document.write(‘a’)
document.write(‘b’)
document.write(‘c’)
}
if (3 > 0){
document.write(‘a’)
document.write(‘b’)
document.write(‘c’)
}
……
比如以上代码,我们满足了这些条件后就要执行很多功能,而且这个条件满足了很多次,但是我们这么写的话代码的偶合(重复)程度很高,这种代码我们把它叫做低效代码,我们编程讲究的是高内聚弱偶合,就是把相同的代码抽出来放在一个匣子里,我们每次再用的时候直接调用这个匣子就行了,不用每次都自己写,这样也会方便许多。这个可以封装成匣子的东西我们叫做函数
就是一个函数可以存放很多语句,当我们需要时直接调用就行了。
(2)函数的形式及调用函数
例如上面代码我们可以简化为:
function test(){
document.write(‘a’)
document.write(‘b’)
document.write(‘c’)
}
if (1 > 0){
test();
}
if (2 > 0){
test();
}
if (3 > 0){
test();
}
函数的基本形式:先是一个关键字function,然后后面跟一个函数名(函数名的名门规则和变量名差不多,不能以数字开头,可以用下划线等等,但是,不管是函数名还是变量名,如果有多个单词拼接,必须遵循小驼峰命名规则,即第一个单词首字母小写,以后单词首字母大写,比如theFirstTNme)然后一个小括号,在一个大括号,打括号里放执行语句,这样,就把它封装好了,当我们要调用时直接写一个函数后面加一个小括号即可调用。例如上边的,函数里有三条语句,怎么让他执行呢?直接调用 test()就可以了。。而且你写上一个 test()他就会执行一遍,你在写上一个 test()他还会再执行一遍。
你把语句写在函数里和函数外效果一样,比如
function test(){
var a = 123;
var b = 234;
var c = a + b;
document.write©;
}
当你在底下 test()的时候就会打印出 357,其实函数和变量差不多,都可以理解成一个筐,只不过变量里装的是数据,函数里装的是语句,而且当你调用他的时候他才会执行,如果你底下不写 test()的话,他就不会执行里边的语句,他就是个装语句的筐,不会打印出 357,只有当你调用他的时候,他才会执行,打印出 357,而且调用两次的话就执行两次,打印两个 357.
既然函数可以把一些语句圈到里边,那么但凡能圈到它里边的东西我们就可以抽象出一类功能。就是说我们正常写的话会先把语句抽出来放在函数里,现在我们反着来,跟 css 一样,先定义功能,在使用功能,比如说我们要定义一个功能,打印 abc,就可以:
function test(){
document.write(‘abc’);
}
然后当你要用这个功能的时候直接调用函数就可以了。
注意:比如说
function a(){
var b = 1;
}
document.write(a);
你不调用这个函数,你想打印这个函数,他就会输出 function a(){var b = 1; }
函数表达式
(1)命名函数表达式
命名函数表达式的形式是这样的,例如:
var test = function abc(){
document.write(‘a’);
}
他会先定义一个变量,变量里边放入函数,这就是函数表达式,但是命名函数表达式的变量名会替代函数名的作用,意思就是调用函数你必须 test()才可以,假如你 abc()就会报错,这个 abc 就不起作用了,但是你输出 test.name 会得到 abc。
(2)匿名函数表达式
既然命名函数表达式的函数名不起作用了,后来我们就省掉了,例如:
var test = function (){
document.write(‘a’);
}
这也是后来比较常用的函数表达式,但是假如你输出 test.name 会得到 test,一个声明函数的函数名.name 也是函数名。
参数——形参和实参
(1)参数的定义及作用:我们知道函数的组成形式必须有关键字 function、函数名、小括号和大括号,这是函数必须有的东西,其实函数的组成形式中还有一个东西叫做参数,这个参数可有可无,但是正是因为这个参数才让函数变的神奇了,真正的高级编程中如果没有参数,那么函数也就没啥用了。但是参数比较简单,比如说:
function sum(a, b){
var c = a + b;
document.write©;
}
sum(1,2);
例如上边的,我们小括号里边放的就是参数,函数名后边的小括号里放了两个值 a,b,这么一放就相当于给函数体里 var a 和 var b(但是写在括号里不能带 var,不然会报错),但是并没有给他赋值,我们就把他叫做形式参数(形参),我们在调用函数的时候小括号里放了 1 和 2,我们把它叫做实际参数(实参),这就相当于给 a 赋值 1,给 b赋值 2,传参后 a=1,b=2,所以调用函数的时候打印 c 得 3.
作用:我们再来看上边这个函数,这个函数的功能就是实现两个数相加,传参数进去之后两个数就能相加了,就是我们现在不看调用函数那个语句,只看这个函数体,我们就相当于把两个数相加的规则给抽象出来了,这个 a 和 b 就跟变量一样,因为你每次执行的时候传的参数都可以不一样,比如你 sum(1,2)打印 c 就得 3,sum(3,4)打印 c 就得 7,这个就和数学里边的函数差不多了,数学里的函数为了抽象规则,xy可以随时代换值,咱们这里边的变量就是参数,所以说有了参数之后我们的函数就真正变成抽象规则了,而不是原来只是为了聚合代码。这个参数结合里边的代码可以组成无数种用法,因为我们每次传进去的参数都可以不同,所以我们针对不同的参数可以进行不同的处理,所以有了参数后函数才变得强大了。
例 1:写一个函数体,加上两个形参,如果第一个数大于 10,就打印第一个数减去
第二个的差,如果第一个数小于 10,就打印两个数的和,如果第一个数等于 10 就
打印
function test(a,b){
if(a > 10){
document.write(a - b);
}else if(a < 10){
document.write(a + b);
}else{
document.write(10);
}
}
(2)JavaScript 不定参
JavaScript 天生不定参,不是说在一个函数里有几个形参就必须有几个实参,不是这样的,在 JS 里,形参比实参多,可以,实参比形参多,也行。
在同一个函数里,形参比实参多,比如说形参有 a,b,c,实参只有 1,2,那么打印 a 得 1,打印 b 得 2,打印 c 就得 undefined。在同一个函数里,实参比形参多,比如形参只有 a,实参有 1,2,那么 a 就等于 1,那个 2 传不进去就算了。
但是无论实参怎么往里传,无论形参有没有把实参表示出来,这个实参都是有地方放的。在每一个函数里边都有一个隐式的东西叫做 arguments,arguments 是实参列表,他就是一个类数组,我们把它理解成一个数组,比如一个函数的实参是 1,2,3,那么arguments 里边就是[1,2,3],就是说无论形参有没有接受完实参,arguments 都会把实参当做一个数组存起来,比如说你在函数里的形参是 a,实参是 1,2,3,你表面上看2 和 3 没地方传,但是他会存放在 arguments 数组里的,你在函数里 console.log(arguments)就会得到[1,2,3],既然是个数组,就有长度,你 arguments.length 就
等于 3,我们也可以在函数体里把 arguments 的每一位用 for 循环单独输出。其实形参的长度也可以表示出来,用函数名.length 表示。
例 2:写一个程序,在一个函数里,如果形参比实参多,输出形参多,如果实参比
形参多,输出实参多,如果一样多,输出相等。
function sum(){
if(sum.length > arguments.length){
console.log('形参多');
}else if(sum.length < arguments.length){
console.log('实参多');
}else{
console.log('相等');
}
}
sum();
例 3:写一个求和功能的函数,无论实参里传多少值都能把他求出来。
function sum(){
var result = 0;
for(var i = 0;i < arguments.length;i++){
result += arguments[i];
}
console.log(result);
}
sum();
解析:由于实参数量不固定,我们就可以用遍历数组把 arguments 的每一位都相加即可。
(3)形参与实参的映射规则
比如说一个函数里形参是 a,b,实参是 1,2,那么 arguments 的数组里就是[1,2],a里边存的也是 1,好,我们现在在函数体里写个 a = 2;这时给 a 重新赋值了,你console.log(arguments[0])也会得到 2,继续写,我们 arguments[0]=3,这时你console.log(a)也得 3.你们看,这里边都是原始值吧?怎么一个变一个跟着变呢?形参和 arguments 确实是一个变一个跟着变的,确实有这样的绑定规则,但是,他俩不是同一个变量,系统内部有映射规则,就是这俩我变你也得变,但是他们是两个变量。
但是,假如说形参比实参多,比如说形参是 a,b,实参只有 1,就算你在函数体里写了b=2,你 console.log(arguments[1])会得到 undefined,实参列表天生有几位就有几位,只有形参和实参一一对应时才会映射。
4.return
(1)return 的第一个作用就是终止函数,比如说你在一个函数体里写
console.log(‘a’);
return
console.log(‘b’);
他就会只输出 a,不输出 b。因为你中间终止函数了,他就不执行下边的了。
(2)return 的第二点作用就是返回值,比如说
function sum(){
return 123;
}
sum();
这时,当你执行函数的时候他就会把 123 返回,但是返回的值没地方放,我们就需要一个变量来存他,比如说 var num = sum();此时输出 num 就会得到 123,这里的 return即返回值又终止函数,你写在 return 下边的语句依然不管用。一般函数处理完一个操作之后并不是为了打印,都是返回给我们以便后续利用,我们一般用变量来接收他的返回值。
5.初识作用域:
作用域后边会细讲,在这里只简单说一下,比如说:
var a = 1;
function test(){
document.write(a);
var b = 2;
function sum(){
document.write(a);
document.write(b);
var c = 3;
}
document.write©;
}
document.write(b);
这是一个会报错的代码,写在外边的 var a = 1 是全局变量,定义在函数里的变量叫局部变量。因为函数相当于一个房间,函数里边的东西能看到外面的东西,也可以访问、修改等等,但是外边的看不到里边的东西,所以你写在最外边的打印 b 会报错,test 函数体里可以打印 a,但是打印 c 就会报错,最里边的 sum 函数则可以把 ab 都打印出来。
练习 1:写一个函数,功能是告知你所选定的小动物的叫声。
function scream(animal){
switch(animal){
case "dog":
document.write('wang!')
return;
case "cat":
document.write('miao!')
return;
case "fish":
document.write('o~o~o')
return;
}
}
解析:以前我们跳出 switch 用 break,现在我们可以直接用 return 跳出函数也
可以。
练习 2.定义一组函数,逆转并输出汉字形式。
function transfer(target){
switch(target){
case '1':
return '一';
case '2':
return '二';
case '3':
return '三';
case '4':
return '四';
case '5':
return '五';
case '6':
return '六';
case '7':
return '七';
case '8':
return '八';
case '9':
return '九';
case '0':
return '零';
}
}
function reverse(){
var num = window.prompt('input');
var str = "";
for(var i = num.length - 1;i >= 0;i--){
str += transfer(num[i]);
}
document.write(str);
}
reverse();
解析:我们需要解决两个问题,逆转、输出汉字形式。我们在这里先用 transfer
函数体把数字转化为汉字的功能用 switch 语句写出来并用 return 结束语句并返
回汉字,在这个函数里,我们传一个形参 target,待会会给他传实参,我们现在来
看第二个reverse 函数体,先让他弹出对话框输入数字,由于输入的数字是字符串形
式(字符串也可以理解成一个数组,例如 var a=“123”,他的每一位也可以拿出来,
你输出 a[0]就得 1,你 a.length 就是 3),所以我们就可以在 for 循环里把他
的每一位都拿出来并且让他逆转,先定义一个 str 空串,然后在 for 循环里让 i
等于 num.length-1,先取最后一位,然后让 i 大于等于 0 并自减,这样就把 num
从后往前的把每一位都拿了出来,然后 str+=num[i],str 里就把 num 里的数字逆转
了,在这一步,我们把 num[i]作 为 transfer 函数的实参传给 target,那么,
str += transfer(num[i]);就把数字即逆转了又接收了 transfer 里 return 的
返回值,把数字转换为汉字了,最后输出 str 调 用 reverse 即可。