大前端学习笔记之JS Day07

函数(下)

作用域

全局作用域

  • 全局作用域是最大的作用域
  • 在全局作用域中定义的变量可以在任何地方使用
  • 页面打开的时候,浏览器会自动给我们生成一个全局作用域 window
  • 这个作用域会一直存在,直到页面关闭就销毁了
// 下面两个变量都是存在在全局作用域下面的,都是可以在任意地方使用的
var num = 100
var num2 = 200

局部作用域

  • 局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域
  • 在局部作用域中定义的变量只能在这个局部作用域内部使用
  • 在 JS 中只有函数能生成一个局部作用域,别的都不行
  • 每一个函数,都是一个局部作用域
// 这个 num 是一个全局作用域下的变量 在任何地方都可以使用
var num = 100

function fn() {
  // 下面这个变量就是一个 fn 局部作用域内部的变量
  // 只能在 fn 函数内部使用
  var num2 = 200
}

fn()

预解析

  • 预解析 其实就是聊聊 js 代码的编译和执行

  • js 是一个解释型语言,就是在代码执行之前,先对代码进行通读和解释,然后在执行代码

  • 也就是说,我们的 js 代码在运行的时候,会经历两个环节 解释代码执行代码

    解释代码

    • 因为是在所有代码执行之前进行解释,所以叫做 预解析(预解释)

    • 需要解释的内容有两个

      • 声明式函数

        • 在内存中先声明有一个变量名是函数名,并且这个名字代表的内容是一个函数
      • var关键字

        • 在内存中先声明有一个变量名

      例:

              console.log(num);
              var num = 100;
              console.log(num);
      // 预解析 
      
              // 1 .不需要
              // 2. 需要预解析  告诉浏览器 定义了一个叫做num的变量 但是不赋值
              // 3. 不需要
      
              // 代码执行 
              // 1. console.log(num); 因为预解析的时候仅仅是 声明 但是没有赋值  
              //所以结果是undefined  
              // 2. num = 100 
              // 3 打印num 的值输出到控制台  
      

预解析重名问题

例1:

        fn();
        function fn(){console.log('hello world')}
        fn();
        var fn = 100;
        fn();
// 预解析 
        // 1.不需要
        // 2.需要 声明一个fn的变量并且赋值为一个函数
        // 3.不需要
        // 4. 需要
        // => 声明一个fn的变量 暂时不赋值
        // 5.不需要

        // 预解析结束 fn变量存在并且是一个函数 

        // 执行 
        // 1. fn() 
        // => 正常调用 
        // 2. fn() 
        // => 同上 
        // 3. fn =100 
        // fn 本来是个函数 但是此刻赋值为100 把函数覆盖了
        // 4.fn() 
        // 把fn当做一个函数来看待 但是上一步 fn不再是函数了
        // fn is not a function ;

例2:

        fn()
        var fn = 100;
        fn()
        function fn() { console.log('你长的好像一个人,我妈妈的儿媳妇') }
        fn()


        // 预解析 
        // 1.不需要
        // 2.声明一个fn变量 但是没有赋值
        // 3.不需要
        // 4.需要 在浏览器声明一个fn的变量 并且直接给他赋值一个函数
        // 5.不需要
        // 预解析结束 fn被声明 并且是个函数



        // 执行阶段

        // fn()  正常调用
        // fn = 100 把变量赋值给fn ()

        // fn() 把fn当做一个函数来调用 而fn已经是个变量了 所以
        // 会报错  fn is not a function 

函数在两个阶段都做了什么

函数定义阶段

  1. 在堆内存中开辟空间
  2. 把函数体内的代码 原样复制到空间内
  3. 把内存的地址赋值给内存的函数名

函数调用阶段

  1. 按照函数名村的地址去找到对应的函数体

    先判断栈内存内是否有这个变量

    如果存在 也会判断里面是否存储着一个函数体

  2. 在调用栈内存云开拼一个新的函数执行空间 (一个函数可以被多次调用为了避免一个调用出现的结果影响所有的调用,所以每次的调用都会申请一个执行空间

  3. 在执行空间内 给形参赋值

  4. 在执行空间内 对函数体内的代码进行预解析

  5. 在执行空间内 对函数体内的代码 执行一遍

  6. 完成以后 这个执行空间被销毁 或者理解为空间被收回

变量使用规则

  • 有了作用域以后,变量就有了使用范围,也就有了使用规则
  • 变量使用规则分为两种,访问规则赋值规则

访问规则

获取变量的规则

  • 首先,在自己的作用域内部查找,如果有,就直接拿来用
  • 如果没有,就去上一级作用域查找,如果有,就拿来使用
  • 如果没有,就继续去上一级作用域查找,以此类推
  • 如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量 is not defined)

例:

var num = 100

function fn() {
  var num2 = 200

  function fun() {
    var num3 = 300

    console.log(num3) // 自己作用域内有,拿过来用
    console.log(num2) // 自己作用域内没有,就去上一级,就是 fn 的作用域里面找,发现有,拿过来用
    console.log(num) // 自己这没有,去上一级 fn 那里也没有,再上一级到全局作用域,发现有,直接用
    console.log(a) // 自己没有,一级一级找上去到全局都没有,就会报错
  }

  fun()
}

