ホームページ > ウェブフロントエンド > jsチュートリアル > 一緒にクロージャについて知りましょう

一緒にクロージャについて知りましょう

coldplay.xixi
リリース: 2020-09-08 14:00:27
転載
2645 人が閲覧しました

一緒にクロージャについて知りましょう

#関連する学習に関する推奨事項:

JavaScript ビデオ チュートリアル

まえがき

# 終わりに は、フロントエンド開発者にとって常に回避できないハードルであり、好むと好まざるにかかわらず、仕事や面接で遭遇することがあります。クロージャについての理解は人それぞれ異なりますので、ここでは私自身のクロージャについての理解をお話します。 (理解に矛盾がある場合は、ご自身でご参照ください)

クロージャの定義方法

定義を与える前に、他の人がどのようにクロージャを定義しているかを見てみるとよいでしょう:

関数オブジェクトはスコープ チェーンを通じて相互に関連付けることができ、関数本体内の変数は関数スコープに保存できます。この機能は、コンピュータ サイエンスの文献では「クロージャ」と呼ばれています - JavaScript オーソリティ ガイド (第 6 版)

#クロージャは、別の関数のスコープ内の変数にアクセスできる関数です。クロージャを作成する一般的な方法は、別の関数の中に関数を作成することです。 --Advanced Programming in JavaScript (Third Edition)

関数が現在の字句スコープ内にある場合でも、関数がその字句スコープを記憶してアクセスできる場合、クロージャが発生します。ドメインの外。 -- あなたの知らない JavaScript (第 1 巻)

上記の段落の説明は同じではありませんが、注意深く味わってみると、いくつかの共通点を見つけることができます。これらの中で最も重要なのは、異なるスコープ間の

接続 です。もちろん、上記の定義を直接引用することもできます (結局のところ、上記の定義は比較的信頼できるものです)。ここでは、著者は最後の段落の定義を好み、書籍「あなたが知らない JavaScript (第 1 巻)」を強く推奨します。 、注意深く繰り返し読む価値があります。

クロージャにどのようなナレッジ ポイントが関係しているか

定義を与えるだけでは十分ではなく、どのようなナレッジ ポイントが内部的に関係しているのかも調査する必要があります。筆者が役立つと思った知識を以下に挙げます。

スコープとスコープ チェーン

実は、著者は皆さんがこれについて考えたことがあることを知っています (いいえ、これを考えたことがない人は誰もいません)。これで誰もが

scope を知ることができました。ここではそれを簡単に説明し、そのプロセスを見ていきます。

スコープ: 変数を名前で検索するための一連のルール。グローバルスコープ、関数スコープ、ブロックスコープの3種類に分かれます。

注目すべきはES6の新しい仕様であるブロックスコープです。中括弧

{} 内の let および const を使用して定義された変数はスコープにバインドされ、中括弧の外側からはアクセスできません。 注: 中括弧の先頭と let 変数宣言の前の間に 一時的なデッド ゾーンがあります (この点はこの記事の範囲外です) 。 スコープ チェーン: 異なるスコープが一緒にトラップされると、スコープ チェーンが形成されます。検索方向は内側から外側であることに注意してください。

スコープの検索方向が内側から外側になるのはなぜですか?これは興味深い質問です。個人的には、js の実行関数がスタックにプッシュされる方法によって決まると思います (少し話が逸れたように感じます。興味のある友人は情報を確認してください)。

字句スコープ

関数が別の関数スコープ内の変数にアクセスできる (または現在のスコープを覚えていて、現在のスコープの外にアクセスできる) 理由の重要なポイント

字句スコープ### 仕事で。これは非常に重要ですが、誰もがこの知識ポイントを知っているわけではないので、ここで簡単に説明しましょう。

プログラミングの世界には、スコープの 2 つの作業モードがあります。1 つは、ほとんどのプログラミング言語で使用される 字句スコープ で、もう 1 つはその逆です。ダイナミック スコープ

(これはこの記事の範囲外です)。

字句スコープ: 変数とブロックのスコープはコードを書くときに決定され、オブジェクトや呼び出される場所によって変更されません (これは反対)。

