# 关键字function

前言

包裹语句,可以在特定情况下重新执行

# 1.创建函数

  • 在全局作用域下声明(预解释的时候)的变量是全局变量
  • 在 私有作用域中声明的变量 和 函数的形参 都是私有的变量

# 1.1 函数声明

# 1.2 函数表达式

# 1.3 匿名自执行函数

  • 声明和执行在一起
;(function () {
  console.log("aaaa")
})()
1
2
3

# 1.4 构造函数

var fun = new Function("console.log('hello 这是我的第一个函数');")
1

# 2.执行函数

# 2.1 执行顺序

  • 1.形成一个新的私有的作用域
  • 2.如果有形参,先给形参赋值
  • 3.进行私有作用域中的预解释
  • 4.私有作用域中的代码从上往下执行

# 2.2 案例

// 首选代码从上往下预解释声明 total,然后从上往下执行代码,total 此时没有被赋值所有为 undefined
console.log(total) //-->undefined
var total = 0
1
2
3
  • 同理私有作用域下面也是,声明了 total 但是没有赋值,结果为 undefiend
var total = 0
function fn(num1, num2) {
  console.log(total) //undefined
  var total = num1 + num2
  console.log(total) //-->300
}
fn(100, 200)
console.log(total) //-->0
1
2
3
4
5
6
7
8
  • 私有作用域下面没有 total,顺着作用域链向上查找,找到全局的 total=0
console.log(total) //-->undefined
var total = 0
function fn(num1, num2) {
  console.log(total) //total 不是私有的找全局下的 total 找这里出现的所有的 total 其实应该是全局的-->0
  total = num1 + num2
  console.log(total) //-->300
}
fn(100, 200)
console.log(total) //-->300
1
2
3
4
5
6
7
8
9

# 2.3 递归

函数内部执行代码时又执行自身的过程

function fn(num) {
  let i = num - 2
  if (i > 0) fn(i)
}
fn(111)
1
2
3
4
5

# 3.作用域

在私有作用域中,我们代码执行的时候遇到了一个变量,首先我们需要确定它是否为私有的变量,如果是私有变量,那么和外面的没有任何的关系;如果不是私有的,则网当前作用域的上级作用域进行查到,如果上级作用域也没有则继续查找,一直找到 window 为止...(作用域链)

# 3.1 作用域链

# 3.2 闭包

  • 函数形成了一个新的私有的作用域保护了里面的私有变量不受外界的干扰(外面修改不了私有的,私有的也修改不了外面的)

# 3.3 柯里化

  • 代码预处理思想

利用函数执行可以形成一个不销毁的私有作用域的原理,把需要预先处理的内容都存储在这个不销毁的作用域中,并且返回一个小函数,以后我们执行的都是小函数,在小函数宏把之前预先存储的值进行相关的操作

函数柯里化:是指将多变量函数拆解为单变量的多个函数的依次调用,可以从高元函数动态的生成批量的低元的函数。

  • 原函数
let add = (x, y) => x + y
add(1, 2)
1
2
  • 柯里化函数
let add = (x) => (y) => x + y
add(1)(2)
1
2

# 4.this

//我们在js中主要研究的都是函数中的this
//js中的this代表的是当前行为执行的主体,js中的context代表的是当前行为执行的环境(区域)
//this是谁和函数在哪定义的和在哪执行的都没有任何关系,如何区分this呢
//1、函数执行,首先看函数名前面是否有".",有的话,"."前面是谁this就是谁,没有的话this就是windwo
function fn() {
  console.log(this)
}
var obj = { fn: fn }
f() //this -->window
obj.fn() //this-->obj

function sum() {
  //this-->windwo
  fn()
}
sum() //this-->window

var oo = {
  sum: function () {
    //this-->oo
    fn()
  },
}
oo.sum() //this-->window

//2、自执行函数中的this永远都是window
//3、给元素的某一个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的this是当前的元素
document.getElementById("div").onclick = fn //fn-->this -->div
document.getElementById("div").onclick = function () {
  //this-->div
  fn() //this-->window
}

/* 练习题 */
var num = 20
var obj = {
  num: 30,
  fn: (function (num) {
    this.num *= 3
    num += 45
    var num = 45
    return function () {
      this.num *= 4
      num += 20
      console.log(num)
    }
  })(num), //把全局变量num的值20赋值给自执行函数的形参,而不是obj的30,如果想是obj下的30,我们要写成obj.num
}
var fn = obj.fn

fn() //-->65
obj.fn() //-->85
console.log(window.num, obj.num) //-->240,120
//window
!(function () {})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55