this 基本概念

  1. 為什么要使用this
  2. this 的使用誤解 ( 2 種 指向誤解 )
  3. this 和詞法作用域的比較
  4. this 的指向正解
  5. this 的綁定方法( call()、apply()、bind() )

this 總是返回一個對象( fun 也是一個對象 ) + this 指向總是善變的

this 的三篇文章按照順序復習
this基本概念 -> this綁定規(guī)則 -> this 應用實例

基本概念

this 總是返回一個對象 即包含當前屬性或者方法函數(shù)的對象, 因為對象的屬性和方法函數(shù)可以賦予另一個對象,所有 this 指向的對象也是善變的。

  function foo () {
  console.log('name :' + this.name);
  }

  var obj = { name: "obj1", foo: foo };
  var obj2 = { name: "obj2", foo: foo };
  var obj3 = { name: "obj3" };

  obj.foo()   // obj1
  obj2.foo()    // obj2
  1. 為什么 使用this
  • this 提供了一種優(yōu)雅的方式來 傳遞 一個對象的引用, 使用 this 能夠得到更加 簡介的 api.

    顯式的傳遞對象的引用(eg: 函數(shù)參數(shù)傳遞) 使得代碼變得混亂和難以維護(eg: 傳遞參數(shù)的個數(shù)就是個問題)。

  • 使用 this 可以 自動引用合適的上下文環(huán)境,并且確定this當前指代的對象進而使用其屬性和方法函數(shù)

  • ** 我們使用 this 的最終目的是保證能夠正確 + 便捷的使用 對象的屬性和方法函數(shù)處理數(shù)據(jù) **

  1. this 的使用誤解 ( this 的指向誤解 )

    1. this 并不指向函數(shù)自身

    2. this 不一定指向定義它的函數(shù)作用域或者定義時的作用域

       function foo() {
           var a = 2;
           this.bar = function() {
             console.log(this.a)
           }
         this.bar();
       }
       foo();
      
  2. this 和詞法作用域的比較

    this 可以通過 參數(shù)傳遞 或者 直接的對象引用來代替。

    ** 但是 this 因為有其更加靈活的特性才被大家所使用,總是使用詞法作用域容易讓你 回到編程的舒適區(qū) **

我們來記錄 foo 函數(shù)被調(diào)用的次數(shù)

    function foo(num) {
        console.log('foo ' + num);

        // 記錄 foo 函數(shù)被調(diào)用的次數(shù)
        this.count++;
    }

    foo.count = 0;
    for(var i = 0; i < 5; i++) {
        foo(i);
    }

    // 記錄 foo 函數(shù)被調(diào)用的次數(shù)
    console.log(foo.count);

  分析一下上面的 輸出 的值 和 this 的指向?
  若需要你來改造 你應該怎么辦??
  1. this 的指向正解 ( 請看 this 的 四種綁定策略 )

    函數(shù)內(nèi)部的this 總是指向 函數(shù)本身被調(diào)用的位置。(this 綁定規(guī)則有詳解)

    所以對于 this 的 指向就是 尋找函數(shù)的調(diào)用位置為首。(瀏覽器自帶的 開發(fā)者工具可以很方便的查看函數(shù)調(diào)用棧)

  2. this 的 三種強制綁定的 方法詳解

** javascript 提供了 call apply 和 bind 三個方法,用于固定 this 的指向 **

