首页 > 其他分享 >JS知识点梳理之作用域、作用域链、柯里化、闭包

JS知识点梳理之作用域、作用域链、柯里化、闭包

时间:2022-11-10 11:46:10浏览次数:64  
标签:闭包 知识点 console 变量 作用域 add function

一、作用域与作用域链

作用域是指 js 变量使用时所存在的一个区域,分为全局作用域(window)和局部作用域(function、setTimeout...等都会产生局部作用域)。当局部作用域变量名与全局作用域变量名重复时,局部变量会覆盖全局变量。

在局部作用域使用变量时,如果在自己作用域找不到对应变量,则会往上一级作用域查找,直到全局作用域,如果全局作用域无此变量则会报 undefined。相反,全局作用域中无法使用局部作用域中的变量。

window.a = 1
function(){
  // 输出 1,虽然局部没有 a 变量,但是 全局中有。
  console.log(a)
  var b = 2
}
// 报错,全局中无法使用局部变量。
console.log(b)

上面这种一层层向外查询变量的过程叫做查询作用域链。而这种一层层局部作用域直到全局作用域的结构被称为作用域链。

// 全局作用域,声明了一个全局变量 a
var a = 100

// 函数会生成局部作用域
function acs(){
  // 在此局部作用域中声明一个局部变量 b
    var b = 50
  // 输出:100, 50
  console.log(a, b) // 执行过程:在此作用域查找变量 a,
                                      // 找不到-->往上一级作用域找-->在全局找到,使用全局作用域中的a
                                      // 在此作用域查找变量 b,查找到了,使用此局部变量的 b
}()

// 输出:b is not defined
console.log(a, b)

二、闭包(Closure)

1. 闭包是什么?

闭包是指在函数外部调用函数内部的局部变量,且在调用后局部变量不会被浏览器立即回收,会一直存在的一种私有变量。再简单点说就是函数返回函数。

红宝书中的描写:闭包是指有权访问另一个函数作用域中的变量的函数。

其实闭包就是返回一个函数,且这个函数对局部变量存在引用形成的包含关系就是闭包。

其实就是创建一个不会被 GC 回收的局部变量。也正因如此,闭包才会有内存泄漏的风险,需要在每次使用完后立刻清除。

闭包的形成:当前环境中存在指向父级作用域的引用。

2. 闭包的写法

// 使用自执行函数形成闭包
var add = function(){
    let sum = 0
  return function operation(){
      return sum = sum ? sum + 1 : 1
  }
}()

// 输出:1
add()
// 输出:2
add()
// 输出:3
add()
// 输出:4
add()

// 清除闭包,删除私有变量
add = null
// 输出:null
console.log(add)
// 输出:add is not function
add()

3. 闭包的作用

使用闭包的目的――隐藏变量,间接访问一个变量,在定义函数的词法作用域外,调用函数。

闭包通常在回调函数、私有属性、函数柯里化中使用。

4. 使用闭包实现多个图片点赞功能

使用闭包完成,多图点赞单独点赞功能,且每个 input 的点赞数量互不干扰。在这个例子中利用闭包声明了 5 个新的独立词法作用域。

<!-- * @Description: 闭包实现多图点赞 * @Author: CY小尘s * @Date: 2021-07-28 18:39:33 * @LastEditTime: 2021-11-08 17:19:37 * @LastEditors: Please set LastEditors-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>闭包实现多图点赞</title>
  </head>
  <style>
    ul li {      list-style: none;      float: left;      margin: 0px 20px 20px 0px;    }    ul li img {      width: 200px;      height: 200px;    }  </style>
  <body>
    <ul>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-0.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-1.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-2.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-3.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-6.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-7.jpg"
          alt="你好"
        />
        <input type="button" class="add" value="当前点赞数量(1)" />
      </li>
    </ul>

    <script>
      window.onload = function () {        // 获取 ul
        let add = document.querySelectorAll("ul li input");        // 循环取出每个 input 添加上闭包
        for (let i = 0; i < add.length; i++) {          // 给每个 input 添加点击事件
          add[i].onclick = (function () {            let sum = 2;            // 返回函数,完成私有变量的创建,形成闭包
            return function () {              this.value = "当前点赞数量(" + sum++ + ")";            };          })();        }      };    </script>
  </body>
</html>

参考视频讲解:进入学习

5. 使用闭包保护私有属性