それ以外の場合は、例を挙げてみましょう:
let a = 1;
function fn(){
    let a = 2;
    function fn2(){
        console.log(a);
    }
 return fn2;
}

let fn3 = fn();
fn3();
ログイン後にコピー
上記の定義から、

fn

はクロージャ関数
fn3 ## であることがわかります。

#fn2

のポインタ アドレスを取得しました。

fn3 が実行されると、実際には fn2 が実行され、内部の a 変数は、スコープ チェーンの検索ルールでは、検出されるのは fn スコープ内の変数 a であるため、最終出力は 1 ではなく 2 になります。 (下の図をご覧ください) 話は逸れますが、字句スコープを欺くにはどうすればよいでしょうか?

字句スコープは静的ですが、それを騙して動的な効果を実現する方法はまだあります。 一緒にクロージャについて知りましょう

第一种方法是使用eval. eval可以把字符串解析成一个脚本来运行,由于在词法分析阶段,无法预测eval运行的脚本,所以不会对其进行优化分析。

第二种方法是with. with通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with本身比较难掌握,使用不当容易出现意外情况(如下例子),不推荐使用 -.-

function Fn(obj){
    with(obj){
        a = 2;
    }
}

var o1 = {
    a:1
}
var o2 = {
    b:1
}

Fn(o1);
console.log(o1.a); //2
Fn(o2);
console.log(o2.a); //undefined;
console.log(a); //2 a被泄漏到全局里面去了
// 这是with的一个副作用, 如果当前词法作用域没有该属性,会在全局创建一个
ログイン後にコピー

闭包能干啥?

闭包的使用场景可多了,平时使用的插件或者框架,基本上都有闭包的身影,可能您没留意过罢了。下面笔者列举一些比较常见的场景。

  1. 模拟私有变量和方法,进一步来说可以是模拟模块化;目前常用的AMD,CommonJS等模块规范,都是利用闭包的思想;

  2. 柯里化函数或者偏函数;利用闭包可以把参数分成多次传参。如下面代码:

// 柯里化函数
function currying(fn){
    var allArgs = [];

    function bindCurry(){
        var args = [].slice.call(arguments);
        allArgs = allArgs.concat(args);
        return bindCurry;
    }
    bindCurry.toString = function(){
        return fn.apply(null, allArgs);
    };

    return bindCurry;
}
ログイン後にコピー
  1. 实现防抖或者节流函数;

  2. 实现缓存结果(记忆化)的辅助函数:

// 该方法适合缓存结果不易改变的函数
const memorize = fn => {
    let memorized = false;
    let result = undefined;
    return (...args) => {
        if (memorized) {
            return result;
        } else {
            result = fn.apply(null,args); 
            memorized = true;
            fn = undefined;
            return result;
        }
    };
};
ログイン後にコピー

如何区分闭包?

说了那么多,我怎么知道自己写的代码是不是闭包呢?先不说新手,有些代码的确隐藏的深,老鸟不仔细看也可能发现不了。 那有没有方法可以帮助我们区分一个函数是不是闭包呢?答案是肯定的,要学会善于利用周边的工具资源,比如浏览器。

打开常用的浏览器(chrome或者其他),在要验证的代码中打上debugger断点,然后看控制台,在scope里面的Closure(闭包)里面是否有该函数(如下图)。

一緒にクロージャについて知りましょう

闭包真的会导致内存泄漏?

答案是有可能。内存泄漏的原因在于垃圾回收(GC)无法释放变量的内存,导致运行一段时候后,可用内存越来越少,最终出现内存泄漏的情况。常见的内存泄漏场景有4种:全局变量;闭包引用;DOM事件绑定;不合理使用缓存。其中,闭包导致内存泄漏都是比较隐蔽的,用肉眼查看代码判断是比较难,我们可用借助chrome浏览器的Memory标签栏工具来调试。由于篇幅问题,不展开说明了,有兴趣自己去了解一下如何使用。

想了解更多编程学习,敬请关注php培训栏目!

以上が一緒にクロージャについて知りましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.im
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート