初识函数
函数的意义在于封装
应用:把实现某一个功能的代码封装在一起,后期在想实现这个功能,只需要执行函数即可,不需要重新编写这些代码了。
目的:“低耦合、高内聚”:减少代码的冗余,提高代码使用率。
函数的参数
形参
定义:「变量」,用来接收后期执行时候,传递进来的实参值
-
生产一个函数,想要实现一些功能,但是实现功能,需要的原材料不确定,需要用户执行它的时候给我,我才知道,此时我们就提供入口 => 形参(变量)
-
设置形参,但是不传递实参,默认值是undefined
作用:“用来存储执行函数时,传递进来的信息”
实参
定义:执行函数的时候,给指定的入口(形参变量)传递的具体值(值)
function sum(n, m) {
// n/m:形参「变量」,用来接收后期执行时候,传递进来的实参值
// 需求:如果n/m的值是非有效数字,我们让其为0
n = +n;
m = +m;
if (isNaN(n)) {
n = 0;
}
isNaN(m) ? m = 0 : null;
var total = n + m;
console.log(total);
}
sum(10, '20'); //n=10 m='20'
sum(10); //n=10 m=undefined 设置形参,但是不传递实参,默认值是undefined
return 返回值
定义:return是函数的返回值机制「出口」:return后面放的是“值”
作用:把变量的值暴露给外面使用 打断函数执行
-
函数里面return 多少,这个函数的返回值就是多少,如果没有返回值,就是undefined;
-
return会打断函数执行,函数体中遇到return,直接返回结果即可,后面的代码则不再执行了
function sum(n, m) {
n = +n;
m = +m;
isNaN(n) ? n = 0 : null;
isNaN(m) ? m = 0 : null;
var total = n + m;
// console.log(total); //里面用total肯定可以,因为是自己家的「大括号/函数体相当于单独的一家人」
// return是函数的返回值机制「出口」:return后面放的是“值”,所以此处“return total; -> return 30;”
// + 如果不写return,我们默认返回值是undefined
// + 函数体中遇到return,直接返回结果即可,后面的代码则不再执行了
return total;
}
// 外面叫做total,和里面的不是一个变量,没啥直接的关系
// + sum() : 函数执行,代表的是函数执行后的返回值「RETURN」
// + sum : 变量/函数名,代表的创建的函数本身「堆内存地址」
var total = sum(10, '20');
console.log(total / 2); //Uncaught ReferenceError: total is not defined
arguments
定义:arguments函数内置的实参集合
- 不管我们设置与否形参,再或者是否传递了实参 ARGUMENTS始终都会存在
- ES6箭头函数中没有ARGUMENTS
形式:arguments 是一个类数组集合
- 类似数组,但不是数组,和元素集合 HTMLCollection 类似
原理 根据索引记录了每一个传递进来的实参信息
-
和是否定义形参变量没有关系,ARGUMENTS中包含了所有传递进来的实参信息
-
length属性代表传递实参的个数
任意数求和
//思路:不管传递几个实参值进来,我们都能求出对应的和
//传递的是非有效数字,则按照0处理(或者不处理)
//传递的是字符串,需要先变为数字再求和,避免字符串拼接
function sum() {
// arguments:内置实参集合「包含了传递进来的所有实参值 “类数组集合”」
var total = 0;
for (var i = 0; i < arguments.length; i++) {
// 获取当前循环的集合中的这一项,并且把其变为数字
var item = +arguments[i];
// 如果item不是一个有效数字,则结束当前这轮循环「不求和了」,继续下一轮即可
if (isNaN(item)) continue;
total += item;
}
return total;
}
console.log(sum(10, 20, '30', 'AA', 40));//100
console.log(sum(10, 20, 30));//60
console.log(sum(10));//10
console.log(sum()); //0
创建函数和执行函数在堆栈内存中的逻辑
- E(execution)C(context)Stack:执行环境栈,又名“栈内存”
- EC:私有的上下文
- EG:全局执行上下文(全局代码都在这里执行)
- AO:私有变量对象
- VO:全局变量对象(全局上下文声明的变量都在这里)
创建函数
语法:function 函数名(形参){ 函数体 }
创建过程
- 第一步:创建值:
- 1、开辟一个堆内存
- 2、把函数体中的代码当作字符串储存在堆中
- 3、把堆地址放到栈中
- 第二步:创建变量
- 第三步:让变量和地址关联 只创建函数,但不执行,函数没有任何意义,因为它只是开了堆内存,存储了一堆字符串而已
执行函数
语法:函数名(实参)
目的:把创建的函数执行(把函数体中的代码执行)
执行过程
- 形成一个全新的私有上下文,并且进栈执行
- 在私有上下文中,也有一个存放自己变量和值的地方:AO 私有变量对象
- 把之前存放在堆内存中的代码,字符串拿出来执行
- 执行代码之前,还有很多很多步骤...eg:this,变量提升
- 当上下文中的代码都执行完后,如果该上下文中的信息没有被外界占用的情况,则执行完出栈(释放掉)以减少栈内存中的空间;
函数的表达形式
实名函数:有函数名的
匿名函数:没有名字的函数
函数表达式:把一个函数作为值,赋值给一个变量或者一个事件绑定等
var sum = function () {};
box.onclick = function () {};
自执行函数:创建和执行都一起完成的
用小括号包起来,或者前面加“~/+/!”等都是为了保证语法不出错
- (function(n){...})(实参)
-
- function(n){...}(实参)
-
- function(n){...}(实参)
- ~ function(n){...}(实参)
- ! function(n){...}(实参)
var res = (function (i) {
// ...函数体
return 100;
})(10); */
~function(){}();
!function(){}();
+function(){}();
回调函数:把一个函数作为“实参「值」”传递给另外一个函数
function fn(callback) {
// callback : 传递进来的匿名函数
callback();
}
fn(function () {});
var arr = [11, 2, 5, 34, 24];
// sort是一个内置函数,此处是把sort执行
arr.sort(function (a, b) {
return a - b;
});
把数组的forEach方法执行,传递一个匿名函数A「回调函数」,那么在forEach内部,就可以获取到这个A
接下来forEach内部干了点事情:循环数组中的每一项,每循环一次都把A执行一次「数组有多少项,回到函数A就要被执行多少次」,并且把每次循环得到的当前项和当前项索引,传递给A的item/index...
-> A : function(item,index){}
var arr = [11, 2, 5, 34, 24];
arr.forEach(function (item, index) {
// item:当前项
// index:当前项的索引
});
箭头函数
与普通函数的区别:
- 没有arguments
- 没有自己的this,this是执行上下文的this
let fn = () => {};
//如果箭头函数只有一个参数,可省略小括号,只写形参
let fn2 = str => {};
//如果大括号内,除了return没有多余语句,可省略大括号和return
let fn3 = num => num + 1;
// 写全=>let fn3 = (num) => {return num + 1};