函数的意义在于封装:把实现某一个功能的代码封装在一起,后期在想实现这个功能,只需要执行函数即可,不需要重新编写这些代码了。
“低耦合、高内聚”:减少代码的冗余,提高代码使用率。
return 返回值
return会直接返回值 ;return会打断函数执行
function sum(x, y) {return x + y;console.log(123);}sum(1,2);//返回值为3,但是不会输出123
arguments实参合集
arguments函数内置的实参集合:不管我们设置与否形参,再或者是否传递了实参
ARGUMENTS始终都会存在(ES6箭头函数中没有ARGUMENTS)
arguments是一个类数组集合(类似数组,但是不是数组)
根据索引记录了每一个传递进来的实参信息(和是否定义形参变量没有关系,ARGUMENTS中包含了所有传递进来的实参信息)
length属性代表传递实参的个数
arguments 是函数获得到所有参数集合,下面是使用 arguments 求和的例子
function sum() {return [...arguments].reduce((total, num) => {return (total += num);}, 0);}console.log(sum(2, 3, 4, 2, 6)); //17
更建议使用展示语法
function sum(...args) {return args.reduce((a, b) => a + b);}console.log(sum(2, 3, 4, 2, 6)); //17
函数创建的具体过程
- 创建值
- 开辟一个堆内存
- 把函数体中的代码当做字符串存储到堆中
- 把堆地址放到栈中
- 创建变量
- 让变量和地址关联
注:创建函数,其实就是创建了一个储存了一堆字符串的堆而已,并没有实际作用。

函数执行的具体过程
执行过程
- 形成一个私有的执行上下文(AO),然后进栈执行
- 初始化作用域链
- 初始化THIS
- 初始化ARGUMENTS
- 形参赋值
- 变量提升
- 代码执行
- 根据情况决定是否出栈释放
作用域
创建函数的时候就声明了它的作用域,在哪个上下文中创建的,那它作用域就是哪个上下文
作用域和上下文是同一意思
是,都是函数执行形成的那个空间,FN的作用域【ECG】ECG 也是全局上下文 从核心来说 都是栈内存
函数自己执行形成的EC(FN) 上下文
函数创建的时候声明了它的作用域
函数执行会形成一个”全新”的”私有”的执行上下文 然后进栈执行
一般情况下,函数执行完,形成的这个私有上下文会出栈释放 来优化内存空间
EC(FN) 私有执行上下文
AO(FN) 私有变量对象 [私有上下文声明的变量都存储在这里=>私有变量]
- AO[active object]是VO的分支,函数私有上下文中[AO]
- 私有变量(AO):
- @1 形参变量
- @2 函数体中声明过的变量
代码执行前的步骤
- 初始作用域链:scope chain
- 初始化THIS
- 初始ARGUMENTS—实参集合
- 形参赋值
- 变量提升
作用域链
<自己的上下文【执行产生的】,函数的作用域【创建时候声明的】>
作用域链机制
- 私有上下文中,变量,首先看是否为自己上下文中的私有变量,如果是自己的【AO】,则接下来所有操作,都是操作自己的
- 如果不是自己私有的变量,则按照作用域链,查找是否为其上级上下文中变量【上级上下文就是函数的作用域】如果找到了,则后期操作的都是上级上下文中的变量
- 如果上级上下文也没有这个变量,则继续找其”上上级”上下文,一直到EC(G)全局上下文位置
- 如果全局上下文中也没有
- 获取变量值就是报错
- 设置变量值就是给window设置的属性
作用域链只向上查找,找到全局window即终止,应该尽量不要在全局作用域中添加变量。
匿名函数
没有名字的函数
1.匿名函数的第一种情形【事件绑定】
var btn=document.querySelector("#btn");btn.οnclick=function(){// alert("document");}
2匿名函数的第二种情形【定时器】
//定时器//setTimeOut(函数体,时间) 多少毫秒之后执行(只执行一次)//setInerval(函数体,时间) 每隔多少毫秒一次//清定时器用clearInterval(timer);setTimeout(function(){console.log("只执行一次呀");},1000);var timer=setInterval(function(){console.log("每隔两秒执行一次");},2000);//10秒停止 清空定时器setTimeout(function(){clearInterval(timer);},10000);
3. 匿名函数的第三种情形【匿名函数具名化】
var fn = function () {};fn();
4. 匿名函数的第四种情形【作为对象中的一个属性】
var obj={name:"dddd",say:function(){alert(this.name);}}obj.say();
箭头函数
与普通函数的区别:
1.没有arguments
2.没有自己的this,this是执行上下文的this
let fn = () => {};//如果箭头函数只有一个参数,可省略小括号,只写形参let fn2 = str => {};//如果大括号内,除了return没有多余语句,可省略大括号和returnlet fn3 = num => num + 1;// 写全=>let fn3 = (num) => {return num + 1};
自执行(匿名)函数
一个函数在定义后立即执行
let a = (function () {console.log(123);//可以拿到返回值return 1;})();let b = ~ function () {console.log(123);//拿不到返回值return 2;}();console.log(a, b);//=>1 -3因为2按位取反的值就是-3
回调函数
- 把一个函数作为[实参‘值’]传递给另外一个函数
function fn(callback){callback();}fn (function (){});
递归
函数自己调用自己,叫做递归
边界条件:用来停止递归的,如果没有边界条件,则会成为死循环
//求1-100的累加结果function sum(n) {//边界:停止条件if(n<0) {return 0}return n+=sum(n-1);}sum(100)
