4-函數進階:理解函數調用

1. 使用隱式函數參數

函數中的兩個隱含的參數:this、arguments
這兩個參數可以像函數體內顯示聲明的參數一樣被正常訪問。

  • this
    • 表示被調用函數的上下文對象。
  • arguments
    • 表示函數調用過程中傳遞的所有實參

arguments

  • arguments是函數的所有實參。
  • arguments有數組的特性,但不是真正數組,不可用數組方法,(類數組?NodeList屬于類數組)
    • length屬性,表示實參的具體個數。
    • arguments[0],可以用數組下標獲取實參的值
    • 轉換為數組
      • [...arguments]
      • Array.from(arguments)
  • 箭頭函數中沒有arguments,可以用...params代替
    var s=(...args)=>{ 
        console.log(args)
    } 
    s(1,2,3) // [1, 2, 3]
  • arguments作為函數參數的別名
    • 非嚴格模式
      • 可以作為行參params的別名,修改行參值
      function init(params){
          arguments[0] = 1;
      }
      init(3,4);  //arguments是一個非數組的結構 3,4
      //params原本為3,arguments[0]改為1,則最后params為1
      
    • 嚴格模式
      • arguments[index]會打印出對應的參數和行參,
      • 修改arguments[index]不會改變行參對應的params值。打印arguments[index]倒是會改變。
      • 只有params自己可以改變自己。
      • use strict開啟嚴格模式

函數上下文:this

代表函數調用相關聯的對象,稱之為函數上下文。

  • this的指向
    • 定義函數的方式
    • 定義函數的位置
    • 函數的調用方式!!!!!!!!!
      • 直接調用
      • 對象方法
      • 構造函數
      • apply和call方法

1. 作為函數直接調用

  • 如果一個函數沒有作為方法,構造函數、apply、call調用的話,我們稱之為函數直接調用。
  • 直接調用的this指向
    • 嚴格模式下,直接調用的this為unfined
    • 非嚴格模式下,this => window
  • 直接調用的表現形式
    //函數聲明
    function a(){}; 
    a();
    //函數定義
    var b=funcgtion(){}; 
    b();
    //函數表達式
    (function (){} ) ()
    //立即執行函數
    

2. 作為方法調用

  • 作為某個對象的方法|屬性被調用。
  • this指向:
    • 當對象是字面量創建,且方法函數為普通函數
      • 事件回調中
        • 方法調用時this應該是當前對象,但在事件回調中,回調函數的this為觸發當前事件的元素,所以該回調函數中的方法調用的普通函數被傳入隱式this,改變為當前元素。而非對象
          • 此時可以用apply/call/bind來改變回調函數中的this指向
      • 非回調情況下
        • 一般this指向該對象。
    • 當對象是字面量創建,且方法函數為箭頭函數時
      • 箭頭函數本身沒有this,依靠上下文環境
  • 方法調用的表現形式
    function afun(){
        return this;//window
    }; 
    afun();//window
    var obj = {
       b : afun
    }
    obj.b();//obj
    //obj的屬性引用了全局變量的函數體,但是是通過方法掉用的,所以this為該對象obj,所以可以在對象的屬性中引用函數。
    //所以 函數不看定義,看調用!
    

3. 作為構造函數調用

  • 目的是創建空對象,將其作為this對象傳遞給構造函數,初始化對象后作為構造函數的返回值。也稱構造函數實例化對象。
  • this指向(構造函數實例化對象):
    • 若構造函數顯示返回了一個原始值,實例化對象后,返回該對象。
    • 若構造函數顯示返回了一個對象,實例化對象后,返回return的對象,當前對象的this失效
function a(){
    return 'a'
}
const ao=new a()
ao //a {}

function v(){
    return {a:1}
}
new v() //{a: 1}

function v(){
    return {
            a:1,
            b:function(){
                    console.log(this)
            }}
}
const obj=new v() 
obj // {a: 1, b: ?}
obj.b() // {a: 1, b: ?}
  • 構造函數調用的表現形式
    function afun(){
        return 1;//window
    }; 
    afun();//1 構造函數作為普通函數調用,正常返回1,沒什么意義
    var obj = new afun(); //obj{} 構造函數實例化對象,返回該對象
    //注意:
    //構造函數顯式的返回原始值,對實例化對象沒有影響。
    //但顯式的返回對象,實例化對象后的變量,返回是return的對象。
    //構造函數只有在實例化對象后,才有意義,將構造函數直接調用沒意義。
    
    //構造函數實例化對象時發生了什么:
    //創建空對象
    //this指向為空對象
    //對象實例化并返回,除了上述的構造函數顯式的返回了一個對象的情況外。
    
    
  • 構造函數的命名約定
    • 通常以描述所構造的對象的名詞命名
    • 大寫字母開頭,例:Ninja;
    • 但這只是約定。

4. 使用apply/call調用

顯式的修改函數的上下文,將this賦給指定對象。我們可以使每個函數上用apply和call完成。
二者唯一區別是,參數列表的形式。

  • apply方法調用
    • 傳參2個:function.apply(指定this的對象,傳參數組)
  • call調用
    • 傳參n個:function.call(指定this的對象,params1,params2,params2)
p75例子,構造函數實例化對象后,對象方法在調用時,修改不了對象的屬性。
原因是對象方法是在[事件回調函數中被調用的,this被改變為觸發事件的元素]。(對象方法是普通函數定義)

注意:p80實現foreach迭代方法展示如何設置函數上下文例子

【構造函數實例化對象】后,對象方法若是箭頭函數定義。
箭頭函數沒有單獨的this,在定義時與上下文this一致。
故,構造函數中的箭頭函數在被實例化后,this被定義為實例化后的對象。
無論怎么調用箭頭函數的這個方法,都不會被傳入和改變this對象。

注意區分,【對象方法】而非【構造函數實例化對象】,中定義箭頭函數時,此時的this為window

5. 解決函數this上下文的問題

  • 使用箭頭函數
    • 箭頭函數沒有單獨的this,在定義時與上下文this一致。
    • 調用箭頭函數時,不會隱式傳入this
    • 箭頭函數的this
      • 對象中,window
      • 實例化的對象,是對象。且不會隱式傳入this
  • 使用bind
    • 創建并返回一個與原函數相同的新函數,并指定新函數的this上下文。
      • button.click.bind(button)將button.click方法copy一份,將this改為button對象。
        `

回到本章的問題,為一個或多個按鈕設置是否單擊的狀態。【單擊意味著事件回調,會隱式的傳入this】

  • 一個 =>【對象】
    • 對象的方法要用普通函數,而不是箭頭函數,箭頭函數的this不知道是否可以被改變,因為他不會隱式傳入this
    • 對象的方法用普通函數,會被事件回調更改this指向,可以用apply、call、bind改變this指向。
  • 多個 =>【構造函數】
    • 箭頭函數,因為實例化時被定義好了this,并且不會被隱式傳入this,可以規避被事件回調改變this的問題。
    • 普通函數,可以用apply、call、bind改變this指向。
      • apply、call改變原來函數的this,bind創建一個與原來一樣的函數,并指定this對象
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容