隨筆——js中的this指向,apply()與 call()

js中apply和Math.max()函數(原文

  1. apply()javascript

    Function.apply() 是JS的一個OOP特性,通常用來模擬繼承和擴展this的用途,對於上面這段代碼,能夠這樣去理解: XXX.apply() 是一個調用函數的方法,其參數爲:apply(Function, Args),Function爲要調用的方法,Args是參數列表,當Function爲null時,默認爲上文php

    Math.max.apply(null, arr)
    複製代碼

    可認爲是html

    apply(Math.max, arr)
    複製代碼

    而後,arr是一個參數列表,對於max方法,其參數是若干個數,即:java

    arr = [a, b, c, d, ...]
    複製代碼

    代入原式中:數組

    Math.max.apply(null, [a, b, c, d, ...])
    複製代碼

    等同於:bash

    Math.max(a, b, c, d, ...)
    複製代碼
  2. 區別:app

    Math.math() 方法能夠求出給定參數中最大的數,可是參數不能是數組。函數

    例如:ui

    > Math.max('1','2','3.1','3.2')
    < 3.2
    > Math.min(1,0,-1)
    < -1
    複製代碼

    此時可用 apply() 解決(第一個參數爲null,第二個參數爲數組; apply() 如何實現的參見上文 apply() 的轉換介紹):this

    > Math.max.apply(null, ['1','2','3.1','3.2'])
    < 3.2
    > Math.min.apply(null, [1,0,-1])
    < -1
    複製代碼

JavaScript中的this(原文

  1. this

    在 JavaScript 中,到處使用者 this ,可是,不少時候 this 指向並不固定,而是隨着它的執行環境的改變而改變。總結一句:this老是指向調用它所在方法的對象

  2. this 在函數裏

    這種方式也稱爲「全局性的函數調用」,例如:

    <script type='text/javascript'>
        var name='Hello_World';
        function test(){
            this.name='Hello_JavaScript';
        }
        
        test();
        
        console.log(this.name);     //Hello_JavaScript
        console.log(window.name);   //Hello_JavaScript
        console.log(name);          //Hello_JavaScript
    <script>
    複製代碼

    經過結果能夠更加證實了全局的name在函數內部被修改了,由於這個函數內部的this指的就是window。

    總結:對於全局性函數調用,函數內部的this就是指的全局對象window,便是:this是調用函數所在的對象。實際上這個test()函數是由全局對象window來去調用的,那麼函數內部的this固然就指的是window

  3. this 在構造函數裏

    <script type='text/javascript'>
        var name='Hello_World';
        function test(){
            this.name='Hello_JavaScript';
        }
        
        var person = new test();
        
        console.log(person.name);     //Hello_JavaScript
        console.log(window.name);   //Hello_World
    <script>
    複製代碼

    分析:咱們經過new關鍵字建立一個對象的實例,能夠發現new關鍵字改變了this的指向,將這個this指向了對象person。在構造函數內部,咱們對this.name=「HelloWorld」進行從新賦值,並無改變全局變量name的值。

    總結:聲明一個構造函數的實例對象時,構造函數內部的this都會指向新的實例對象,或者說,構造函數內部的this指向的是新建立的對象自己

  4. 在對象的方法中調用

    <script type='text/javascript'>
        var name='Hello_World';
        
        var person= {
          name:'Hello_JavaScript',
          info:function(){
            alert(this.name);       
          }
        }
        
        person.info();        //Hello_JavaScript
    <script>
    複製代碼

    總結:當person對象調用info()函數時,info函數內部的this指向的就是person對象。即,當this出如今對象的方法中時,那麼該方法內部的this指向的就是這個對象自己,也就是說this指向的調用函數的對象

JavaScript之call和apply(原文

  1. 使用call和apply的做用

    上文提到 this 的出現的三種方式,總結爲兩種:

    • 直接調用

      test(), 此種調用方式中,函數內部的this指向的window

    • 構造函數形式的調用

      var person = new test(); 此種方式調用中,函數內部的this指向的是person

    以上兩種方式,實際上能夠這麼說,函數內部的this都是表明當前對象,只不過是JavaScript中函數內部的this會隨着程序而指向不一樣的對象

    那麼個人問題是:咱們能不能手動修改this的指向呢?

    答案:能夠的,使用call或者apply。這個也就是call和apply的做用 → 改變函數內部this的指向

  2. 應用場景

    //代碼一
    <script type='text/javascript'>
        function Person(name,age){
          this.name=name;
          this.age=age;
        }
        
        function info(){
          alert(this.name +','+this.age);
        }
        
        var p1=new Person('jack','20');
    <script>
    複製代碼

    問題:我如今想借用這個info方法來去實現對p1對象的打印,怎麼作?

    方案一:直接調用info函數,即:info() ;經過上面的講解,仔細想一想,確定不行,由於這樣調用的話,info函數內部的this實際上是指向的window。

    方案二:經過對象調用,即 p1.info() ;其實也不行,由於p1對象壓根就沒有info這個方法,p1對象只有name和age屬性。

    解決方法以下:

    //代碼二
    <script type='text/javascript'>
       function Person(name,age){
         this.name=name;
         this.age=age;
       }
       
       function info(){
         alert(this.name +','+this.age);
       }
       
       var p1=new Person('jack','20');
       p1.show=info;
       p1.show();
       
    <script>
    複製代碼

    能夠發現咱們經過向p1對象添加了一個show屬性,而這個show屬性的值實際上是一個函數的地址,是一個函數對象,而後經過p1.show()就能夠實現打印了。此種方法確實能夠實現功能,可是這種方法是經過爲p1對象添加屬性完成的,若是仍然有相似的需求,是否是都要向p1對象添加屬性來完成需求呢,這樣就會致使p1對象的佔用空間愈來愈大,因此方式並不優雅

    針對上面的問題,本質上就是想經過修改info函數內部的this指針的問題來完成對當前對象的一個打印,那麼咱們能夠在不增長屬性的方式上來完成功能,這個就須要使用到了call和apply。

  3. call和apply的使用

    • 功能:改變this指向,使用指定的對象調用當前函數

    • 語法:

      call([thisObj[,arg1[, arg2[, [,.argN]]]]])
      複製代碼
      apply(thisObj[,argArray])
      複製代碼
    • 說明:

      1. 兩個方法的功能徹底同樣,惟一區別就是參數。

        對於第一個參數來講thisObj,做用是同樣的,用做表明當前對象的對象,說白了就表示的是函數執行時,this指向誰。

        對於 第二個參數apply要求傳入的是一個參數數組 ,也就是說將一系列參數組成一個數組傳入,而 對於call來講,參數以散列的值的方式傳入 。例如,func(thisObj,arg1,arg2,arg3...)對應的apply用法就是func(thisObj,[arg1,arg2,arg3...])。本文以call方法爲例

      2. 這兩個方法都是Function對象中的方法,由於咱們定義的每一個對象都擁有該方法。

      3. call 方法能夠用來代替另外一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變爲由 thisObj 指定的新對象,若是沒有提供 thisObj 參數,那麼 Global 對象被用做 thisObj。(?)

      4. 使用call和apply解決上面代碼的問題

      //代碼三
      <script type='text/javascript'>
          function Person(name,age){
            this.name=name;
            this.age=age;
          }
          
          function info(){
            alert(this.name +','+this.age);
          }
          
          var p1=new Person('jack','20');
          
          info.call(p1);      //或者 info.apply(p1)
          
      <script>
      複製代碼

      分析:

      當在函數中調用call方法時,函數內部的this會自動指向call方法中的第一個參數。上面的例子中,當執行info.call(p1)時,info函數內部的this則會自動指向p1對象,因此固然就能夠call這種方式來完成對p1對象的打印。

      1. call()重寫
      <script type='text/javascript'>
          function Person(){
              this.name = 'Hello_World';
              this.info=function(){
                  alert(this.name)
              }
          }
          
          function Cat(){
              this.name='貓';
          }
          var cat =new Cat();
          
          Person.call(cat);
          
          cat.info();    //Hello_World
          
      <script>
      複製代碼

      上面代碼最終會打印:‘Hello_World’,這個答案最關鍵是 Person.call(cat) 這一行代碼,仔細去想一想究竟發生了什麼事情,當調用call方法時,函數Person內部的this其實已經自動的指向了cat對象,至關於就是給cat對象執行了下面的兩行代碼:

      this.name='Hello_World',
      this.info=function(){
          alert(this.name)
      }
      複製代碼

      而後重寫了原來cat對象中的name屬性,把name由「貓」改爲了「 Hello_World 」,並且並得到了一個新的info方法(能夠這麼理解,至關於給cat對象添加了一個info屬性),因此cat對象固然能夠調用info方法了,因此結果就是「 Hello_World 」。apply的使用和call的功能相同,使用方式也很相似。

    關於call和apply的使用,恰好在 知乎 看到一個很生動形象的比喻,放在這裏但願有助於記憶。


    貓吃魚,狗吃肉,奧特曼打小怪獸。

    有天狗想吃魚了

    貓.吃魚.call(狗,魚)

    狗就吃到魚了

    貓成精了,想打怪獸

    奧特曼.打小怪獸.call(貓,小怪獸)

相關文章
相關標籤/搜索