首發我的博客瀏覽器
JavaScript 中的this
,你們都用過。可是它到底指向哪裏呢?今天在閱讀 《你不知道的JavaScript (上卷)》再結合本身平時看的博客,對它又有了新的認識,在此來作個小結,再碰到this
,就不再用擔憂不知道它指向哪裏了。
如下示例(在瀏覽器端運行)app
function sayHi(){ var hi = 1; console.log(this.hi); } var hi = 2; var obj = { hi : 3, sayHi : sayHi } // output sayHi(); // 2 obj.sayHi(); // 3
從上述代碼的執行結果咱們能夠看出,直接調用 sayHi()
函數,它輸出的 this.hi
不指向函數體內本身定義的 hi
變量,也就是說,this
的指向與詞法做用域無關,這也是剛接觸 JavaScript的同窗常犯的一個錯誤(包括我本身),認爲 this.xx
就指向函數體裏面定義的變量 xx
。sayHi
函數的只定義了一次,但obj.sayHi()
與 sayHi()
的輸出結果不同,也偏偏證實了 函數體內this的指向與函數定義的位置無關,而與函數被調用的位置有關,至於爲何輸出結果不同,在下文會講到。函數
默認綁定比較常見,表現形式就是在全局做用域中獨立調用,如上文中的 sayHi()
,這種直接調用方式函數體內的 this
就應用了默認綁定規則,默認綁定有如下兩種狀況。oop
this
綁定到 undefined
this
指向全局對象 window
/***** 如下例子爲處在嚴格模式下 *****/ function fn1(){ 'use strict' console.log(this); } fn1(); // undefined /***** 如下例子處於非嚴格模式下被調用 *****/ function fn2(){ console.log(this); } fn2(); // window function fn3(){ console.log(this); } /* * 這也是在非嚴格模式下被調用 * 由於在函數定義時沒有用嚴格模式 */ 'use strict' fn3(); // window
隱式綁定的常見形式爲 obj.fn()
,若obj
對象中有 fn
這個方法(fn能夠在別處定義,但必須被添加到obj中做爲obj的一個屬性方法),那麼 fn
中的 this
就指向 obj
對象,如最開始代碼中 obj.sayHi()
輸出3,就是由於sayHi
中的this
隱式綁定到obj
對象。(我的以爲默認綁定中綁定到window對象時也能夠歸類爲隱式綁定,由於在全局對象中,非嚴格模式且不考慮ES6的話,全部的全局變量都自動成爲window的屬性)。來看個具備迷惑性的例子(出自於原書)post
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 函數別名! var a = "oops, global"; // a 是全局對象的屬性 bar(); // "oops, global"
這是個具備迷惑性的例子,obj
對象有函數 foo
這個方法,後面又在全局做用域中,bar
引用了這個方法,最後再調用 bar
。咱們只須要關注函數最後被調用的位置,它是在全局做用域中被單獨調用的,因此仍是爲默認綁定,指向 window
this
顯示綁定就比較簡單了,用 call,apply,bind方法,都會綁定函數中的this到傳入的參數對象中code
所謂new綁定就是在用構造函數new一個對象的時候,其中的this指向生成的對象。這就完了嘛?尚未哦。對象
簡單的說,箭頭函數中的this,會綁定到函數外(也就是上一層做用域中的this),函數外的this指向哪,箭頭函數中的this就指向哪。(代碼出自於原書)blog
function foo() { // 返回一個箭頭函數 return (a) => { //this 繼承自 foo() console.log( this.a ); }; } var obj1 = { a:2 }; var obj2 = { a:3 }; var bar = foo.call( obj1 ); /* * foo先綁定this到obj1對象上,因此foo內的this指向obj1, * 返回的箭頭函數根據詞法做用域規則,繼承了外部foo的this, * 因此箭頭函數中的this指向obj1 */ bar.call( obj2 ); // 2, 不是 3 ! /* * 箭頭函數中this一但綁定,不可更改 * 此時仍是指向obj1 * 因此輸出的是 obj1.a => 2 */
new > 顯示 > 隱式 > 默認繼承
上述知識來自《你不知道的JavaScript(上卷)》