函数的概念
函数就是封装了一段可以被重复执行调用的代码块。
函数的目的就是让代码可以重复使用
声明及调用
声明函数
-
自定义函数方式(命名函数)
function 函数名(){ //函数体 }
-
因为有名字,所以也被称为命名函数
-
调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面
-
-
函数表达式(匿名函数)
// 这是函数表达式写法,匿名函数后面跟分号结束 var fn = function(){ //函数体 }; // 调用的方式,函数调用必须写到函数体下面 fn();
- 因为函数没有名字,所以也称为匿名函数
- 这个fn 里面存储的是一个函数,不是变量
- 匿名函数也可以传参
- 函数调用的代码必须写到函数体后面
调用函数
-
方法一:函数名();
//声明函数 function fn(){ console.log(1); } //调用函数 fn();
-
方法二:在事件中调用,直接写函数名,不使用括号
//声明函数 function fn(){ console.log(1); } //在点击事件中调用函数 document.onclick = fn;
函数封装
函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口
函数传参
参数 | 说明 |
---|---|
形参 | 形式上的参数,函数定义的时候传递的参数,接收实参 |
实参 | 实际上的参数,函数调用的时候传递的参数 |
- 函数的参数可以没有,也可以有很多个
- 函数的实参与形参的个数可以不一样,但尽量保持一致
- 如果实参数多于形参,则以形参数作为标准,形参有几个就取几个实参
- 如果实参数少于形参,则多余的形参就会是
undefined
function fn(形参1,形参2...){
//函数执行代码
}
fn(实参1,实参2...);//调用时传参
函数的返回值
return
- 所有函数都会有函数返回值即函数执行后一定会返回一个结果,如果没有定义默认返回undefined;
- 在函数中,reture会终止函数,return之后的代码就不会再执行了
- return只能用于函数中,用在其他地方会报错
- return只能返回一个值,如果用逗号隔开多个值,只会返回最后一个值
break、continue、return 的区别
break
: 结束当前循环continue
:跳出本次循环,继续执行下次循环return
:不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
arguments
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。
- arguments存放的是传递过来的实参
- arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性
- 按索引方式储存数据
- 不具有真正的数组的方法,如push() , pop() 等方法
// 函数声明
function fn() {
console.log(arguments); //里面存储了所有传递过来的实参
console.log(arrguments.length); // 3
console.log(arrguments[2]); // 3
}
// 函数调用
fn(1,2,3);
作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域
整个 script 标签或者一个独立的 js 文件
全局变量
- 在全局作用域下的变量就是全局变量,全局都可以使用
- 在函数内部没有声明直接赋值的变量也是全局变量
- 全局变量在浏览器关闭时销毁
局部(函数)作用域
作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域
局部变量
- 在局部作用域下的变量是局部变量,只能在定义它的函数内使用
- 函数的形参也看做局部变量
- 局部变量在函数执行完就会销毁
var num = 10; //全局变量
console.log(num); //10
function fn() {
var num = 20; //局部变量
console.log(num); //20
}
fn();
console.log(num); //10
JS 没有块级作用域(在ES6之前)
在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用。
Java会报错:
if(true){
int num = 123;
System.out.println(num); // 123
}
System.out.println(num); // 报错
JS 中没有块级作用域(在ES6之前):
if(true){
int num = 123;
System.out.println(num); // 123
}
System.out.println(num); // 123
作用域链
- 只要是代码,就至少有一个作用域
- 写在函数内部的叫局部作用域
- 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
- 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
- 作用域链采取就近原则的方式来查找变量最终的值
预解析
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
-
预解析:js引擎会把js里面所有的
var
还有function
提升到当前作用域的最前面-
注意,下面的
fun
是变量名,不是函数名,fun()
才是函数名var fun = function() { //函数体 }
-
-
代码执行:从上到下执行JS语句
预解析
- 变量预解析(变量提升):只提升变量声明,不会提升赋值
- 函数预解析(函数提升):函数的声明会被提升到当前作用域的最上面,但是不会调用函数
预解析重要案例(有点意思( •̀ ω •́ )✧)
- 源代码
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
- 经过预解析之后
function f1() { //函数提升
var a = 9; //声明且赋值,局部变量
b = 9; //未声明直接赋值,全局变量
c = 9; //未声明直接赋值,全局变量
//a = b = c = 9;
//正常的集体声明应该是var a = 9, b = 9, c = 9
// 而不是var a = b = c = 9;
console.log(a); //9
console.log(b); //9
console.log(c); //9
}
f1();
console.log(c); //9
console.log(b); //9
console.log(a); //报错 a是局部变量