『javascript高級プログラム設計』学習ノート|10.14-10.16.クローズドパッケージ

14557 ワード

先端小讴に注目して、オリジナルの技術記事をもっと読みます.
関連コード→

10.14閉パッケージ

  • 閉パケットとは、通常、ネストされた関数で実装される別の関数の役割ドメイン内の変数を参照する関数です(関数が外部変数にアクセスしている場合、それは閉パケットです).
  • 閉パケットにおける関数の役割ドメインチェーンには、外部関数変数への参照
  • がある.
  • グローバルな役割ドメインで閉包関数にアクセスするために、通常、外部関数内で内部閉包関数
  • が戻る.
    したがって、
  • 外部関数が閉パケットで参照するアクティブなオブジェクトは、外部関数の実行後に破棄されることはなく、メモリに残る
  • である.
  • メモリを解放するには、外部関数のアクティブオブジェクトへの閉パッケージ関数の参照
  • を解除する必要がある.
    function arraySort(key, sort) {
      return function (a, b) {
        //       ,        key sort,    
        let va = a[key]
        let vb = b[key]
        if (sort === 'asc' || sort === undefined || sort === '') {
          //   :va > vb
          if (va > vb) return 1
          else if (va < vb) return -1
          else return 0
        } else if (sort === 'desc') {
          //   :va < vb
          if (va < vb) return 1
          else if (va > vb) return -1
          else return 0
        }
      }
    }
    let compareNames = arraySort('name') //            ,           arraySort     key sort   ,       
    let result = compareNames({ name: 'Nicholas' }, { name: 'Matt' }) //       
    compareNames = null //        arraySort       ,    

    10.14.1 thisオブジェクト

  • 閉パッケージ内でthisを使用すると、コードがより複雑になります.内部関数が矢印関数を使用していない場合、thisは実行関数のコンテキストにバインドされます.
  • グローバル関数で呼び出され、非厳格モードではthiswindowを指し、厳格モードはundefined
  • に等しい.
  • は、あるオブジェクトのメソッドとして呼び出す、thisは、そのオブジェクト
  • を指す.
  • 匿名関数は、匿名関数を呼び出すオブジェクト
  • を指すオブジェクトにバインドされない.
    global.identity = 'The Window' // vscode node    ,        window,    window  global
    let object = {
      identity: 'My Object',
      getIdentityFunc() {
        return function () {
          return this.identity
        }
      },
    }
    console.log(object.getIdentityFunc()) // ƒ () { return this.identity },      
    console.log(object.getIdentityFunc()()) // 'The Window',          this.identity,this      
  • 関数が呼び出されると、変数thisthisが自動的に作成され、内部関数は外部関数の2つの変数に直接アクセスできません.アクセスするには、閉パケットでアクセス可能な別の変数に参照を保存する必要があります.
    let object2 = {
      identity: 'My Object',
      getIdentityFunc() {
        let that = this //        this   that 
        return function () {
          return that.identity //   (    )   that,that  getIdentityFunc()    this(      this)
        }
      },
    }
    console.log(object2.getIdentityFunc()()) // 'My Object',          that.identity,that        getIdentityFunc this
  • 特定の場合のarguments
  • let object3 = {
      identity: 'My Object',
      getIdentity() {
        return this.identity
      },
    }
    console.log(object3.getIdentity()) // 'My Object'
    console.log(object3.getIdentity) // [Function: getIdentity],  getIdentity()
    console.log((object3.getIdentity = object3.getIdentity)) // [Function: getIdentity],  getIdentity()   object3.getIdentity
    console.log((object3.getIdentity = object3.getIdentity)()) // 'The Window',              ,this      
    console.log((object3.funcA = object3.getIdentity)()) // 'The Window',  getIdentity()         ,    
    object3.funcB = object3.getIdentity
    console.log(object3.funcB()) // 'My Object',    object3  ,this  object3

    10.14.2メモリリーク

  • 異なるゴミ回収メカニズムを使用するため、IE 9の前にパケットを閉じるIEブラウザでは、HTML要素がパケットを閉じる役割ドメインに保存されると、
  • が破棄されないという問題が発生する.
    function assignHandler() {
      let element = document.getElementById('someElement')
      element.onclick = () => {
        console.log(element.id) //            element,          element     
      }
    }
    
    function assignHandler2() {
      let element = document.getElementById('someElement')
      let id = element.id //   element.id   id
      element.onclick = () => {
        console.log(id) //      element,           element.id   id
      }
      element = null //    element     ,      
    }

    10.15今すぐ呼び出される関数式

  • が直ちに呼び出す匿名関数は、関数宣言と同様に括弧に含まれる
  • の即時呼び出し関数式(IIFE)とも呼ばれる.
    ;(function () {
      //      
    })()
  • ES 5はブロックレベルの役割ドメインをサポートしていないが、IIFEシミュレーション
  • を使用することができる.
    ;(function () {
      for (var i = 0; i < 3; i++) {
        console.log(i) // 0、1、2
      }
    })()
    console.log(i) // ReferenceError: i is not defined,i       (       ) 
  • ES 6はブロックレベルの役割ドメインをサポートし、IIFEを必要とせずに同様の機能
  • を実現することができる.
    {
      let i = 0
      for (i = 0; i < 3; i++) {
        console.log(i) // 0、1、2
      }
    }
    console.log(i) // ReferenceError: i is not defined
    
    for (let i = 0; i < 3; i++) {
      console.log(i) // 0、1、2
    }
    console.log(i) // ReferenceError: i is not defined
  • クリックハンドラを実行する場合、反復変数の値はループ終了時の最終値であり、表示する値
  • をクリックするたびにIIFEまたはブロックレベルの役割ドメインでロックすることができる.
    let divs = document.querySelectorAll('div')
    for (var i = 0; i < divs.length; ++i) {
      divs[i].addEventListener(
        'click',
    
        //      :    (                      )
        // function(){
        //   console.log(i);
        // }
    
        //      :          ,         
        (function (_i) {
          return function () {
            console.log(_i)
          }
        })(i) //            
      )
    }
    
    for (let i = 0; i < divs.length; ++i) {
      //  let   ,                 
      divs[i].addEventListener('click', function () {
        console.log(i)
      })
    }
  • と同様に、タイムアウト論理を実行する場合、反復変数の値はループ終了をもたらす値であり、IIFEまたはブロックレベルの役割ドメインを使用して反復する値
  • をロックすることもできる.
    for (var i = 0; i < 5; i++) {
      //             ,                5
      setTimeout(() => {
        console.log(i) // 5、5、5、5、5
      }, 0)
    }
    
    for (var i = 0; i < 5; i++) {
      //            ,           ,                
      ;(function (_i) {
        setTimeout(() => {
          console.log(_i) // 0、1、2、3、4
        }, 0)
      })(i)
    }
    
    for (let i = 0; i < 5; i++) {
      //   let  :               
      setTimeout(() => {
        console.log(i) // 0、1、2、3、4
      }, 0)
    }

    10.16プライベート変数

  • 関数またはブロックに定義変数は、プライベート(関数またはブロックの外部がアクセスできない変数)
  • とみなすことができる.
  • プライベート変数は、関数パラメータ、ローカル変数、および関数内部で定義された他の関数
  • を含む.
    function add(num1, num2) {
      // 3     :  num1、  num2、    sum
      let sum = num1 + num2
      return sum
    }
  • 特権メソッドは、関数のプライベート変数(およびプライベート関数)にアクセスできる共通のメソッドであり、構造関数において
  • を実現することができる.
    function MyObject() {
      let privateVariable = 10
      function privateFunction() {
        console.log('privateFunction')
        return false
      }
      //     (  ):      privateVariable     privateFunction()
      this.publicMethod = function () {
        console.log('privateVariable', privateVariable++)
        return privateFunction()
      }
    }
    let obj = new MyObject()
    obj.publicMethod()
    /* 
      privateVariable 10
      privateFunction
    */
  • 同構造関数の欠点は、構造関数でプライベート変数を実現する問題は、各インスタンスがメソッド(プライベートメソッド&特権メソッド)を再作成し、メカニズムが同じFunctionオブジェクトが
  • を複数回インスタンス化することである.
    function Person(name) {
      /*     name        ,    getName() setName()       */
      this.getName = function () {
        return name
      }
      this.setName = function (_name) {
        name = _name
      }
    }
    let person = new Person('Nicholas') //               (    &    )
    console.log(person.getName()) // 'Nicholas'
    person.setName('Greg')
    console.log(person.getName()) // 'Greg'

    10.16.1静的プライベート変数

  • 匿名関数式を使用してプライベート役割ドメインを作成し、特権メソッドを実装します.
  • プライベート変数とプライベートメソッドの定義
  • プライベート変数は静的プライベート変数として共有するが、各インスタンスには存在しない
  • .
  • コンストラクタの定義
  • 関数式定義コンストラクション関数(関数宣言によって内部関数が作成される)
  • キーワード定義コンストラクタを使用することなく、グローバル役割ドメインに
  • を作成する.
  • 共有メソッドの定義(特権メソッド)
  • は、構造関数のプロトタイプ上で
  • を定義する.

    ;(function () {
      /*        ,        */
    
      //          ,   
      let privateVariable = 10
      function privateFunction() {
        return false
      }
    
      //     :        &       (        )
      MyObject = function () {}
    
      //     /    (  ):           
      MyObject.prototype.publicMethod = function () {
        console.log('privateVariable', privateVariable++)
        return privateFunction()
      }
    })()
  • この方式では、プライベート変数とプライベートメソッドはインスタンスによって共有され、特権メソッドはプロトタイプに定義され、インスタンスによっても
  • が共有される.
  • インスタンスを作成してもメソッドは再作成されませんが、特権メソッドを呼び出して静的プライベート変数を変更すると、すべてのインスタンス
  • に影響します.
    ;(function () {
      //     name,   
      let name = ''
    
      //     ,         
      Person = function (_name) {
        name = _name
      }
    
      //     ,          
      Person.prototype.getName = function () {
        return name
      }
      Person.prototype.setName = function (_name) {
        name = _name
      }
    })()
    
    let person1 = new Person('Nicholas')
    console.log(person1.getName()) // 'Nicholas'
    person1.setName('Matt')
    console.log(person1.getName()) // 'Matt'
    
    let person2 = new Person('Michael')
    console.log(person2.getName()) // 'Michael',               
    console.log(person1.getName()) // 'Michael',      

    10.16.2モジュールモード

  • は、単一のオブジェクトに基づいて拡張され、役割ドメインチェーンによってプライベート変数と特権メソッドを関連付けます.
  • は、一例のオブジェクトのオブジェクト字面量を、即時呼び出しの関数式
  • に拡張する.
  • 匿名関数の内部で、プライベート変数とプライベートメソッド
  • を定義する
  • 匿名関数の内部では、公開アクセス属性とメソッドのみを含むオブジェクトの字面量
  • が返される.
    let singleton = (function () {
      /*           ,        */
    
      //          ,   
      let privateVariable = 10
      function privateFunction() {
        return false
      }
    
      //                       
      return {
        publicProperty: true,
        publicMethod() {
          console.log(++privateVariable)
          return privateFunction
        },
      }
    })()
    console.log(singleton) // { publicProperty: true, publicMethod: [Function: publicMethod] }
    singleton.publicMethod() // 11
  • 本質的には、このモードは、単一のオブジェクトの共通インタフェース
  • をオブジェクトの字面量で定義する.
    function BaseComponent() {} // BaseComponent  
    
    let application = (function () {
      let components = new Array() //       components
      components.push(new BaseComponent()) //    , BaseComponent            
    
      /*      */
      return {
        // getComponentCount()    :        
        getComponentCount() {
          return components.length
        },
        // registerComponent()    :    
        registerComponent(component) {
          if (typeof component === 'object') {
            components.push(component)
          }
        },
        // getRegistedComponents()    :        
        getRegistedComponents() {
          return components
        },
      }
    })()
    
    console.log(application.getComponentCount()) // 1
    console.log(application.getRegistedComponents()) // [ BaseComponent {} ],     BaseComponent
    
    function APPComponent() {} // APPComponent  
    application.registerComponent(new APPComponent()) //     APPComponent
    console.log(application.getComponentCount()) // 2
    console.log(application.getRegistedComponents()) // [ BaseComponent {}, APPComponent {} ],     BaseComponent APPComponent

    10.16.3モジュール強化モード

  • は、モジュールモードを使用して、オブジェクトを返す前に強化され、特定のタイプのインスタンスとして単一のオブジェクトに適していますが、追加のプロパティまたはメソッドを追加するシーンを追加する必要があります.
  • 匿名関数の内部で、プライベート変数とプライベートメソッド
  • を定義する
  • 匿名関数の内部で、ある(特定の)タイプのインスタンス
  • を作成する.
  • インスタンスオブジェクトに共有属性とメソッド(拡張)
  • を追加
  • はインスタンスオブジェクト
  • を返す.
    function CustomType() {} //     
    let singleton2 = (function () {
      //          ,   
      let privateVariable = 10
      function privateFunction() {
        return false
      }
    
      //          
      let object = new CustomType()
    
      //          
      object.publicProperty = true
      object.publicMethod = function () {
        console.log(++privateVariable)
        return privateFunction
      }
    
      //     
      return object
    })()
    console.log(singleton2) // CustomType { publicProperty: true, publicMethod: [Function: publicMethod] }
    singleton2.publicMethod() // 11
  • は、モジュールモードの単一のオブジェクト共通インタフェースを例にとる、thisapplicationコンポーネントのインスタンスである必要がある場合、モジュール拡張モードを使用して作成することができる:
  • .
    let application2 = (function () {
      let components = new Array() //       components
      components.push(new BaseComponent()) //    , BaseComponent            
      let app = new BaseComponent() //           
    
      /*      */
      // getComponentCount()    :        
      app.getComponentCount = function () {
        return components.length
      }
      // registerComponent()    :    
      app.registerComponent = function (component) {
        if (typeof component === 'object') {
          components.push(component)
        }
      }
      // getRegistedComponents()    :        
      app.getRegistedComponents = function () {
        return components
      }
    
      return app //     
    })()
    
    console.log(application2) // BaseComponent { getComponentCount: [Function (anonymous)], registerComponent: [Function (anonymous)], getRegistedComponents: [Function (anonymous)] }
    console.log(application2.getComponentCount()) // 1
    console.log(application2.getRegistedComponents()) // [ BaseComponent {} ],     BaseComponent
    
    application2.registerComponent(new APPComponent()) //     APPComponent
    console.log(application2.getComponentCount()) // 2
    console.log(application2.getRegistedComponents()) // [ BaseComponent {}, APPComponent {} ],     BaseComponent APPComponent

    プライベート変数&プライベートメソッド
    特権メソッド
    欠点
    コンストラクタ
    インスタンスで独立
    インスタンス
    各インスタンスのメソッドの再作成(プライベートメソッド&特権メソッド)
    プライベートドメイン
    プライベート役割ドメインで、静的、共有
    コンストラクタのプロトタイプ
    特権メソッドを呼び出してプライベート変数を変更し、他のインスタンスに影響を与える
    モジュールモード
    プライベート役割ドメインで独立
    単一オブジェクト上
    モジュール拡張モード
    プライベート役割ドメインで独立
    インスタンスオブジェクト上

    まとめ&質問

  • 閉鎖とは何ですか?その役割は何ですか.
  • 矢印関数を使用しない場合、thisはグローバルメソッドとローカルメソッドで呼び出されたとき、それぞれどこを指しますか?匿名関数のthisなら?
  • 関数がネストされている場合、内部関数は外部関数のthisとargumentsにどのようにアクセスしますか?
  • 今すぐ呼び出される関数式とは?ブロックレベルの役割ドメイン
  • をコードでシミュレートしてください.
  • コード実装機能:すべてのdiv要素を取得し、異なるdivをクリックして対応するインデックス値を表示してください.IIFEとブロックレベルの役割ドメインでそれぞれ
  • を実現することが要求される.
  • コード実装機能:1秒後に0~4のデジタル反復を実現してください.IIFEとブロックレベルの役割ドメインでそれぞれ
  • を実現することが要求される.
  • プライベート変数とは?どのような内容が含まれますか?
  • 特権方法とは何ですか?コードを書いて、構造関数の中で特権の方法を実現して、そしてこの方法に何の問題があるかを話してください.
  • コードを書いて、プライベート変数を通じて特権方法を実現して、この方法に何の限界があるかを話して証明してください.
  • コードを書いてください.モジュールモードによって一例のオブジェクトの共通インタフェースを定義し、Webコンポーネント登録
  • を実現します.
  • モジュール拡張モードはどんなシーンに適していますか?コードでそのモードのWebコンポーネント登録
  • を実現してください.