在 JavaScript 的世界裏,一切均可以理解爲對象。包括函數,函數在 JS 中也是一類對象,不過是一類特殊的對象,將函數做爲構造類來使用,能夠生成新的對象,從而實現JS 世界中的類的概念。javascript
接下來咱們從頭開始回顧函數的發展過程。java
咱們知道,函數包含定義
和調用
兩個階段,函數在使用以前,必須先定義。數組
有的同窗可能更習慣用
聲明
來表示定義,不要緊,均可以。app
函數定義共分爲以下幾種:函數
接下來咱們一一介紹。ui
最先咱們定義一個函數是這樣子的,也是最多見的。this
function test(){
//todo
}
複製代碼
很簡單,定義好以後,咱們就可使用了:spa
test();
複製代碼
定義一個函數,也能夠理解爲定義一個變量,將這個變量的值指向一個函數,因而就有了另一種定義函數的方式(表達式定義):code
var test = function(){
//todo
}
複製代碼
調用也很簡單對象
test();
複製代碼
那聲明式定義函數與表達式定義函數之間的區別是什麼? 你們看下面兩段代碼:
test();
function test(){
//todo
}
複製代碼
對象方法的調用:
var a = {
say:function(){
//todo
}
}
a.say();
複製代碼
函數調用時, 內部的this,必定是指向函數所屬的對象的。
var say = new Function('a','b','return a + b');
複製代碼
ES6 規範中的函數定義方式。
let say = () => {};
複製代碼
let say = function(){console.log(this)}
say();
複製代碼
間接調用分爲兩種,call
和 apply
,call
和 apply
的做用就是改變函數調用的上下文。下面舉個例子來講明一下它們的做用。
咱們先定義一個函數 test:
function test(){
console.log(this);
}
複製代碼
這個函數很簡單,僅僅是打印當前上下文 this。
咱們這樣調用
test();
複製代碼
輸出結果是 window。
我如今又有一個對象 a :
var a = {
name: '小A'
}
複製代碼
我想讓a 對象執行 test 方法提供的功能,該怎麼辦呢?
固然,你們能夠說,我給 a 對象增長一個方法 testA,而後執行 a 對象的 testA 方法,不就能夠了嗎?
a.testA = function(){
console.log(this);
}
a.testA();
複製代碼
那咱們若是不想爲 a 對象額外增長這個方法,而是複用最開始定義的 test 方法,怎麼辦?? 這就是 call 和 apply 的做用。
test.call(a);
//或者
test.apply(a);
複製代碼
這就是改變函數執行上下文的意思。
call 和 apply 的惟一區別是傳參不一樣。
call 的第一個參數是上下文對象,剩餘的參數就是函數調用時的參數。
test.call(a, 1, 2, 3);
複製代碼
apply 的第一個參數是上下文對象,第二個參數是個數組,數組中存放的是函數調用時的參數。
test.apply(a, [1, 2, 3]);
複製代碼
var a = {
name: 'A',
say: function(){
console.log(this.name);
}
}
a.say();
複製代碼
打印的是 'A'。
咱們接着看:
var a = {
name: 'A',
say: function(){
function test(){
console.log(this.name);
}
test();
}
}
a.say();
複製代碼
執行結果是 undefined,而不是 'A'。 這是爲何?
一個簡單的理解方法:
函數調用時
所指向的對象。test() 等價爲 window.test()
因此 test() 執行時 this 指向 window。
定義時
所指向的執行上下文。以上就是對函數 this 指向的一些概括,利用這些方法,能讓你精準地判斷 this 指向,即便寫一百層複雜嵌套函數,也能輕鬆判斷出來。
(本文完)