一、函数的作用-解耦合
我们程序一般都要尽量去做到高内聚、低耦合。意思就是每个模块与每个模块之间的依赖要尽量降低,也就是模块的单一职责。每个模块尽量只做一件事,做自己分内的事情即可。
所以我们要做的事情就是解耦。JavaScript中解耦最好的方式就是用函数。
二、函数基础
1、函数是什么
function test(参数) {
函数执行体
}
// 声明了函数,就相当于在电脑上安装了软件,你要用的时候就去调用他,不调用的时候是不会自己执行的。
总结:一个固定的功能或者是程序段被封装的过程,实现一个固定的功能或者是程序,在这个封装体中需要一个入口和一个出口,入口就是参数,出口就是返回。
2、函数名命名规则
与变量的命名规则一致,这里在复习一下
- 不能以数字开头,可以以字母$_开头
- 可以包含字母_$数字
- 不能使用关键字、保留字
- 结构化、语义化命名
- 养成良好的习惯,使用小驼峰命名法
- 不要使用拼音,很让人讨厌!
3、函数的声明方式
1、直接声明
function test() {};
2、字面量声明
var test = function test1() {};
请注意:这里的function后面可以写名字也可以不写。不写我们都知道就跟普通函数没什么区别。但是如果写了呢?
1、test1在外部不可见。即在外面调用该函数,只能使用test();而使用test1()是会报错的。
2、test多了一个name属性,test.name = test1;
3、在函数内部是可以使用test1()来调用自己。
var test = function test1() {
test1(); //3、在里面可以使用test1自己调用自己。
}
test1(); //1、报错,因为test1在外面已经被忽略了,在外面只能使用test()
test(); // 正确调用
test.name; //2、该函数多了一个name属性,值就是test1。
一般我们用字面量声明函数的时候,都是使用匿名函数字面量来声明。
var test = function() {};
4、形参与实参(重要)
1、形参是形式上的占位而已,需要等到函数执行的时候传进来,该值才有值。
2、实参是实际传递到函数的参数,他有实际的值。
function test(a, b) { // 括号里的参数就是形参,形式上的占位
console.log(a + b)
};
test(1, 5); // 1 5就是实参,实际传递进去的参数,有具体内容
3、形参与实参是一一对应的。
4、参数是什么数据类型都可以传递过去的。
5、形参与实参数量不一致会报错吗?不会报错。
形参 > 实参,没有传值的形参的值是undefined。
实参 > 形参,只按照位置一一对应。多出来的就不赋值,但是存在。
6、在函数执行时知不知道传递的实参有多少个?知道。arguments。
function test(a, b) {
console.log(arguments); // 打印 [1, 2, 3, 4]
}
test(1, 2, 3, 4); // 定义的时候只接收两个,通过arguments能获取到所有实参。
关于arguments:arguments是一个数组,是传递过来的实参的数组,可以遍历拿到所有实参,数量不一致也可以。
7、能否拿到形参的长度?当然可以,直接是函数名.length。如 test.length
8、做一道题:
一个函数被调用时,累加他的实参值。(实参数量未知)
function sum() {
var a = 0;
for (var i = 0; i < arguments.length; i++) {
a += arguments[i];
}
console.log(a);
}
sum(1, 2, 3, 4, 5, 6);
9、通过形参来改变实参的值的两种情况区分
// 注意形参数量 <= 实参数量
function test(a, b) {
a = 5; // 这句话直接就改变实参的值了。因为到这里形参与实参已经统一了。
console.log(arguments[0]); // 打印5
}
test(1, 2, 3);
// 注意形参数量 < 实参数量
function test(a, b) {
b = 3;
console.log(arguments[1]); // 打印undefined
//形参与实参确实统一了,但是统一的是一一对应的统一。实参只有一个,就只有a跟1统一了。跟b没啥关系
}
test(1);
所以:形参与实参统一时,只会统一有对应关系的形实参。其实形参与实参是两个东西,一个存放在栈,一个在堆,但是他们之间是有映射关系的。修改形参时,通过映射关系,就会修改相应的实参。但是只能是对应上了的形参修改时,实参才会修改。如果形参有两个,实参只有一个,那么修改第二个形参对实参毫无影响,因为本身实参就只有一个。(例子2)
5、return相关知识点
1、return之后的语句不会执行,因为return就是说明该函数已经执行完毕了,并且返回。
2、所有的函数都有return,如果没有写的话,系统会自动为我们在最后添加return。
3、return不仅可以终止函数的运行,还可以返回你想返回的东西。
4、return与逻辑运算符的运用题:
function test(name) {
return name || '您没有填写名字';
}
test();
三、作用域初识
1、函数嵌套时,越往里面的函数越能访问到外面函数定义的变量,既能获取也能修改。
function test1() {
var a = 1;
function test2() {
var b = 2;
console.log(a); // 能访问到外层函数的变量
a = 3; // 能成功修改外层a的值
}
test2();
console.log(b); // 报错,不能访问到内层的变量
}
2、作用域是什么?
声明的变量、函数能访问的范围。
四、作业
1、定义一个函数,从wp接收一个饮料的名称,函数返回对应的价格。
var drink = window.prompt('请输入一款饮料(可乐、雪碧、芬达)');
function judgePrice(d) {
var price;
switch (d) {
case '可乐':
price = 3;
break;
case '雪碧':
price = 2;
break;
case '芬达':
price = 3.5;
break;
}
return res;
}
console.log(judgePrice(drink));
2、定义一个函数,从wp接收第一个数,接收一个运算符号(+ - * / %),在接收一个数。利用这个函数做运算,并返回运算结果。
function computer() {
var num1 = Number(window.prompt('请输入第一个数:'));
var operator = window.prompt('请输入运算符:');
var num2 = Number(window.prompt('请输入第二个数:'));
var res;
switch (operator) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
return num1 / num2;
case '%':
return num1 % num2;
default:
return '输入有误';
}
}
console.log(computer());
3、定义一个函数,从wp接收一个n,算出n的阶乘,不能用for循环。
var num = parseInt(window.prompt('请输入一个需要阶乘的n'));
function factorial(n) {
// 递归退出条件
if (n === 1) {
return 1;
}
// 当前的数* n-1的阶乘
return n * factorial(n - 1);
}
console.log(factorial(num));
4、定义一个函数,从wp接收一个n,算出斐波那契数列的第n位,不能使用for循环。
var num = parseInt(window.prompt('请输入需要查找第几位斐波那契数:'));
function fib(n) {
if (n === 2 || n === 1) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
console.log(fib(num));