很多人剛剛接觸前端甚至一些“老”前端都經常會在JavaScript中所謂的難點,如this,原型,繼承,閉包等這些概念中迷失了自我。接下來這篇文章會把我自己對于JavaScript中這些點通過指向的概念做個總結并分享給大家,希望可以幫助大家更好的了解這些所謂的難點。
this是什么?其實它本身就是一種指向。this指向可以分為以下幾種情況
· 普通調用,this指向為調用者
· call/apply調用,this指向為當前thisArg參數
· 箭頭函數,this指向為當前函數的this指向
這個怎么理解呢?接下來我會一一做解析。
通俗理解一下,就是誰調用,則this便指向誰。這里又大致分為幾種情況,分別為
即某方法為某對象上的一個屬性的屬性,正常情況當改方法被調用的時候,this的指向則是掛載該方法的對象。廢話不多說,直接看代碼可能會更好的理解。
var obj = {
a: 'this is obj',
test: function () {
console.log(this.a);
}
}
obj.test();
// this is obj
即該函數為自己獨立的函數,而不是掛載到對象上的屬性(window除外),也不會被當成構造函數來使用,而僅僅是當成函數來使用,此時的this指向則是window對象。例子如下
var a = 'this is window'
function test () {
console.log(this.a);
}
test();
// this is window
這個我們來理解一下,其實也很簡單,我們都知道,window對象是全局對象。其實整個代碼塊等同于
window.a = 'this is window'
window.test = function test () {
console.log(this.a);
// 此時是window為調用者,即this會指向window
}
window.test();
即該函數被當成構造函數來調用,此時的this指向該構造器函數的實例對象。我們來看一個例子,先上一個屬于第二種情況的例子
function test () {
this.a = 'this is test';
console.log(this.a);
console.log(this);
}
test();
// this is test
// Window {}
按照上面的來理解,此時的this的確指向window對象,但是如果我換種形式,將其換成構造函數來調用呢,結果又會如何呢,直接上代碼
function Test () {
this.a = 'this is test';
console.log(this.a);
console.log(this);
}
var test = new Test();
// this is test
// Test {a: 'this is test'}
OK,好像的確沒有問題了,此時的this的確指向了該構造函數的實例對象。具體這里的一些解釋后面我會在原型鏈繼承里面詳細講解。
call方法形式,fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg,當前this指向
arg1[, arg2[, ...]],指定的參數列表
詳細介紹請猛戳MDN
示例代碼如下
function Test () {
this.a = 'this is test';
console.log(this.a);
console.log(this);
}
function Test2 () {
Test.call(this);
}
var test = new Test2();
// this is test
// Test2 {a: 'this is test'}
和call類似,唯一的一個明顯區別就是call參數為多個,apply參數則為兩個,第二個參數為數組或類數組形式, fun.apply(thisArg, [argsArray])
thisArg,當前this指向
一個數組或者類數組對象,其中的數組元素將作為單獨的參數傳給fun函數
詳細介紹請猛戳MDN
但是終究apply里面的數組參數會轉變為call方法的參數形式,然后去走下面的步驟,這也是為什么call執行速度比apply快。這邊詳情有篇文章有介紹,點擊鏈接。
另外,提及到call/apply,怎么能不提及一下bind呢,bind里面的this指向,會永遠指向bind到的當前的thisArg,即context上下文環境參數不可重寫。這也是為什么a.bind(b).call(c),最終的this指向會是b的原因。至于為什么,其實就是bind實現實際上是通過閉包,并且配合call/apply進行實現的。具體的請參考bind MDN里面的用法及 Polyfill實現。
首先需要介紹的一點就是,在箭頭函數本身,它是沒有綁定本身的this的,它的this指向為當前函數的this指向。怎么理解呢,直接上個代碼看下
function test () {
(() => {
console.log(this);
})()
}
test.call({a: 'this is thisArg'})
// Object {a: 'this is thisArg'}
這樣看聯想上面的call/apply調用的理解,好像是沒有問題了,那如果我設置一個定時器呢,會不是this指向會變成Window全局對象呢?答案肯定是不會的,因為箭頭函數里面的this特殊性,它依舊會指向當前函數的this指向。不多BB,直接看代碼
function test () {
setTimeout(() => {
console.log(this);
}, 0)
}
test.call({a: 'this is obj'})
// Object {a: 'this is obj'}
當然普通函數使用setTimeout的話會讓this指向指向Window對象的。demo代碼如下
function test () {
setTimeout(function () {
console.log(this);
}, 0)
}
test.call({a: 'this is obj'})
// Window {...}
這里可能會牽扯到setTimeout的一些點了,具體這里我就不講了,想深入了解的猛戳這里
箭頭函數里面還有一些特殊的點,這里由于只提及this這一個點,其他比如不綁定arguments,super(ES6),抑或 new.target(ES6),他們都和this一樣,他會找尋到當前函數的arguments等。
關于箭頭函數里面的this這里也有詳細的介紹,想深入了解的可以自行閱讀。
上一篇:HTML5新技術,離線緩存
掃一掃 加微信咨詢