JS----函数与对象

121 阅读8分钟

函数

一、函数的概念

  • 什么是函数?
    • 首先明确一点,和我们数学中的函数是两个概念
    • 在 JS 中,函数可以理解为将一段在程序中多次出现的代码封装起来的盒子,以便在多个地方调用执行
    • 换句话说:函数就是一个内部封装了部分代码的盒子,可以在多个位置被调用
  • 函数的使用
    • 创建函数(定义函数)
    • 调用函数

二、函数的定义

1. 声明式定义

  • 语法: function 函数名(参数: 非必传, 暂时不写) { 函数被调用的时候需要执行的某一段代码 }
function fn() {

}
/**
 * 分析:
 *      function:声明函数的关键字,代表接下来这段代码是一个函数
 *      fn:函数名,调用函数时需要使用,函数名自定义,符合命名规范和见名知意即可(!** 匿名函数时可以不写)
 *      ():小括号内存放函数的参数(后续讲解)
 *      {}:存放函数代码,调用函数时,想执行的代码都写在内部
*/

2. 赋值式定义

  • 语法:var 函数名 = function (参数: 非必传, 暂时不写) {}
var fn = function () {

}

三、函数的调用

  • 调用的时候 不管如何定义, 都是使用 函数名()
  • 注意: 如果一个函数只定义, 而不调用, 那么永远不会执行
function fn1() {

}
var fn2 = function () {

}

fn1()
fn2()

四、变量和函数的预解析(预解释)

变量的规则(变量提升):
  • JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将变量的声明(定义) 提取到页面的最顶部(JS代码的最顶部)。
  • 注意: 提升的只有变量的声明, 没有变量的赋值。那么换句话说, 也就是在变量定义前去使用, 得到的是一个 undefined
        console.log(a)  // undefined
        var a = 100
        console.log(a)  // 100

        /*
            原本的代码
                console.log(a)
                var a = 100
                console.log(a)

            开始运行代码, 浏览器读取我们JS整体代码

            读取完毕, 预解析 后的代码

                var a
                console.log(a)  // undefined
                a = 100
                console.log(a)  // 100
        */
函数的规则(函数提升):
  • JS 在运行我们的代码的时候, 会先整体阅读一次我们的 JS 代码,此时读取完毕后, 会将声明式定义的函数 提取到页面的最顶部(JS代码的最顶部)。所以我们在书写代码的时候, 可以在 声明式定义的函数前, 去调用函数
        console.log(a)  // undefined
        var a = function () { console.log('我是a函数') }
        console.log(a)  // ƒ () { console.log('我是a函数') }
        /*
            原本的代码
                console.log(a)
                var a = function () { console.log('我是a函数') }
                console.log(a)

            开始运行代码, 浏览器读取我们JS整体代码

            读取完毕, 预解析 后的代码

                var a
                console.log(a)  // undefined
                a = function () { console.log('我是a函数') }
                console.log(a)  // ƒ () { console.log('我是a函数') }
        */
        console.log(a)  // ƒ a () { console.log('我是a函数') }
        function a() {
            console.log('我是a函数')
        }
        console.log(a)  // ƒ a () { console.log('我是a函数') }

        /**
         原本的代码
                 console.log(a)  // ƒ a () { console.log('我是a函数') }
                 function a () { console.log('我是a函数') }
                 console.log(a)  // ƒ a () { console.log('我是a函数') }
         
             浏览器读取我们的JS整体代码, 开始函数提升
         
             提升后的代码:
                 function a () { console.log('我是a函数') }
                 console.log(a)
                 console.log(a)
        */

四、函数的参数

  • 参数是什么?
    • 如果没有参数,那么函数的执行功能是固定的,写好函数后内部内容将不会变
    • 比如:函数内部的代码为 1 + 1,那么始终执行时始终都是 1 + 1,如果此时想要计算 1 + 2 的值,需要重新封装一个 1+2 的函数
  • 参数在哪里?如何使用
    • 书写函数时有一个 () 内部就是书写参数的,函数分为两种,形参---实参
    • 1)形参:函数定义时小括号中书写的内容,相当于在函数中创建了一个变量 具体的值由实参提供,如果实参没有传递对应的内容,那么值为undefined
    • 2)实参:函数调用时小括号中书写的内容,这里书写的内容会传递给对应的形参
   function num () {
       console.log(1 + 1)
   }
   num()   // 打印值为 1+1

   function num (a, b) {   // 此处 a b 为形参
       console.log(a + b)
   }
   num(1, 1)   // 此处为 实参,分别传递给 a  和  b
   num(1, 2)   // 此处打印值为 1 + 2

注意: 函数的形参与实参是按照从左到右的顺序一一对应的

   // 少传参数
   function num1(a, b, c, d) {
       console.log(a,b,c,d)
   }
   num1(1, 2, 3, 4)    // 打印1,2,3,4
   num1(1, 2, 4) // 打印1,2,4,undefined
   num1(4) // 打印4,undefined,undefined,undefined
   // 多传参数
   function num2 (a) {
       console.log(a)
   }
   num2(1, 2)  // 打印 1
   num2(1)  // 打印 1

