淺談細說 JS 函數(call,apply,重載)

什麼是函數?數組

引用 W3School 的原話:

函數是一組能夠隨時隨地運行的語句。
函數是 ECMAScript 的核心。
函數是由這樣的方式進行聲明的:關鍵字 function、函數名、一組參數,以及置於括號中的待執行代碼。
函數的基本語法是這樣的:
function functionName(arg0, arg1, ... argN) {
  statements
}
  1. 聲明函數的幾種方式app

  2. 調用函數的幾種方式函數

  3. 重載函數的實現this

  4. 函數的獨立性spa

聲明函數code

//聲明函數的4種方法

//方法一 直接聲明
function speak(word){
    console.log(word)
}

//方法二 指定一個匿名函數 將其賦給一個變量,後面能夠直接經過該變量調用該函數
var speak2 = function (word) {
    console.log(word);
};//定義匿名函數須要注意最後須要加分號

//方法三 使用 Function對象 生成一個函數實例 
var speak3 = new Function("word","console.log(word);");

//方法四 使用 Function函數 返回函數實例
var speak4 = Function("word","console.log(word);");

調用函數基本方法對象

speak("hello world for global !");

this.speak("hello world for this !");

window.speak("hello world for window !");

調用函數的高級方法圖片

speak.call(null,"hello world with call !");//null 表明是用全局對象 window 調用

speak.apply(null,["hello world with apply !"]);

輸出結果:
圖片描述ip

這裏方法一你們不言而喻,簡單明瞭,直接就是聲明瞭一個函數,須要指出的是,默認寫的函數在不依附其餘對象的狀況下均爲全局函數,即成爲 window 對象的成員,能夠直接使用 window(Window 對象的實例,Window 對象實現了核心 JavaScript 所定義的全部全局屬性和方法)調用,或者經過 this 調用,在這裏JS 頂層代碼中 this 指向的就是 window內存

每當咱們使用方法一聲明瞭一個函數的時候,實際是生成了一個 Function 對象的實例.即每一個函數其實質都是一個 Function 對象實例.

注意:
JS 解析器每解析到一個函數的時候,都會在堆內存內劃分出一塊空間來存儲建立該 Function 實例

方法二:
首先 JS 解析器解析到一個函數的時候,在堆內存內劃分出一塊空間來存儲建立該 Function 實例,接着在當前棧內存
建立一個叫 speak2 的變量,這個變量有個值,這個值是一個地址,指向的是堆內存中的那個 Function 實例.實際上這就是大名鼎鼎的引用.

方法三:
與方法一和方法二不一樣的是,前兩個方法都是聲明好讓解析器去解析,讓解析器生成 Function 實例(就是上面聲明的函數,解析器調用 Function 構造器來生成實例,這些步驟是咱們看不到的),方法三是咱們手動調用 Function 構造器生成 Function 實例(步驟掌握在本身的手裏)

方法四:
與方法三不一樣的地方就是沒有 new,在這裏 new 與沒 new 的區別就是當有 new 的時候 Function 函數充當一個構造器,new 後返回的就是實例化後獲得的對象(此時Function 內部的 this指向的就是當前生成的對象),不使用 new 的話就是把 Function 函數看作一個普通函數直接調用,直接調用 Function 函數讓其在內部(咱們看不到)new 一個實例返回,本質是同樣的.

call方法與 apply 方法
查看EcmaScript.js
圖片描述

能夠看到 call 方法與 apply 方法的區別:

  • 他們的第一個參數指的是調用該方法對象

  • call 方法的第二個參數是可變數組參數,便可以傳入多個參數,非傳入一個數組.傳入的多個參數對應的是被調用方法的各參數.

  • apply 方法的第二個參數是一個數組對象,便可以直接傳入一個數組對象,數組對象的每項對應的是被調用的方法的各參數.

實現重載函數
在 JS 中,並不像其餘強類型語言同樣能夠聲明重載函數,若在原先聲明的函數後再聲明一個不一樣參數數量的函數(JS是弱語言, 聲明的函數不須要指明參數類型),解析器會用後面聲明的函數覆蓋前面聲明的函數.那咱們該如何實現呢.

arguments 對象
在每一個函數都有一個arguments 屬性,一樣查看 EcmaScript.js
圖片描述

當生成一個函數實例後,解析器會賦給arguments 屬性一個Arguments對象實例,這個實例是什麼,再看 EcmaScript.js
圖片描述

能夠得知其爲一個對象同時爲數組對象的子類,故能夠將其當初數組對象使用.
函數實例中的 arguments對象(能夠算是一個數組)的數組項內容即是咱們在調用函數時進行傳遞的參數.只要咱們有傳參,這個屬性就有數組項,不然數組長度爲0,故咱們能夠經過arguments.length 來查看其獲得的形參的數量.

有了上面的基礎即可實現重載函數
這裏引用 W3School 的例子

function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 5);
  } else if(arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

doAdd(10);        //輸出 "15"
doAdd(40, 20);    //輸出 "60"

函數的獨立性
咱們都知道,每當咱們聲明瞭一個函數,其實際爲一個 Function 實例,那它獨立在哪呢,如何體現呢
看一下代碼:

function Dog(name,age){
    this.name = name;
    this.age = age;
    this.showName = function () {
        console.log(this.name);
    }
}

function Cat(name,age){
    this.name = name;
    this.age = age;
    this.showName = function () {
        console.log(this.name);
    }
}

var dog = new Dog("wangwang",2);
var cat = new Cat("miaomiao",3);

dog.showName();
cat.showName();
dog.showName.call(cat);

輸出結果爲:
圖片描述

解釋:
每當咱們在函數內使用 this 的時候,無非這幾種狀況:
1.做爲構造器生成的實例對象
2.做爲調用當前方法的對象
3.在 JS 頂層代碼可使用 this 表明 window 調用全局函數等

故當咱們使用 call 方法調用某個對象的方法時,雖然從代碼語義上看,這個所屬方法是屬於該對象的(showName 屬於 Dog 或 Cat),可是因爲函數有用其特殊的獨立性即有以上幾個關於 this 的特色,致使最終的結果是不一樣的.
當咱們直接調用 dog 的 showName 方法時,showName 方法內的 this 指向的是該dog 對象(Dog 實例).

咱們知道調用 call 方法時須要傳入的第一個參數即爲調用當前函數亦或方法的對象,此時被調用的方法的 this 指向的實際爲傳入的第一個參數.即當咱們經過 call 調通 dog 的 showName 方法時,傳入的第一個參數是 cat 對象,表明 dog 的 showName 方法的 this 此時指向的不是 dog 是 cat.最後輸出的固然是 cat 的內容

最後指出:在對函數進行傳參時,若傳的是 JS 的基本類型,則爲值傳遞,不然爲引用傳遞.

相關文章
相關標籤/搜索