fn()
  • 变量的访问规则也叫做作用域的查找机制
  • 作用域的查找机制只能是向上找,不能向下找

例:

function fn() {
  var num = 100
}
fn()

console.log(num) // 发现自己作用域没有,自己就是全局作用域,没有再上一级了,直接报错

赋值规则

  • 当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值

  • 变量赋值规则:

    • 先在自己作用域内部查找,有就直接赋值
    • 没有就去上一级作用域内部查找,有就直接赋值
    • 还没有再去上一级作用域查找,有就直接赋值
    • 如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值
    function fn() {
      num = 100
    }
    fn()
    
    // fn 调用以后,要给 num 赋值
    // 查看自己的作用域内部没有 num 变量
    // 就会向上一级查找
    // 上一级就是全局作用域,发现依旧没有
    // 那么就会把 num 定义为全局的变量,并为其赋值
    // 所以 fn() 以后,全局就有了一个变量叫做 num 并且值是 100
    console.log(num) // 100
    

递归函数

在编程世界里面,递归就是一个自己调用自己的手段。

// 下面这个代码就是一个最简单的递归函数
// 在函数内部调用了自己,函数一执行,就调用自己一次,在调用再执行,循环往复,没有止尽
function fn() {
  fn()
}
fn()
//需要有初始化,自增,执行代码,条件判断的,不然就是一个没有尽头的递归函数,我们叫做 死递归

简单实现一个递归

  • 需求: 求 1 至 5 的和
    • 先算 1 + 2 得 3
    • 再算 3 + 3 得 6
    • 再算 6 + 4 得 10
    • 再算 10 + 5 得 15
    • 结束
  • 开始书写,写递归函数先要写结束条件(为了避免出现 “死递归”)
function add(n) {
  // 传递进来的是 1
  // 当 n === 5 的时候要结束
  if (n === 5) {
    return 5
  }
}

add(1)

再写不满足条件的时候我们的递归处理

function add(n) {
  // 传递进来的是 1
  // 当 n === 5 的时候要结束
  if (n === 5) {
    return 5
  } else {
    // 不满足条件的时候,就是当前数字 + 比自己大 1 的数字
    return n + add(n + 1)
  }
}
add(1)

对象

对象是复杂数据类型,万物皆对象

var obj = {
  num: 100,
  str: 'hello world',
  boo: true
}
//这里的 {} 和函数中的 {} 不一样
//函数里面的是写代码的,而对象里面是写一些数据的

对象就是一个键值对的集合

  • {} 里面的每一个键都是一个成员
  • 也就是说,我们可以把一些数据放在一个对象里面,那么他们就互不干扰了
  • 其实就是我们准备一个房子,把我们想要的数据放进去,然后把房子的地址给到变量名,当我们需要某一个数据的时候,就可以根据变量名里面存储的地址找到对应的房子,然后去房子里面找到对应的数据

创建一个对象

  • 字面量的方式创建一个对象
// 创建一个空对象
var obj = {}

// 像对象中添加成员
obj.name = 'Jack'
obj.age = 18
  • 内置构造函数的方式创建对象
// 创建一个空对象
var obj = new Object()

// 向对象中添加成员
obj.name = 'Rose'
obj.age = 20
  • Objectjs 内置给我们的构造函数,用于创建一个对象使用的

注:

 //建议使用第一种来创建对象 
        // 键的名字按照变量的命名规则 规范 
        // 不要有重复 后边 会覆盖前面
        // 可以使用纯数字 作为键名  自动把数字排到最前面
        // 也可以使用特殊符号作为键名  
        // 键的 可加单引号 可不加单引号 但是如果用特殊符号作为键名 必须加单引号 
        // 建议使用字符串作为键名

对象的操作

 var jianzeng = {
            name:'jiangjiang',
            age:18,
            ball:function(){
                return '千锋白巧克力'
            }
        }
 jianzeng.height = '181cm';
        alert(jianzeng.height)
delete 
        alert(jianzeng.age);
        delete jianzeng.age;
        alert(jianzeng.age);
 重新赋值就是改的过程 
        alert(jianzeng.name);
        jianzeng.name = 'xiaojiang'
        // alert(jianzeng.name);
        alert(jianzeng.age) // 查看静态属性
        alert(jianzeng.ball())//调用动态方法 

另一种写法

  • 增 对象名[‘键名’] = 值

  • delete 对象名[‘键名’] = 值

  • 改 对象名[‘键名’] = 值

  • 查 对象名[‘键名’]

        var pengpeng = {
            name:'rock',
            age:18,
            1:666,
            2:888,
            'aaa^bbb':999,
            'ccc-ddd':777
        }
        
         // //alert(pengpeng.1);报错
        // alert(pengpeng['1'])
        // // alert(pengpeng.aaa^bbb)
        // alert(pengpeng['aaa^bbb'])

注:

当对象的键名字中有 纯数字 特殊符号

这个时候 增删改查 要使用 中括号的方式引用

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340