一、函数的声明
- 函数:把一堆重复性的代码封装,哪里需要,那里调用
- JavaScript 有三种声明函数的方法。
(1)function 命令
function
命令声明的代码区块,就是一个函数。function
命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。
function sum(s) {
console.log(s);
}
//上面的代码命名了一个`sum`函数,以后使用`sum()`这种形式,就可以调用相应的代码。这叫做函数的声明(Function Declaration)。
sum();
(2)函数表达式 (采用变量赋值的写法。 )
var sum = function(s) {
console.log(s);
};
//采用函数表达式声明函数时,`function`命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
var sum = function x(){
console.log(typeof x);
};
x;
// ReferenceError: x is not defined
sum();
// function
//上面代码在函数表达式中,加入了函数名`x`。这个`x`只在函数体内部可用,指代函数表达式本身,其他地方都不可用。可以在函数体内部调用自身,因此,下面的形式声明函数也非常常见。
var f = function f() {}
//需要注意的是,函数的表达式需要在语句的结尾加上分号,表示语句结束。而函数的声明在结尾的大括号后面不用加分号
(3)Function 构造函数(这种声明函数的方式非常不直观,几乎无人使用。 )
var sum = new Function(
'x',
'y',
'return x + y'
);
// 等同于
function sum(x, y) {
return x + y;
}
注意:如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
二、参数
【形参】:函数【定义】的时候小括号里面的【变量】叫形参,形参名自定义
【实参】:函数【调用】的时候小括号里面的【值】叫实参,实参的值可以是变量,一般都是固定值
function sum(x, y, z) {
if(z == '+') {
alert(x + z + y + "=" + (x+y));
}else if(z == '-') {
alert(x + z + y + "=" + (x-y));
}else if(z == '*') {
alert(x + z + y + "=" + (x*y));
}else if(z == '/') {
alert(x + z + y + "=" + (x/y));
}else if(z == '%') {
alert(x + z + y + "=" + (x%y));
}else {
alert('请输入正确的运算符号(+ - * / %)!')
}
}
var a = Number(prompt("请输入第一个数字:"));
var b = Number(prompt("请输入第二个数字:"));
var c = prompt("请输入运算符号:");
sum(a, b, c);
- 函数参数不是必需的,JavaScript 允许省略参数。
- 传值:函数调用的时候,小括号里面的值回传给函数定义时的参数
//函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。
var p = 2;
function f(p) {
p = 3;
return p;
}
var i = p;
console.log(f(i));//3
console.log(p); // 2
//上面代码中,变量`p`是一个原始类型的值,传入函数`f`的方式是传值传递。因此,在函数内部,`p`的值是原始值的拷贝,无论怎么修改,都不会影响到原始值。
三、函数的返回值
函数中有return关键字,return后面的代码不会执行
- return后面有一个值,叫返回值,要接收返回值,用变量接收
- return后面没有返回值,变量接收到的是undefined
- 可以返回不同的数据类型
- 没有括号返回的是整个函数体
function f1(x, y) {
var sum = x + y;
console.log("return前的" + sum);
return "a";
console.log("return后的" + sum);
}
// f1(1, 2);
var result = f1(1, 2);
//先打印出return前的3
console.log(result);//a
console.log(f1(1, 2));//a
console.log(f1);//整个函数体
四、函数的其他定义
(1)命名函数:函数有名字
(2)匿名函数:函数没有名字
函数的另一种定义方式
函数表达式:var 函数名/变量 = 匿名函数
函数的声明:function 函数名() {}
function f1() {
console.log('命名函数');
}
var f2 = function () {
console.log('匿名函数');
}
f2();
console.log(f2);
f1();
console.log(f1);
function f3() {
console.log('命名函数lllllllll');
}
f3();
//函数自调用,一次性调用,函数没有名字,相当于声明函数的同时直接调用
(function() {
console.log('自调用');
})();
console.log(typeof f2);// function
//相当于给g函数重命名为f
var f = function g() {
return 10;
}
console.log(f);
console.log(typeof f);
console.log(f());
1.把函数当成参数
function f1(x, y) {
console.log(x + y);
}
f1(10, 20);
function f2(fn) {
console.log(fn);
fn(1, 2);
}
f2(f1);
2.函数作为返回值
function f3() {
console.log('f3被调用了');
return function () {
console.log('函数被返回了');
}
}
f3();
var ff = f3();
console.log(ff);
f3()();
五、作用域
作用域:使用的范围
- 全局变量:用var声明的变量,可以在页面中任何位置使用
- 局部变量:函数内部定义的变量,在函数外面不能使用
- 全局作用域:全局变量使用的范围
- 局部作用域:局部变量使用的范围
- 块级作用域:一对大括号{}中可以堪称是一块,在这个区域中定义的变量只能在这个区域中使用,在目前用法中没有涉及到块级作用域
- 隐式全局变量:声明的变量没有var
区别:
- 全局变量不能被删除
- 隐式全局变量能被删除
function f1() {
var num1 = 10;
console.log(num1);
}
f1();
console.log(num1);
var num2 = 20;
console.log(num2);
var a = 1;
b = 1;
delete a;
delete b;
console.log(typeof a);
console.log(typeof b);
补充:作用域链
(1)只有函数可以制造作用域结构,只要是代码,就至少有一个作用域
(2)凡是代码中有函数,这个函数就构成另一个作用域,如果函数中还有函数,在这个作用域中又诞生一个作用域
(3)将这样的所有作用域列出来,可以有一个结构:函数内指向函数外的一个链式结构,就是作用域链
// 从内到外找
var num = 10;
function f1() {
var num = 0;
function f2() {
var num = 500;
function f3() {
var num = 200;
console.log(num);
function f4() {
var num = 100;
console.log(num);
}
f4();
}
f3();
}
f2();
}
f1();
六、函数的练习
1、求1-n数字的和
// 求1-n数字的和
function sum(n) {
var sum = 0;
for(var i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
var result = sum(parseInt(prompt('请输入要求1到你所输入的值的和:')));
console.log(result);
2、求n个数中最大值
// 求n个数中最大值
function max() {
// 通过arguments获取实参的值,本质是对象,其实是伪数组,具有数组才会有的属性length
console.log(typeof arguments);
var max = arguments[0];
for(var i = 0; i < arguments.length; i++) {
if(max < arguments[i]) {
max = arguments[i];
}
}
return max;
}
//最小值
function min() {
// 通过arguments获取实参的值,本质是对象,其实是伪数组,具有数组才会有的属性length
console.log(typeof arguments);
var min = arguments[0];
for(var i = 0; i < arguments.length; i++) {
if(min > arguments[i]) {
min = arguments[i];
}
}
return min;
}
var result1 = max(12, 22, 56, 3, 99, 21, 888, -52, -79);
var result2 = min(12, 22, 56, 3, 99, 21, 888, -52, -79);
console.log('最大值为' + result1,'最小值为' + result2);
3、输入年月日,判断这一天是这一年的第几天1999/2/20
//输入年月日,判断这一天是这一年的第几天1999/2/20
//判断平年闰年
function isYear(year){
if(year % 4 == 0 && year % 100 != 100 || year % 400 == 0){
return year;
}
}
// console.log(isYear);
//判断第几天
function getDay(year,month,day){
//判断一月份内的
var days = day
if(month == 1){
return days;
}
//到这一步用户输入的不是一月份
var arr = [31,28,31,30,31,30,31,31,30,31,30,31];
for(var i = 0; i < month -1; i++){
days += arr[i];
}
//是否加一
if(isYear(year) && month > 2){
days++;
}
return '这一天是今年的第' + days + '天';
}
var nian = parseInt(prompt('请输入年份'));
var yue = parseInt(prompt('请输入月份'));
var ri = parseInt(prompt('请输入日子'));
console.log(getDay(nian,yue,ri));
4、用户输入班级人数(>=4),根据人数输入成绩,求总成绩、平均成绩、最高分、最低分
//用户输入班级人数(>=4),根据人数输入成绩,求总成绩、平均成绩、最高分、最低分
function people(){
//班级人数
var count = parseInt(prompt('请输入人数:'));
//装数组
var grade = [];
//录成绩
for(var i = 0; i < count; i++){
grade[grade.length] = parseInt(prompt('请输入第' + (i + 1) + '个人的成绩:'));
}
var sum = 0;
//求最高分,最低分
var max = grade[0];
var min = grade[0];
for(var i = 0; i < grade.length; i++){
sum += grade[i];
if(max < grade[i]){
max = grade[i];
}
if(min > grade[i]){
min = grade[i];
}
}
//求平均值
var avg = sum / grade.length;
//打印结果
console.log(grade);
console.log('总分数为:' + sum);
console.log('平均分数为:' + avg);
console.log('最大值为:' + max);
console.log('最小值为:' + min);
}
people();
补充:argument
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments
对象的由来。一种伪数组,真对象。(具有数组的length属性)
arguments
对象包含了函数运行时的所有参数,arguments[0]
就是第一个参数,arguments[1]
就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
var f = function (one) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
f(1, 2, 3);
// 1
// 2
// 3