七、JavaScript函数
函数:函数就是实现功能的代码模块
作用:方便我们反复调用,执行程序,实现效果
注意:函数定义时,只是在定义封装程序,并没有执行程序,只有调用函数才会执行其中封装的程序
一、函数基本语法
1、声明式
通过关键词function来定义声明函数
1 // 语法结构: 2 function 函数名称 (){ 3 函数封装的执行程序 4 就是每次调用函数,都会执行的程序 5 }
函数命名规范:
- 函数名称只能是数字、字母、下划线
- 严格区分大小写
- 不要使用关键词和保留词
推荐遵守:
- 不要使用中文、$、不能使用特殊符号等
- 一般函数遵守小驼峰命名法,构造函数遵守大驼峰命名法
2、赋值式/匿名函数
将函数赋值给一个变量进行存储,函数不定义函数名称,使用变量名作为函数的名称
1 // 语法格式: 2 var fun = function () { 3 函数封装的程序 4 }
二、函数的参数
在函数程序执行时,输入的一些数据内容,称为函数的参数
1 // 给形参赋值默认值5,也就是如果没有输入实参数据,按照5来执行 2 // 如果输入实参数据,实参数据会覆盖默认值5,按照实参数据来执行 3 function setPyramid(line = 5){ 4 for(var i = 1 ; i <= line ; i++){ 5 for(var j = 1 ; j <= line-i ; j++){ 6 document.write(' '); 7 } 8 for(var k = 1 ; k <= i ; k++){ 9 document.write('* '); 10 } 11 document.write('<br>'); 12 } 13 } 14 // 会按照默认值数据来执行 15 setPyramid(); 16 // 程序按照数值10来执行,生成10行金字塔 17 setPyramid(10);
1 // 一个函数可以有多个参数,多个参数都定义在函数的 ( ) 小括号中 2 // 多个参数之间,使用逗号间隔 3 // 实参赋值与形参的顺序是一一对应的 4 function myAdd2(max , min=1){ 5 var res = 0; 6 for(var i = min ; i <= max; i++){ 7 res += i; 8 } 9 console.log(res); 10 } 11 // 定义两个参数,将带有默认值的参数,定义在所有参数最后 12 // 定义一个实参,按照形参赋值的顺序,这个实参会赋值给第一个形参,max 13 myAdd2( 100 );
三、函数的返回值
在函数中 可以通过 return 关键词来定义函数的返回值,也就是函数的执行结果,没有定义返回值的函数,返回值一律是 undefined
1 function myAdd2(max, min=1){ 2 // 容错处理 3 if(min > max){ 4 var int = min; 5 min = max; 6 max = int; 7 } 8 var res = 0; 9 for(var i = min ; i <= max ; i++){ 10 res += i; 11 } 12 // 通过 return 来定义函数的执行结果,返回值 13 return res; 14 } 15 var b = myAdd2(1,10); 16 console.log(b);
return 可以终止函数中一切内容的执行,包括循环内、循环外的、之后的循环次数的
1 function fun(){ 2 for(var i = 1 ; i <= 10 ; i++){ 3 if(i == 5){ 4 // break 只能终止循环中的程序 5 // 对循环外的程序,没有作用 6 7 // return 可以终止函数中所有的程序的执行 8 // 包括循环内,循环外的,之后的循环次数的 9 return; 10 } 11 console.log(i); 12 } 13 console.log('我是循环外的程序'); 14 } 15 16 fun();
四、堆和栈
在内存中操作系统将内存分成了两个部分,栈和堆
栈:
- 存储基本数据类型:布尔类型、数值类型、字符串类型、undefined、null
- 以有序的方式存储数据,先进后出原则
堆:
- 存储引用数据类型:函数、数组、对象
- 以无序的方式存储数据
- 变量名称 / 函数名称存储在栈中,而变量名称 / 函数名称中存储的是 堆中内存空间的内存地址
总结:
- 基本数据类型比较,比较的是 存储的数值数据
- 引用数据类型比较,比较的是 存储的内地地址
- 即使两个引用数据类型,数据内容都完全一致,因为存储的内存空间不同,变量名称/函数名称中存储的内存地址也不同,一定是不等的
五、预解析/预解释
在 JavaScript 的程序执行机制中 , 会有一种 叫做 预解释 / 预解析 的执行机制
在 JavaScript 的程序执行之前,会提前解释通过关键词 var 声明的变量和通过关键词 function 声明的函数
1 // 变量的预解析 2 // 如果在声明int1之前调用这个变量, JavaScript执行这个变量,不会认为变量不存在,而是认为变量已经被定义,只是没有被赋值 3 var int1 = 100; 4 5 // 对于 let const 关键词声明的变量 , JavaScript程序不会执行预解析/预解释 6 // 优点:如果提前调用变量,只是没有正确赋值,数值是undefined,但是其他程序可以执行 7 // 缺点:提前预解释/预解析所有的JavaScript程序,会占用内存,减低程序的执行效率,容易造成内存泄漏
1 // 函数的预解析 2 // 通过 function 定义的函数,可以在定义之前,提前调用 3 function fun1() { 4 return '我是通过function定义的函数'; 5 } 6 7 // 使用匿名函数赋值声明的函数不能提前调用 8 var fun2 = function () { 9 return '我是匿名函数'; 10 }
六、变量的作用域
变量的作用域指的就是变量的有效范围,也就是这个变量在什么范围内,可以被正常的调用使用
-
-
全局作用域变量:声明在函数之外的变量,可以在程序中和函数中,都被正常调用
-
局部作用域变量:声明在函数中或者函数的参数,只能在函数内部被调用被执行,不能在函数外部直接被调用执行
-
-
即使是通过 return 定义为返回值的变量,也只是返回变量存储的数值,不是返回这个变量
-
JavaScript语法中变量的调用原则:
-
如果函数局部作用域中有这个变量,那么就调用局部作用域中的变量
-
如果函数局部作用域中没有有这个变量,那么会先去父级函数中寻找
-
如果父级函数有这个变量,就使用这个变量,直至全局作用域
-
如果全局作用域也没有这个变量,执行结果是报错
-
-
七、递归函数
在函数中,自己调用自己
1 function fun(){ 2 fun() 3 } 4 5 // eg: 6 function fun( num ){ 7 num--; 8 if(num >= 1){ 9 fun(num); 10 } 11 } 12 fun(5)
写递归,一定是先写终止情况,也就是最后的情况
1 // 使用递归生成菲波那切数列 2 // 1 1 2 3 5 8 13 21 34 55 ..... 3 4 // 求第n位上, 菲波那切数列的数值 5 function fun(n) { 6 // 第一位第二位数值都是 1 7 if (n == 1 || n == 2) { 8 return 1; 9 } 10 // 之后的数值是前两位数值的和 11 return fun(n - 1) + fun(n - 2); 12 } 13 console.log(fun(30));