创建一个计数器函数,在里面定义一个私有属性,这里通过闭包保护它不会被直接修改。

可以看见在这个例子中我们并没有直接操作 privatelyCounter,而是通过 makeCounter 主动暴露的方法来操作计数器中的 privateCounter。

// 创建一个计数器
const makeCounter = function(){
    // 创建私有变量
    var privatelyCounter = 0
    // 输出私有变量
    function console(){
        return privatelyCounter
    }
    // 更改计数器方法
    function change(num){
        privatelyCounter += num
    }
    // 暴露公有方法
    return {
        CounterAdd(num){
            change(num)
        },
        CounterSub(num){
            change(num)
        },
        CounterLog(){
            return console()
        }
    }
}
// 声明两计数器
const counter1 = makeCounter()
const counter2 = makeCounter()
counter1.CounterAdd(1)
counter1.CounterAdd(1)
counter2.CounterSub(-1)
counter2.CounterSub(-1)
// 输出:2
console.log(counter1.CounterLog())
// 输出:-2
console.log(counter2.CounterLog())

三、使用闭包实现函数柯里化

所谓函数柯里化就是将一个多参函数转为单参函数。

// 正常求自增方法
function numAdd(x, y){
    return x + y
}
console.log(numAdd(1, 2))

// 使用闭包实现柯里化
function numAddCurry(x){
    return function(y){
        return x + y
    }
}
// 先声明一个变量拿到自增方法
const curry = numAddCurry(1)
// 在调用这个变量进行自增,输出:3
console.log(curry(2))
// 亦或者直接调用自增方法传入两个参数,输出也是:3
console.log(numAddCurry(1)(2))

标签:闭包,知识点,console,变量,作用域,add,function
From: https://www.cnblogs.com/hellocoder2029/p/16876548.html

相关文章

  • 细说js变量、作用域和垃圾回收
    基本类型和引用类型在JavaScript中,数据类型可分为基本类型和引用类型,基本类型有六种:Null,Undefined,String,Boolean,Number,Symbol;而引用类型就是传说中的Object了。......
  • 大数据如果你只会离线计算,这个项目可以帮你完善一部分知识点
    在大数据开发从业人员中相信很多涉及的工作内容以离线计算居多,对数据是怎么采集的,如何采集,数据结构该设计没有清晰的了解在查阅相关数据产品后发现了某开源的SDK,数据模型设......
  • 一天梳理完react面试高频知识点
    描述事件在React中的处理方式。为了解决跨浏览器兼容性问题,React中的事件处理程序将传递SyntheticEvent的实例,它是跨浏览器事件的包装器。这些SyntheticEvent与你习惯......
  • Spring Security 知识点总结
    Security部分WebSecurityConfigurerAdaptersecurity配置的核心类在这里配置权限等信息authenticationauthentication是认证(登陆)authorizationauthorizati......
  • Spring Security 知识点总结
    Security部分WebSecurityConfigurerAdaptersecurity配置的核心类在这里配置权限等信息authenticationauthentication是认证(登陆)authorizationauthorizati......
  • 闭包
    一次看透什么是闭包认识闭包-函数的执行空间不会销毁-外部函数返回一个内部函数-内部函数中使用了外部函数的私有变量闭包函数-概念+函数内的函数-特点:......
  • js 闭包和promise
    闭包概述:闭包就是在函数内部返回一个函数,内部函数可以对外部函数的属性和方法进行引用,外部的属性和方法不会被js垃圾回收机制所回收这个结构就称为闭包函数的生命周......
  • javascript基础知识之闭包和递归
    一,什么是闭包,会出现什么问题?如何避免?1、函数里面包含的子函数,子函数访问父函数的局部变量2、通过return将子函数暴露在全局作用域,子函数就形成闭包3、通过闭包,父函数的局......
  • WPF | 零碎知识点记录1
    用一个电影院来举例子:Shell就是一个剧院,里面空空荡荡的Region就是演出厅,Bootstrapper就是剧场运营部门,安排演出单位的引入和演出安排及演出厅之间的资源协调;Module就是......
  • 关于AP的一些知识点
     FAT模式是指AP可以独立配置,有独立的管理接口,就像普通的无线AP一样;胖模式主要用于不使用交流电的小型网络。FIT模式是指AP由TP-LINKAC(无线控制器)统一控制和设置。 ......