理解js中的函數調用和this


概述

這是我看typescript的時候看引用資源看到的,原文在這里:Understanding JavaScript Function Invocation and "this",我簡單地總結一下記下來供以后開發時參考,相信對其他人也有用。

機制

js中的函數調用機制是這樣的:

  1. 建立一個表argList,從索引1開始塞入函數的參數。
  2. 表的索引0的值是thisValue。
  3. 把this賦給thisValue,然后調用func.call(argList)。

說這么多,其實就是想說明,函數調用f(x,y)其實就是f.call(this, x, y)的語法糖。內部是通過f.call(this, x, y)來調用的。

可以看到,雖然f(x,y)里面沒有this,但是f.call(this, x, y)里面有this,所以非常好理解為什么函數調用中會有this了。

那么this是從哪里來的呢?當f(x,y)沒有調用者的時候,this自動被賦值為window;當f(x,y)有調用者的時候,this被賦值為指向調用者。

例子

舉幾個實例感受一下:

//例子1
function hello(thing) {
  console.log(this + " says hello " + thing);
}
hello.call("Yehuda", "world"); //輸出Yehuda says hello world

//例子2
function hello(thing) {
  console.log(this + " says hello " + thing);
}
//相當於hello.call(window, "world");
hello("world"); // 輸出[object Window] says hello world

//例子3
function hello(thing) {
  console.log(this + " says hello " + thing);
}
let person = { name: "Brendan Eich" };
person.hello = hello;
//相當於hello.call(person, "world");
person.hello("world"); //輸出[object Object] says hello world

注意:我們這里不是strict mode。

更優雅的寫法

有時候,我們希望函數沒有調用者,但是this卻不指向window對象。有以下2種優雅的解決方案:

箭頭函數

es6里面定義了箭頭函數,不只是為了簡化函數的寫法,而且還有這么一條有用的規定:箭頭函數的this不會隨調用者的不同而變化,它的this永遠是被定義的函數域中的this。

//不用箭頭函數
let person = {
    hello: function(thing) {
        return function() {
            console.log(this + " says hello " + thing);
        }
    }
}
let helloTest = person.hello('world');
helloTest(); //輸出[object Window] says hello world


//使用箭頭函數
let person = {
    hello: function(thing) {
        return () => {
            console.log(this + " says hello " + thing);
        }
    }
}
let helloTest = person.hello('world');
helloTest(); //輸出[object Object] says hello world

需要注意的是,需要用一個function()把箭頭函數包裹起來,因為如果不這樣的話,它被定義的函數域是window。

bind

用箭頭函數有點麻煩,我們可以這么寫一個bind函數達到效果。

let person = {
    hello: function(thing) {
        console.log(this + " says hello " + thing);
    }
}

let bind = function(func, thisValue) {
    return function() {
        return func.apply(thisValue, arguments)
    }
}

let boundHello = bind(person.hello, person);
boundHello('world'); //輸出[object Object] says hello world

es5給所有Function封裝了上面的bind方法,所以我們只需要這么寫:

let person = {
    hello: function(thing) {
        console.log(this + " says hello " + thing);
    }
}

let boundHello = person.hello.bind(person);
boundHello('world'); //輸出[object Object] says hello world

這就是bing()方法的來歷0.0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM