学习JavaScript中的闭包closure应该注意什么

目录
  • 闭包简述
  • 1.闭包使得内部函数可以访问外部函数的属性(变量或方法)
  • 2.闭包的广阔应用场景
  • 3.用闭包模拟私有方法
  • 4.从性能角度考虑,非必要不使用闭包

闭包简述

Mozilla 上这样解释闭包:一个函数和对其周围状态(lexical environment,词法环境) 的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中, 每当创建一个函数, 闭包就会在函数创建的同时被创建出来。 词法(lexical)一词指的是,词法作用域根据源代码中声明变量的位置来确定该变量在何处可用。

我对闭包的理解:闭包使得可以模拟私有项,可以使得内部函数可以访问外部函数的属性,非必要不用闭包。

1.闭包使得内部函数可以访问外部函数的属性(变量或方法)

这有时会带来便利, 例如有时可以通过在外部函数声明变量,代替全局变量。 下面是一个设备视口大小改变时,重置 echarts 的例子。

// 设备视口大小改变时,重置 echarts
let timer = null
window.onresize = function () {
  // 简单的防抖动处理
  if (timer) clearTimeout(timer)
  timer = setTimeout(() => {
    console.log(timer)
    chart.resize()
  }, 500)
}

也可以考虑使用闭包的方式,而不必在声明全局变量(更大范围的变量) timer,例如这样

window.onresize = this.debounce(() => {
  chart.resize()
}, 500)

function debounce (fn, delay = 500) {
  let timer = null
  return (p) => {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn(p)
    }, delay)
  }
}

2.闭包的广阔应用场景

闭包的广阔应用场景,体现在你使用只有一个方法的对象的地方,都可以使用闭包。

因为闭包允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。 在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

而在日常开发中,符合使用闭包的场景其实很常见,因为使用只有一个方法的对象的地方,都可以使用闭包, 而使用也并不太麻烦,加上闭包本身就是 javascript 的重要知识点,这些加起来使得闭包具备了实用的特征。

但如果你不熟练闭包,有更好的替代方案,也不必非要使用,因为实用好用的东西很多, 闭包只是选择之一,为了给自己多一种选择闭包又是要学的。

3.用闭包模拟私有方法

JavaScript 没有类似 JAVA 那样的将方法声明为私有的原生支持,但我们可以使用闭包来模拟私有方法。 私有方法不仅仅有利于限制对代码的访问,还提供了管理全局命名空间的强大能力, 避免非核心的方法弄乱代码的公共接口部分。

下面的示例展现了如何使用闭包来定义公共函数,并令其可以访问私有函数和变量。这个方式也称为模块模式(module pattern)

window.onload = () => {
  let Counter1 = makeCounter(); // 创建实例1
  let Counter2 = makeCounter(); // 创建实例2

  console.log(Counter1.value()); // value:0
  Counter1.add(); // 调用增加函数,执行加一
  console.log(Counter1.value()); // value:1

  console.log(Counter2.value()); // value:0

  // 注意,实例2的 value 没有受到实例1的影响,也就是说 Counter1 和 Counter2 各自独立。
  // 每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。
  // 然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。

  // undefined,Counter1 无法直接访问私有项 privateNumber
  console.log(Counter1.privateNumber);
  // Counter1.changeBy is not a function,Counter1 无法直接访问私有项 changeBy
  console.log(Counter1.changeBy(10));

  // 问私有项无法被访问,这提示我们应关注到以这种方式使用闭包,
  // 提供了许多与面向对象编程相关的好处 —— 特别是数据隐藏和封装。
}

/// 声明一个模块:计数器,模块内部包含了两个模拟的私有项 privateNumber 和 changeBy,
// 并返回一个对象,对象内部包含三个属性,分别是 add(),reduce(),value()。
let makeCounter = function () {
  let privateNumber = 0;

  function changeBy (val) {
    privateNumber += val;
  }

  return {
    add: function () {
      changeBy(1);
    },
    reduce: function () {
      changeBy(-1);
    },
    value: function () {
      return privateNumber;
    }
  }
};

在这个例子中,包含两个私有项: 名为 privateCounter 的变量和名为 changeBy 的函数。 这两项都无法在函数外部直接访问。必须通过匿名函数返回的三个公共函数访问。这就是模拟了私有特性。

4.从性能角度考虑,非必要不使用闭包

关于闭包的性能,我无深入的理解,也无数据证明,但我认为这挺重要的。

因此,这里引用一下 Mozilla 的说法:

如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的, 因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。

