在面向對象的JS中,咱們瞭解到在JS中,一切都是對象。由於一切都是對象,咱們開始明白咱們能夠爲函數設置和訪問其餘屬性。而this提供了一種更優雅的方式隱式「傳遞」一個對象的引用。
關於this,咱們常見的誤區:編程
function f1() { console.log(this) } f1() // window
關於這兩個誤區,其實在官方文檔中有很明確的說明。數組
函數的調用方式決定了this的值。
那麼this並非指向函數自己,也不是指向函數的做用域,而是在運行時進行綁定的,並非在編寫時綁定,它的上下文也取決於函數調用時的各類條件。this的綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式。app
它指向什麼徹底取決於函數在哪裏被調用,也就是說,誰調用,誰負責函數
而bind()、apply()、call()則是能夠更改this指向的方法this
(這部分並非翻譯的原文,由於原文關於this講的不是很細緻,而我以爲理解了this,才能瞭解bind()、apply()、call()有什麼用處。因此這塊是我根據《你不知道的JavaScript 上卷》this的部分,粗略的介紹了部分,有興趣的話能夠看看那本書,關於this講的很細緻。)spa
到目前爲止,咱們已將函數視爲由名稱(可選,也能夠是匿名函數)組成的對象及其在調用時執行的代碼。但這不是所有真相,實際上函數看起來更接近下面的圖像:翻譯
如今,我將經過示例介紹每一個函數中出現的這3種相似方法。3d
官方文檔說: bind()方法建立一個新函數,當調用時,將其關鍵字設置爲提供的值。code
這很是強大。它讓咱們在調用函數時明肯定義它的值。咱們來看看cooooode:對象
var pokemon = { firstname: 'Pika', lastname: 'Chu ', getPokeName: function() { var fullname = this.firstname + ' ' + this.lastname; return fullname; } }; var pokemonName = function() { console.log(this.getPokeName() + 'I choose you!'); }; var logPokemon = pokemonName.bind(pokemon); // creates new object and binds pokemon. 'this' of pokemon === pokemon now logPokemon(); // 'Pika Chu I choose you!'
讓咱們分解吧。當咱們使用bind()方法時:
很酷的是,在咱們bind()一個值後,咱們能夠像使用任何其餘正常函數同樣使用該函數。咱們甚至能夠更新函數來接受參數,並像這樣傳遞它們:
var pokemon = { firstname: 'Pika', lastname: 'Chu ', getPokeName: function() { var fullname = this.firstname + ' ' + this.lastname; return fullname; } }; var pokemonName = function(snack, hobby) { console.log(this.getPokeName() + 'I choose you!'); console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby); }; var logPokemon = pokemonName.bind(pokemon); // creates new object and binds pokemon. 'this' of pokemon === pokemon now logPokemon('sushi', 'algorithms'); // Pika Chu loves sushi and algorithms
call()的官方文檔說: call()方法調用具備給定此值的函數和單獨提供的參數。
這意味着,咱們能夠調用任何函數,並在調用函數中明確指定what_ this _should reference_。真的相似於bind()方法!這絕對可讓咱們免於編寫hacky代碼。
bind()和call()之間的主要區別在於call()方法:
call()和apply()用於徹底相同的目的。它們之間的惟一區別是_ call()指望全部參數都單獨傳遞,而apply()須要一個數組。例:
var pokemon = { firstname: 'Pika', lastname: 'Chu ', getPokeName: function() { var fullname = this.firstname + ' ' + this.lastname; return fullname; } }; var pokemonName = function(snack, hobby) { console.log(this.getPokeName() + ' loves ' + snack + ' and ' + hobby); }; pokemonName.call(pokemon,'sushi', 'algorithms'); // Pika Chu loves sushi and algorithms pokemonName.apply(pokemon,['sushi', 'algorithms']); // Pika Chu loves sushi and algorithms
這些內置的方法存在於每一個JS函數中都很是有用。即便你最終沒有在平常編程中使用它們,你仍然會在閱讀其餘人的代碼時常常遇到它們。