重拾JS 函数

195 阅读5分钟

写在之前:在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.执行完成,进行出栈操作

在函数执行前的初始化工作

    1. 初始化作用域链
    1. 初始化this 指向
    1. 初始化 argument 实参集合
    1. 形参赋值: 存放在自己私有上下文中的 变量对象(AO)
    1. 变量提升
    1. 代码执行

上层示例执行

  • 创建执行环境栈(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];

qqq.png

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}

pp.png

函数式编程

  • 在JS中,有几种编程范式:面向过程编程、面向对象编程 函数式编程
  • 面向过程:本质是写好每一步,然后让js代码从上往下运行
  • 面向对象编程:万物是对象,定义好类后,创建对象,然后通过new的方式,在实例上进行操作
  • 函数式编程: 是一种数学运算关系,属于一种映射关系。参数是输入的内容,return返回值是输出的内容。同时做到相同的输入,会得到相同的输出。 y=f(x)

对于头等功民的理解

  • 在一门语言中,当函数可以作为变量一样使用的时候,那么就说这么语言拥有头等函数。
  • 也可以换一种说法:函数可以赋值给变量、可以作为参数、可以作为返回值 来使用

在函数中,还存在很多的类型,比如高阶函数、闭包、纯函数、柯里化等等。后面进行研究。