04js函数,作用域链和预解析
1.函数
函数概述
函数(方法)即某个特定代码块(有某种功能),是程序中的一个独立实体
函数的优点
减少冗余代码,复用性高(需要就调用) 函数封装(特定的代码用函数包起来)
使程序变得简短清晰,提高可读性
提高了代码的可维护性
函数的分类
函数可以分为:系统函数 内置函数和自定义函数
系统函数,内置函数:是官方提供好的函数,可直接使用如console.log()、alert()、Math.pow()等
自定义函数:是用户自己定义的函数, 用户可以根据实际需求, 对特定的功能使用函数来封装
函数的定义和调用
1.匿名函数(很少使用,可以传参)
( function (s) { console.log("默认打印"); console.log(s); console.log(s);//输出结果 传参 console.log(s);//输出结果 传参 console.log(s);//输出结果 传参 } )("传参")//输出结果:默认打印 传参 ("错误")//报错
2.具名函数
//必须使用function关键字, 且为小写, 函数名可以自己给定函数名的命名规则和变量名一致函数名后必须写圆括号() function 函数名() { 代码块; }
3.具名函数的变种(看起来很丑且数值类型为字符串,不建议使用)
var fn = new Function(" num","console.log('函数'+num)")//注意:都是字符串 fn(55)//输出结果:函数55(num为形参,55为实参)调用:函数名(实参);函数在不调用的情况下是不会执行的
函数自带伪数组arguments(下标,长度和数组一样但是不能使用push和pop)
//写个函数计算所有传入参数相乘的结果参数数量不定) function getRide() { var sum = 1; for(var i=0;i<arguments.length;i++){ //arguments 所有函数自带的一个为数组,用来接收不确定个数的变量 sum *=arguments[i]; } return sum; } console.log(getRide(2,3,4));
函数的嵌套使用
<input id="num1" type="text" placeholder="请输入第一个数"><!-- 输入第一个数 --> <select name="" id="s"><!-- 选择运算符 --> <option value="+">+</option> <option value="-">-</option> <option value="*">*</option> <option value="/">/</option> </select> <input id="num2" type="text" placeholder="请输入第二个数"><!-- 输入第二个数 --> <input id="result" type="text"><!-- 显示最终结果--> <button id="btn">计算</button><!-- 事件驱动按钮(调用计算器函数) --> <script> //自定义加减乘除函数 function fn3(x, s, y) { var result = 0; switch (s) { case "+": result = x + y; break; case "-": result = x - y; break; case "*": result = x * y; break; case "/": result = x / y; break; default: console.log("参数错误"); } return result; }//制作一个简易计算器(计算两个数的加减乘除,带可手动输入数字和运算符) function fn4() { var num1 = document.getElementById("num1").value;//获取第一个数值并赋值给num1 var s = document.getElementById("s").value;//获取运算符... var num2 = document.getElementById("num2").value;//获取第二个数值... document.getElementById("result").value = fn3(Number(num1),s,Number(num2))//嵌套调用加减乘除函数 return result; } document.getElementById("btn").onclick = fn4;//执行事件驱动 </script>
2.作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域(全局变量)
全局变量在整个script标签或者js文件都能用
局部作用域(局部变量)
局部变量
var num = 20; function j (){ var num = 10; console.log(num);//输出 10 局部变量num } j() console.log(num);//输出20 全局变量num
js中没有块级作用域{}( if{},for{}) 在es6才新增的块级作用域
if(1<2){ var num = 10; } console.log(num);//所以可以输出 10
作用域链
逐级往外找变量的过程叫做作用域链,一旦找到了变量,则不再继续
var a =1;//最外层的变量 function fn1(){ var a = 2; var b = 2; fn2(); function fn2(){ var a= 3; fn3(); function fn3(){ var a =4;//最里层的变量 console.log(a);//a的值?4 console.log(b);//b的值?2 } } }
3.预解析
- js代码在浏览器(js解析器)运行分为两步:预解析 代码执行
- 预解析js引|擎会把js 里面所有的var还有 function 提升到当前作用域的最前面
变量预解析(变量提升 )
console.log(num);//报错
console.log(num);//代码执行前会预解析(var声明了名为num的变量但没赋值)输出undefined var num = 10;
具名函数预解析(函数提升)
fn(); function fn(){ console.log("函数");//输出 函数 }
赋值函数预解析(因为是赋值形式 相当于变量提升 所以第二段代码会报错)
var fn2 = function(){ console.log("函数2");//输出 函数2 } fn2();
fn2(); var fn2 = function(){ console.log("函数2");//报错 }