五、函数的返回值

  • 每一个函数调用完毕后 都会有一个结果(值), 默认为 undefined
  • 如果想要更改那么我们需要借助一个 关键字 return
  • return 的后边可以跟 任何的数据, 包括表达式
  • 注意:函数中 return 只会生效一个, 因为 return 具有中断函数的能力,所以一般 return 会写在函数的末尾。如果想要写在函数的开头, 必须结合分支语句

六、作用域

  • 简单来说: 就是一个变量生效的范围

全局作用域

  • 整个 script 标签内部的区域声明的变量就是在全局作用域创建
  • 如果是在全局作用域创建的变量或者函数我们统称为 全局变量或者全局函数,那么能在当前代码的所有位置去使用
  • JS 在全局作用域中提供了一个 对象, 叫做 window, 我们书写的所有的 全局变量或者全局函数, 都在 window 对象内部存放

局部作用域(函数作用域)

  • 在一个函数内部生成的变量就是存在于局部作用域的
  • 在局部作用域创建的变量只能在当前作用域内使用

七、作用域链

  • 每一个作用域上一层会有一个全新的作用域, 每个作用域之间的一个连接, 我们称之为作用域链
  • 如果我们在一个作用域内寻找一个变量, 那么我们会在当前作用域内查找, 如果找到直接使用;如果没有找到, 那么会继续去上一层作用域继续查找, 找到就使用, 如果没有找到继续去上一层查找。所以我们将这个层层查找的顺序之间的连接, 称之为作用域链
作用域链分为两个规则:
1. 查找规则
  • 在一个作用域内查找一个变量, 如果有直接使用, 如果没有会去上一层继续查找, 如果找到直接使用, 没有的话继续去上一层查找, 直到找到了全局作用域, 找到了直接使用, 如果没有找到直接报错
  • 注意: 查找的时候只会层层向上, 不会向下
2. 赋值规则
  • 在一个作用域对一个变量进行赋值, 那么会先在当前作用域内查找变量, 找到直接修改, 如果没有, 会去上一层作用域查找。如果找到直接修改, 没有继续向上, 如果找到了全局作用域还是没有, 那么会在全局作用域创建一个变量, 然后对他进行赋值操作

八、递归函数

  • 在编程中就是指 自己调用自己的一种手段。递归函数就是在一个函数内部调用了自身. 循环执行
  • 递归函数有点类似于循环,也需要有初始化, 自增, 执行的代码, 判断条件。如果上述的内容缺少, 那么就是一个死递归, 永远不会结束
求 1~5 的所有数字相加的和
        function fn(n){
            if(n === 1) return 1
            return n + fn(n - 1)
        }
        let res = fn(4)
        console.log(res)
递归求阶乘
        function fn(n) {
            if(n === 1) return 1
            return n * fn(n - 1)
        }
        let res = fn(5)
        console.log(res)  //120
使用递归封装一个函数, 能够计算出斐波那契数列中某一个位置的具体数值
        function fn(n) {
            if (n === 1 || n === 2) return 1
            return fn(n - 1) + fn(n - 2)
        }
        var res1 = fn(4)
        console.log(res1)  //3

对象

对象是一个 复杂数据类型, 也叫做 引用数据类型

   var obj = {
   num: 100,
   str: "hello",
   boo: true,
};
  • 这里的 {} 和函数中的 {} 不一样, 函数内部书写代码, 对象里面是书写数据的
  • 对象就是一个键值对的集合
    • 什么是键值对?
      • 对象 obj 中, num 是键, 100 是值
      • 对象 obj 中, str 是键, 'hello' 是值
      • 对象 obj 中, boo 是键, true 是值

创建对象

  • 字面量方式创建对象
    • 语法:var obj = {} var obj1 = {键值对, 键值对}
  • 内置构造函数创建
    • 语法:var obj = new Object()
  • 对象内对于 键(key) 的要求
    • 推荐使用符合变量命名规则和规范的名字
    • 可以使用纯数字当作 键名
      • 这种情况下该属性会排列在最前面
    • 可以使用任何特殊符号
      • 使用特殊符号的时候,在书写时需要被引号包裹

对象数据类型的操作(增删改查)两种语法

1. 点语法

  var obj = {};
  obj.name = "qianfeng"; // 增
  obj.name = "qianfeng123"; // 改
  console.log(obj.name); // 查
  delete obj.name; // 删

2. 中括号语法(数组语法)

   var obj = {}
   obj["name"] = "qianfeng"  //增
   obj["name"] = "qianfeng123"  //改
   console.log(obj["name"])  //查
   delete obj["name"]  //删
  • 两者的差异
    • 符合变量命名规范与规则的情况,两者并无差异
    • 操作不符合变量命名规范与规则的名称时,比如纯数字或者带有特殊符号的,就只能用中括号语法
    • 涉及变量相关的时候,只能使用中括号语法