例如,在创建新的对象或者类时,方法通常应该关联于对象的原型,而不是定义到对象的构造器中。 原因是这将导致每次构造器被调用时,方法都会被重新赋值一次(也就是说,对于每个对象的创建,方法都会被重新赋值)。

英文原文:

It is unwise to unnecessarily create functions within other functions if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.

For instance, when creating a new object/class, methods should normally be associated to the object's prototype rather than defined into the object constructor. The reason is that whenever the constructor is called, the methods would get reassigned (that is, for every object creation).

概括就是一句话,非必要不用闭包。好东西很多闭包只是之一, 当然闭包作为js的重要知识点,作为可能的解决方案之一,学习是必要的。

到此这篇关于学习JavaScript中的闭包closure应该注意什么的文章就介绍到这了,更多相关JS 闭包closuret内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript闭包closure详述

    目录 一.什么是闭包 二. 闭包的作用 前言: 在JavaScript部分,闭包是很重要的东西,所以我们今天就闭包的相关知识做一总结.首先,在了解闭包前,我们先要知道作用域的相关知识,前面 作用域相关博文有解释,这里不在赘述.接下来我们来看一下什么是闭包? 一.什么是闭包 闭包(closure)指有权访问另一个函数作用域中变量的函数. ----- JavaScript 高级程序设计 简单理解闭包就是一个函数,他的特点是:一个作用域可以访问另外一个函数内部的局部变量. 举个简单的例子: 比如说我们

  • javascript中闭包(Closure)详解

    在javascript中,函数可看作是一种数据,可以赋值给变量,可以嵌套在另一个函数中. var fun = function(){ console.log("平底斜"); } function fun(){ var n=10; function son(){ n++; } son(); console.log(n); } fun(); //11 fun(); //11 我们把上面第二段代码稍微修改下: var n=10; function fun(){ function son(){

  • 学习Javascript闭包(Closure)知识

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数内部声明变量的时候,

  • javascript中闭包closure的深入讲解

    简介 闭包closure是javascript中一个非常强大的功能.所谓闭包就是函数中的函数,内部函数可以访问外部函数的作用域范围,从而可以使用闭包来做一些比较强大的工作. 今天将会给大家详细介绍一下闭包. 函数中的函数 我们提到了函数中的函数可以访问父函数作用域范围的变量,我们看一个例子: function parentFunction() { var address = 'flydean.com'; function alertAddress() { alert(address); } al

  • JavaScript 匿名函数(anonymous function)与闭包(closure)

    引入 匿名函数 闭包 变量作用域 函数外部访问函数内部的局部变量 用闭包实现私有成员 引入 闭包是用匿名函数来实现.闭包就是一个受到保护的变量空间,由内嵌函数生成."保护变量"的思想在几乎所有的编程语言中都能看到. 先看下 JavaScript 作用域: JavaScript 具有函数级的作用域.这意味着,不能在函数外部访问定义在函数内部的变量. JavaScript 的作用域又是词法性质的(lexically scoped).这意味着,函数运行在定义它的作用域中,而不是在调用它的作用

  • JavaScript知识点总结(十六)之Javascript闭包(Closure)代码详解

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.很早就接触过闭包这个概念了,但是一直糊里糊涂的,没有能够弄明白JavaScript的闭包到底是什么,有什么用,今天在网上看到了一篇讲JavaScript闭包的文章(原文链接),讲得非常好,这下算是彻底明白了JavaScript的闭包到底是个神马东东以及闭包的用途了,在此写出来和大家分享一下,希望不理解JavaScript闭包的朋友们看了之后能够理解闭包!以下内容大部分是来自原文,我在原文的基础

  • 理解javascript函数式编程中的闭包(closure)

    闭包(closure)是函数式编程中的概念,出现于 20 世纪 60 年代,最早实现闭包的语言是 Scheme,它是 LISP 的一种方言.之后闭包特性被其他语言广泛吸纳. 闭包的严格定义是"由函数(环境)及其封闭的自由变量组成的集合体."这个定义对于大家来说有些晦涩难懂,所以让我们先通过例子和不那么严格的解释来说明什么是闭包,然后再举例说明一些闭包的经典用途. 什么是闭包 通俗地讲, JavaScript 中每个的函数都是一个闭包,但通常意义上嵌套的函数更能够体 现出闭包的特性,请看

  • 学习JavaScript中的闭包closure应该注意什么

    目录 闭包简述 1.闭包使得内部函数可以访问外部函数的属性(变量或方法) 2.闭包的广阔应用场景 3.用闭包模拟私有方法 4.从性能角度考虑,非必要不使用闭包 闭包简述 Mozilla 上这样解释闭包:一个函数和对其周围状态(lexical environment,词法环境) 的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure). 也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域.在 JavaScript 中, 每当创建一个函数, 闭包就会在函数创建的同时

  • JavaScript中的闭包(Closure)详细介绍

    闭包是JavaScript中一个重要的特性,其最大的作用在于保存函数运行过程中的信息.在JavaScript中,闭包的诸多特性源自函数调用过程中的作用域链上. 函数调用对象与变量的作用域链 对于JavaScript中的每一次函数调用,JavaScript都会创建一个局部对象以储存在该函数中定义的局部变量:如果在该函数内部还有一个嵌套定义的函数(nested function),那么JavaScript会在已经定义的局部对象之上再定义一个嵌套局部对象.对于一个函数,其内部有多少层的嵌套函数定义,也

  • javascript中的闭包概念与用法实践分析

    本文实例讲述了javascript中的闭包概念与用法.分享给大家供大家参考,具体如下: 闭包的概念:闭包是指有权访问另一个函数作用域中的变量的函数 (引自<javascript高级程序设计第三版>178页).闭包的优点是不会产生全局变量,避免变量污染问题,但是闭包也有一个缺点就是闭包携带包含它的函数作用域会比其它函数占用更多的内存,过度使用会导致内存占用过多. wiki上关于闭包的概念: In programming languages, closures (also lexical clos

  • JavaScript中的闭包原理分析

    我们来看一个定义: Closure 所谓"闭包",指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 这说明了,JavaScript中的闭包是包含了上下文的函数,也就是说,这个函数的作用基础,是它所处的环境,这是不能超越的,跟线性代数是不是有一点似曾相识的感觉呢? 换个角度看,闭包的作用是为了实现OO.JavaScript中,没有像C++那样的public.private.protect属性标识, 建立起类比较困难."类

  • JavaScript中的闭包

    1.什么是闭包 闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内.而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数和声明的其他内部函数.当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包. 闭包的特点 1 函数嵌套函数 2 函数内部可以引用外部的参数和变量 3 参数和变量不会被垃

  • 深入学习JavaScript中的promise

    目录 为什么要用Promise? 使用Promise解决异步控制问题 Promise的结构 回调函数 为什么异步代码一定是回调函数结构? 刨析Promise 原型方法——catch\finally\then 为什么要在.then的回调函数中return一个Promise呢? 那如果我们不指明return返回值,它会返回什么呢?是如何实现链式调用呢? resolve和reject resolve() reject() Promise常用API——all().allSettled().any().r

  • 浅谈javascript中的闭包

    很长一段时间不理解闭包,后来了解了作用域,以及this相关问题才理解了闭包相关知识. 闭包(closure),也是面试题常客.简单点来说就是函数嵌套函数. 函数作为返回值: function foo () { var a = 1; return function () { a++; console.log(a); } } var aaa = foo(); aaa(); //2 aaa(); //3 其实这个代码不难理解,aaa是指向foo()返回的一个新函数,但是在这个函数里面引用了a变量,所以

  • 理解javascript中的闭包

    阅读目录 什么是闭包? 闭包的特性 闭包的作用: 闭包的代码示例 注意事项 总结 闭包在javascript来说是比较重要的概念,平时工作中也是用的比较多的一项技术.下来对其进行一个小小的总结 什么是闭包? 官方说法: 闭包是指有权访问另一个函数作用域中的变量的函数.创建闭包的常见方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量------<javascript高级程序设计第三版> 下面就是一个简单的闭包: function A(){ var text="

  • 深入学习JavaScript中的原型prototype

    javascript 是一种 prototype based programming 的语言, 而与我们通常的 class based programming 有很大 的区别,我列举重要的几点如下: 1.函数是first class object, 也就是说函数与对象具有相同的语言地位 2.没有类,只有对象 3.函数也是一种对象,所谓的函数对象 4.对象是按 引用 来传递的 那么这种 prototype based programming 的语言如何实现继承呢(OO的一大基本要素), 这也便是

  • 深入学习 JavaScript中的函数调用

    定义 可能很多人在学习 JavaScript 过程中碰到过函数参数传递方式的迷惑,本着深入的精神,我想再源码中寻找些答案不过在做这件事之前,首先明确几个概念.抛弃掉值传递.引用传递等固有叫法,回归英文: call by reference && call by value && call by sharing 分别是我们理解的 C++ 中的引用传递,值传递.第三种比较迷惑,官方解释是 receives the copy of the reference to object

随机推荐