** call 和 apply bind 都是定義在 Function 上面的方法。**
** call apply 返回一個調(diào)用函數(shù)的執(zhí)行結(jié)果。 **
** bind 返回一個修改了內(nèi)部this的 包裝函數(shù)。 **

  • call 的 傳參解析 ( 4 種傳參的方式 )

    call 參數(shù)使用正常的對象

    call 參數(shù)為空、null、undefined 則默認傳入全局對象

      var n = 'bar';
      var obj = {n: 'foo'}
    
       function baz() {
         console.log(this.n)
       }
    
       baz.call(obj);        // foo
       baz.call(window);
       baz.call();
       baz.call(null),
       baz.call(undefined);
    

    call 傳入一個基本類型的數(shù)據(jù),這個基本類型的數(shù)據(jù)會被轉(zhuǎn)為包裝對象 賦值給 this

         var f = function () {
             console.log(this);
         };
    
         f.call(5)     // Number {[[PrimitiveValue]]: 5}
    

    call 可以傳遞多個參數(shù),第一個參數(shù)為需要綁定的對象,后面的參數(shù) 依次是函數(shù)調(diào)用的傳參參數(shù)

  • apply ( 接受一個數(shù)組作為函數(shù)執(zhí)行時的參數(shù) )

  • bind 將函數(shù)體內(nèi)部的 this 強制綁定,返回一個新的經(jīng)過包裝的函數(shù)

      // 自己實現(xiàn)的簡單功能的 bind 函數(shù)
      function bind(fun, obj) {
            return function() {    // 這個 就是 bind 返回的函數(shù)
                  fn.apply(obj);
            }
      }
    

apply call bind 使用全攻略 ( 4種使用場景 )

  1. 傳遞空對象 ** 參數(shù)柯里化 **( 看你傳遞的對象到底有多空 )

    call apply bind 傳遞一個空對象常常用于參數(shù)的柯里化

     function bar(a, b) {
           console.log(a + ',' + b);
     }
    

    直接使用 null / undefined 作為空 傳入

     var baz = bar.call(null, 1, 4)      // 1, 4
    
     var bak = bar.bind(null, 10);
     bar(19)    // 10,19
    

    傳遞進去一個 真空對象 var ? = Object.create(null);

    var baz = bar.call(?, 1, 4)       // 1, 4
    
  2. 自定義的兩種 bind 方法

    1. 創(chuàng)建自定義的 bind 方法函數(shù)

       function bindCopy(fn, obj) {
             return function() {
                    fn.apply(obj, arguments);            // 這里主要依賴 call 方法 ** 注意不能少了函數(shù)參數(shù) **
              }
       }
      
    2. 擴展函數(shù)方法庫(** 重要知識點 **)

      Function.prototype.bindCopy() {
             var fn = this;
             var obj = arguments[0];
             var args = Array.prototype.slice(arguments, 1);
             return function() {
                      fn.apply(obj, args)
             }
       }
      

      重要知識點:

      • 函數(shù)使用 prototype 可以進行擴展( Function.ptototype.bindCopy )

      • 使用 apply 可以將 類數(shù)組對象( 有 length 屬性的對象 ) 進行參數(shù)結(jié)構(gòu)

      • 函數(shù)自身調(diào)用時也是使用 this 表示調(diào)用的上下文

      • 注意 原函數(shù)本身的 參數(shù)不能少

  3. apply 和 call 的妙用

    1. 將數(shù)組解構(gòu) (上面是將類數(shù)組對象解構(gòu))

      var arr = [1, 4, 6, 7];
      Math.max.apply(null, arr);        // 7
      
    2. 使用 call 方法用在 對象繼承中 重新調(diào)用被子類覆蓋的父類方法;

       function Parent() {
           this.a = 'super';
           this.Super = function() {
                  console.log('父類的 Super 方法' + this. a);      
           }
       }
      
       var p = new Parent();
      
      function Children (a) {
            this.a = a;
            Parent.call(this);     // 調(diào)用 父類的構(gòu)造函數(shù)
       }
      
      var c = new Children(12);
      c.Super()          // 使用子類 繼承過來的方法
      
      c.Super.call(p)        // 使用 call 重新調(diào)用父對象的方法
      

    試著自己實現(xiàn)一個類似 于 forEach 的 方法吧

.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 7,002評論 15 54
  • 特別說明,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 816評論 0 1
  • 1.函數(shù)參數(shù)的默認值 (1).基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認值,只能采用變通的方法。
    趙然228閱讀 830評論 0 0
  • 1. this之謎 在JavaScript中,this是當前執(zhí)行函數(shù)的上下文。因為JavaScript有4種不同的...
    百里少龍閱讀 1,093評論 0 3

友情鏈接更多精彩內(nèi)容