函数
一、函数基础
1、函数的定义
将特定的代码片段,抽取成为独立运行的实例,就是函数;
函数好处:代码复用、方便维护、便于理解、使用简单;
2、函数的创建
-
在当前函数所在script标签创建时,优先将该函数存储在堆中,并且函数名存储在栈中
-
当前这个代码所在的script标签的上面的script的标签中任意函数和全局变量都是可以被调用的
-
但是当前代码所在的script标签下面的script的标签中函数和全局变量是不可以调用的
-
函数名:驼峰式命名法,首字母一般都是小写,如果该函数是构造函数,函数名首字母需要大写
-
函数后面的()是执行当前函数需要传入参数内容
-
{}里面是函数的语句块,当执行函数时,该语句的内容就会被执行
命名函数
function fn(a,b){ //fn即为函数名 console.log(a+b); //调用函数时执行此语句块 } fn(10,20); //调用函数并传入参数
匿名函数
//代码运行到定义匿名函数后才可以调用该匿名函数 var fn=function(){ console.log(arguments.callee);//arguments.callee 就是函数本身 }
自执行函数
(function(){ //自己执行自己,也是匿名函数 })();
构造函数定义函数
var fn=new Function("a","b","console.log(a+b)"); fn(3,5);
二、作用域与作用域链
1、作用域
作用域就是变量作用的范围,分为全局作用域和局部作用域
作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。
某个执行环境中所有的代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)
var a=10; //函数外为全局作用域,函数外var定义的变量是全局变量 function fn(a){ //参数是局部变量 //函数内为局部作用域 var a=20; //函数里var定义为局部变量 console.log(a);//20 优先局部变量,没有再去外面找全部变量 }; console.log(a);//10 无法调用函数内局部变量,打印全局变量10
2、作用域链
作用域链就是执行代码时,会首先在自身函数内找变量,找不到再去外部找,再找不到就去window环境找,这个过程就是作用域链
var a=10; function fn(){ function fn1(){ console.log(a);//10 执行此代码输出a,首先在函数内fn1找变量,找不 到,然后去外部fn函数找,找不到去全部window找,这时找到a=10; 这个过程就是作用域链 } }
当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)
-
作用域链的前端,始终都是当前执行的代码所在环境的变量对象
-
作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境
-
全局执行环境的变量对象始终都是作用域链上的最后一个对象
内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。
三、参数、return
function fn(a,b){ // a,b是参数,参数可以是任意内容,如果没有对应填入,该参数就是undefined // 执行函数时,填入的参数就相当于给参数赋值 // js是一个弱类型语言,因此,参数不能强制约定类型 // ES5中不能设置参数的默认值 console.log(a+b); } fn(3);执行函数时填入值与函数参数顺序是一一对应关系
function fn(obj){ // 相当于给obj赋值一个o,obj和o的引用地址相同 // 当修改obj的属性时,全局的o属性也会被修改 obj.a=10; //此时o对象中的属性也变成10 } var o={a:1}; fn(o);
arguments参数集
-
它只能出现在函数内
-
它用来接受动态的实参
-
它是一个伪数组,原型是对象Object
-
可以通过下标[index]方式取值
function getValue(){ console.log(arguments);//arguments就是传进来的4个参数组成的集合 //当参数不确定时,就可以不设置参数,使用arguments接收 //arguments.callee就是函数自己也就是getValue函数 //匿名函数调用自己常用到arguments.callee //arguments.callee.caller是调用此函数的函数,也就是fn1函数 } getValue(1,2,3,4); function fn1(){ getValue(); }
-
function getValue(){
console.log(arguments);//arguments就是传进来的4个参数组成的集合
//当参数不确定时,就可以不设置参数,使用arguments接收
//arguments.callee就是函数自己也就是getValue函数
//匿名函数调用自己常用到arguments.callee
//arguments.callee.caller是调用此函数的函数,也就是fn1函数
}
getValue(1,2,3,4);
function fn1(){
getValue();
}return返回值
-
可以允许函数返回一个值,仅一个,也可以返回对象,数组,函数,函数体等
-
如果在函数最后一句没有返回值的情况下,尽量不要写return
-
函数没有return则返回undefined
-
return break continue区别
return 只能使用在函数中,函数外不能使用,无视任何内容直接跳出函数
break 用于switch或者循环语句中,跳出当前循环或者锚点循环,或者switch语句,循环外的语句继续执行
continue 仅跳出当前次循环,继续下一次循环,只能用于循环语句中
//生成rgba随机颜色函数,带透明度 function randomColor(alpha){ // 如果没有参数,随机 alpha=alpha==undefined ? Math.random().toFixed(2) : alpha; // 传入的参数转换为数值 alpha=Number(alpha); // 如果传入的参数是非数值,就让透明度为1 if(isNaN(alpha))alpha=1; var color="rgba("; for(var i=0;i<3;i++){ color+=parseInt(Math.random()*256)+","; } color+=alpha+")"; return color; }
四、回调函数,递归
递归或者回调的次数过多,没有阻止递归或者回调的条件,会造成堆栈溢出
1、回调函数
function fn1(f){ f()//这里f函数称为回调的函数 } function fn2(){ console.log("aaa"); } fn1(fn2);
利用回调函数模拟一个简单红绿灯(控制台输出 红灯,绿灯这样)
function getLight(first,second,third){ first(second,third); } function getRedLight(fn,fn1){ var f=arguments.callee; var ids=setTimeout(function(){ console.log("红灯"); clearTimeout(ids); fn(fn1,f); },1000); } function getYellowLight(fn,fn1){ var f=arguments.callee; var ids=setTimeout(function(){ console.log("黄灯"); clearTimeout(ids); fn(fn1,f); },1000); } function getGreenLight(fn,fn1){ var f=arguments.callee; var ids=setTimeout(function(){ console.log("绿灯"); clearTimeout(ids); fn(fn1,f); },1000); } getLight(getGreenLight,getYellowLight,getRedLight); //可以更改函数的回调顺序改变输出结果的顺序
2、递归
函数不断自己调用自己,这样就叫做函数的递归;
递归的本质是函数每次自执行都会复制出一个一样的函数执行,每个复制的函数都有自己的作用域,如没有递归结束,则函数下面语句不执行,知道递归结束后才执行后面语句
var i=0; fn(); function fn(){ i++; // console.log(i); if(i<4) fn(); //这里就是再递归,满足条件继续执行自己 console.log(i);//注意此时会输出四次i=4;因为只有在上面递归完后,才能执行此语句 } function fn(n){ if(!n) n=1; n++;//2 if(n<5) fn1(n);//挂起不会往下执行 return n;//2因为第一次进来n=1,n++之后为2,而递归是复制出一个函数执行,这里是把n作为参数带进去,那么n就是每个复制的函数的局部变量,都只能在自身函数内部调用,此时的fn函数也只能调用到自己的局部变量,也就是n=2; } fn();//函数运行完之后,局部变量会被销毁 function fn(n){ if(!n) n=1; n++;//2 if(n<5) return fn1(n);//挂起不会往下执行,这里使用return把每次复制函数的结果返回给到上一个复制的函数,就会把变量n一步一步向上返回,直到返回给原函数,所以此时return n 会输出5 return n; //5
原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/272656.html