写在之前:在JS中,函数作为一个重要的组成部分,它以其私有上下文、变量信息存储、创建构造函数等独特性,我们将其称为一等公民。同时由于其 高复用、低耦合的特点,在VUE、REACT中,也开始大面积的体现 函数式编程 这一概念
函数
- 函数的基本组成:形参、函数体、实参、函数调用等部分构成
function add(x,y) {
return x+y
}
add(1,2)
- 我们将定义函数设置的值,称为形参。在函数调用执行时,所传递的值称为实参
- 函数属于引用类型,所以函数会存放在堆内存中,其 函数体 会以字符串的形式存储。我们称之为 “代码字符串”。在函数不执行的情况,这个函数毛用没有,弃之如敝履。
- 同时函数本身也是一个对象,它是会存储自己特有的键值对
name: add; length: 2; prototype ....。同时我们也可以给其设置私有的键值对。 - 函数执行:就是将函数堆中的代码字符串进行执行。在执行前,会构建自己的执行环境,创建执行上下文。
作用域与作用域链
- 作用域[[scope]]: 函数的作用域就是 创建这个函数所在的上下文。
- 在函数创建的时候,就会定义这个函数的作用域
- 作用域链[scopeChain]: 在代码执行的时候,会构建一条作用域链,它的左侧是当前的上下文,右侧是函数的作用域。 <当前上下文, 函数作用域>
- 目的:在后期执行函数的时候,我们经常会遇到变量,在使用变量时,我们会先查看是否是自己的私有变量,如果是则直接使用,如果不是则要沿着这条链向上查找,直到找到全局上下文为止。
示例
var a=[10,11];
function fn(b) {
b[0] = 100; b = [200]; b[1] = 300;
console.log(b);
}
fn(a);
log(a);
函数执行的步骤:
- 1.创建新的执行上下文
- 2.将执行环境栈ECStack 中的上下文进行压栈处理
- 3.将新创建的执行上下文进行进栈
- 4.执行函数
- 5.执行完成,进行出栈操作
在函数执行前的初始化工作
-
- 初始化作用域链
-
- 初始化this 指向
-
- 初始化 argument 实参集合
-
- 形参赋值: 存放在自己私有上下文中的 变量对象(AO) 中
-
- 变量提升
-
- 代码执行
上层示例执行
- 创建执行环境栈(ECStack),创建全局上下文EC(G)
- 将全局变量存放到全局变量对象中VO(G)
- a----->AAAFFF000 AAAFFF000 --存放数组--> [10,11]
- fn----->AAAFFF111 AAAFFF111 --存放函数堆--> fn,创建作用域[[scope]]: EC(G)
- fn(a) 代码执行,创建私有上下文 EC(FN)
- 初始化作用域链 <EC(FN), EC(G)>
- 初始化THIS: window
- 初始化arguments
- 形参赋值: b = AAAFFF000
- 变量提升
- 代码进栈执行
- 代码执行:
- b[0] = 100; 将 AAAFFF000 中的第一项变为 100;
- b = [200]; 修改形参B的指针指向 从
AAAFFF000变为AAAFFF111 - b[1] = 300;给AAAFFF111 增加修改变量信息
- log(b) ==> [200,300]
- log(a)
- [100, 11];
arguments 的问题
- arguments 实参变量,它内部的数据,是函数调用时,给的实参的数据
- 它与形参会形成映射机制,但是当arguments 没有对应的形参变量时,就算后期更改形参数值,也影响不了arugments的映射机制
var a = 4;
function b(x,y,a,b) {
console.log(a);
arguments[2] = 10;
console.log(a);
x = 100;
b = 200;
console.log(arguments[0])
}
a = b(1,2,3)
console.log(a);
- a=b(); 获取的是b执行的返回值,如果没有return,那么就是undefined;
- 在非严格模式下: arguments 和 形参赋值 形成映射关系,无论形参改变 还是 arguments 改变,都是一改都改
- 在严格模式下: arguments 和 形参赋值 没有映射关系。一个改变,另一个不会改变
x ---> arguments[0] y ---> arguments[1] a ---> arguments[2] - arguments 中,由于传入的实参没有 b,所以开始就不会形成映射关系。就算后期给形参赋值,也不会增加映射关系
- 最终的 arguments: {0: 100; 1: 2; 2: 10; length: 3}
函数式编程
- 在JS中,有几种编程范式:面向过程编程、面向对象编程 函数式编程
- 面向过程:本质是写好每一步,然后让js代码从上往下运行
- 面向对象编程:万物是对象,定义好类后,创建对象,然后通过new的方式,在实例上进行操作
- 函数式编程: 是一种数学运算关系,属于一种映射关系。参数是输入的内容,return返回值是输出的内容。同时做到相同的输入,会得到相同的输出。
y=f(x)
对于头等功民的理解
- 在一门语言中,当函数可以作为变量一样使用的时候,那么就说这么语言拥有头等函数。
- 也可以换一种说法:函数可以赋值给变量、可以作为参数、可以作为返回值 来使用
在函数中,还存在很多的类型,比如高阶函数、闭包、纯函数、柯里化等等。后面进行研究。