目录
1.函数定义
函数:是由事件驱动的或者当它被调用时执行的可重复使用的代码块
1.1 函数声明
function 函数名(参数1,参数2,...) {
要执行的代码(代码块)
}
【函数声明不是可执行的语句,不需要分号结尾】
被声明的函数不会直接执行,被调用时执行。
上面的函数是命名函数(有函数名的函数),可以直接通过函数名调用。
调用:函数名(参数1,参数2,...);
函数名存储的是函数
1.2 函数表达式
把一个函数存储在变量中,就形成了函数表达式。
var 变量=匿名函数;【函数表达式要使用分号结尾,因为它是可执行语句的一部分。】
var x = function (a, b) {return a * b};【变量x保存的是函数】
上面的函数是一个匿名函数(没有函数名的函数),匿名函数不能直接调用,使用存储它的变量名调用。【调用:x(4, 3);】
x(4, 3);//12
变量存储的是函数
函数的自调用:没有名字,声明完了,马上进行调用,只能使用一次
函数是有数据类型的,数据类型为function-->console.log(typeof 函数名);查看
2.函数参数
注意:如果调用时省略了参数(或参数少于被声明的数量【实参数<形参数】),则丢失的值被设置为:undefined。
如果函数调用的参数太多(超过声明),则可以使用 arguments 对象来达到这些参数。
arguments 对象包含函数调用时使用的参数数组。
arguments可以获取函数调用的时候,传入的实参的个数
arguments.length--->实参的个数
argument[index]--->实参的值
3.函数可以作为参数使用
函数可以作为参数使用,如果一个函数作为参数,这个函数叫回调函数
只要是看到一个函数作为参数使用了,那就是回调函数
4.函数可以作为返回值使用
5.函数作用域
全局变量:函数之外声明的变量,网页的所有脚本和函数都能够访问
局部变量:函数中声明的变量,只能在函数内部访问,外部不能使用
注意:
- JavaScript 变量的有效期始于其被创建时。局部变量在函数完成时被删除;全局变量在页面关闭时被删除,如果不关闭页面,就不会释放,就会占空间,消耗内存。
- 函数参数也是函数内的局部变量。
全局作用域:全局变量的使用范围
局部作用域:局部变量的使用范围
(说明:js【ES5】没有块级作用域)块级作用域:一对大括号就可以看成是一块,在这块区域中定义的变量,只能在这个区域中使用,但是在js中,在这个块级作用域中定义的变量,外部也能使用【这里只是想说明:在函数里声明的变量,只能在函数里使用;而其他在大括号内部声明的变量,外部也可以访问】
可总结:除了函数以外,其他任何位置使用var定义的变量都是全局变量
扩展
1.隐式全局变量:声明的变量没有使用var,就叫隐式全局变量
全局变量是不能被删除的,隐式全局变量是可以被删除的
2.作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了;搜索到0级作用域的时候,如果还是没有找到这个变量,结果报错
6.预解析
JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的,JavaScript解析器执行JavaScript代码的时候,分为两个过程,预解析过程和代码执行过程。
定义:在当前作用域下,js代码执行之前,进行的一些解析工作:把变量或者函数提前到当前所在的作用域的最上面。(声明提升)【顺序:先提升var,再提升function】
通过声明提升,函数可以在声明的函数体之前进行调用;变量也可以在赋值之前进行输出,而不会报错,而如果直接输出一个没有声明的变量会报错。
浏览器寻找var关键字声明的变量和通过function关键字声明的函数(从上到下,从里到外:先在局部作用域里找,然后子对象根据作用域链一级一级向上寻找所有父对象的变量),将声明提前(声明提升),变量在提升声明的时候不会提升赋值,默认值是undefined,变量在遇到表达式赋值之后才改变值【var num;-->undefined num=10;-->10】;函数在提升声明的时候不会提升调用,存储的是函数体的字符串,不执行,函数调用以后执行。
注意:
- 同名的var声明和同名的函数声明,function优先于var,即:同名时,函数声明覆盖变量声明
- 同名的var声明,后者会覆盖前者
- 同名的函数声明,后者会覆盖前者
通过预解析的案例说明一些注意事项:
1.预解析会分段(多对script标签中函数重名,预解析的时候不会冲突)
<script>
f1();//hello1
function f1() {
console.log("hello1");
}
</script>
<script>
//f1();//hello2
function f1() {
console.log("hello2");
}
</script>
2.预解析,不会超出script标签
<script>
console.log(f1);//报错--->当前script标签内,并未声明函数f1或变量f1,所以报错
</script>
<script>
function f1(){}//虽然声明了函数f1,但预解析也只是在当前的标签内
</script>
3.由于js代码是从上至下执行的,一对script标签里的代码可以访问在它之前的script标签的代码
<script>
function f1(){}
var f1= 10;
</script>
<script>
console.log(f1);//10
</script>
//个人理解:之前说的function优先var
第一对script等价于:
<script>
var f1;
function f1(){}
f1= 10;//注意这里赋值了,所以第二对script访问的f1实际是变量f1,
而不是函数f1;如果没有给f1赋值,访问的f1就是函数f1--->console.log(f1);--function f1(){}
</script>
通过识别预解析的结果,加深理解: