函数执行时,程序的基本执行过程和原理
函数的定义/封装阶段
- 在内存中开辟一个存储空间,并且定义内存地址;
- 定义函数的程序内容,存储在这个内存地址,报送的空间中;此时程序没有被执行,以字符串的形式来存储
- 将内存地址存储在 变量名称 / 函数中
函数的调用阶段 - 读取变量名称 / 函数名称中存储的内存地址
- 通过内存地址,找到对应的函数程序
- 给函数程序中的参数,进行赋值
- 预解析 / 预解释
- 执行函数中存储的程序代码
预解析的无下限操作
只要是写在程序中的var 和 function关键词,都被预解析。
不管程序会不会执行,都会进行预解析。
如果是不执行的程序,var 会进行预解析,如果提前使用,结果是undefined
如果是函数,function 会预解析,但是不执行的函数,不能调用的。
函数不能调用的原因:
预解析会执行,也会存储内存地址。但是程序不执行,这个内存地址中就没有内容,执行结果会报错
console.log(int); //undefined
// fun();
if(false){
// 当if判断,条件执行结果是true时,才会执行程序
// 如果条件执行结果是false,var int = 100 是不会执行的
var int = 100;
function fun(){
console.log(123);
}
}
console.log(int); //undefined
fun(); // fun is not a function
变量的作用域
- 什么叫变量的作用域?
所谓的变量的作用域,就是变量的使用范围
每一个变量都有自己的使用范围
就好像 Q币 只能在QQ商城中使用
王者荣耀的金币,只能在王者荣耀的商城中使用 - 变量的作用域分为两种
- 定义在函数之内的变量
包括函数的参数,定义在函数内部的变量,都称为局部作用域变量 / 局部变量
只能在函数内容部使用,如果外部想要直接调用,是不行的
- 定义在函数之内的变量
// 此时函数中定义的变量,参数a和变量b,都是局部作用域变量
// 只能在函数内部被调用使用
// 函数外部不能直接使用调用
// 只要是在函数外部,调用函数内部的变量,都是报错
function fun1(a){
var b = 100;
console.log(a,b); // 函数内部调用
}
// fun1('北京');
// console.log(a,b); // 函数外部调用, // a is not defined
- 定义在函数之外的变量,称为全局作用域变量/全局变量
在函数的内部是可以使用,全局作用域变量的,但是是有条件的
var int = 100;
function fun2(){
console.log(int);
}
fun2(); //100
//总结: 在函数外部,不能直接调用函数内部定义的局部作用域变量
//在函数内部,可以调用函数外部的全局作用域变量,但是是有条件的.全局变量要在调用函数前定义。
在函数中,调用变量和对变量赋值的原则
// 变量的调用
// var int = '北京';
function fun1(){
// var int = 100;
// console.log(int);
function f1(){
var int = '反正不用';
}
}
// fun1();
调用变量的原则
-
会先在当前作用域中,找是否有这个变量
(1) 如果有,就直接使用这个变量
(2)如果没有,去父级作用域寻找这个变量
a. 如果父级作用域有这个变量,就使用这个变量
b. 如果父级作用域没有这个变量,再向上一层寻找 -
如果找到这个变量,就直接使用
-
如果所有的作用域都没有这个变量,执行结果是报错
-
只会向父级作用域找变量,不会向子级作用域找变量
// 变量的赋值 //1 var int = '北京'; function fun2 (){ var int = 100; int = 200; console.log(int); } fun2(); //控制台输出:200 //2 var int = '北京'; function fun2 (){ int = 100; var int = 100; console.log(int); } fun2(); //控制台输出:100 //3 var int = '北京'; function fun2 (){ console.log(int); int = 100; var int = 100; } fun2(); //控制台输出:undefined //4 var int = '北京'; function fun2 (){ console.log(int); } fun2(); //控制台输出:北京 //5 var int = '北京'; function fun2 (){ var int = 200; int = 100; console.log(int); } console.log(int); // 控制台输出:北京 //6 function fun2 (){ var int = 200; int = 100; console.log(int); } console.log(int); // 控制台输出:int is not defined //函数外部的调用,只能调用全局作用域的int // 如果全局作用域没有int,是函数内部,赋值语句升级定义的全局变量 // 调用的就是 函数内部的的变量,int // console.log(int);
变量的赋值原则
- 先在当前作用域中找变量,如果有,就对这个变量进行赋值
(1) 如果当前作用域没有这个变量,去父级作用域找这个变量
(2) 如果父级也没有这个变量,再去父级找变量
(3) 如果所有的作用域都没有这个变量
赋值语句,升级为定义变量语句,并且定义的是全局作用域变量
不会去子级找变量赋值
记住一句话: 定义变量,一定要写 var 关键词,不管是局部还是全局
递归函数
递归函数:是一种特殊的函数,就是在函数内部,调用函数自己本身.
/*
function fun1(){
在函数fun1中调用函数fun1自己本身
fun1()
}
*/
// 递归函数,实际当中,我们基本上用不到,只是作为概念,了解,掌握几个相应的demo就可以了
// 倒序输出
for(var i = 5 ; i >= 1 ; i--){
console.log(i);
}
递归方式输出
function fun(num){
console.log(num);
num--;
if(num >=1){
fun(num);
}
}
fun(5);
function fun(num){
num--;
if(num >=1){
fun(num);
}
// 将执行的输出,写在递归调用之下
console.log(num);
}
fun(5);
- 调用递归函数,一定要有条件,无条件的调用递归函数,会一直执行调用,不会停止
- 调用递归函数,进入递归函数,会由外至内执行,结束递归函数,会从内至外执行