下一篇:《你不知道的javascript》筆記_對象&原型javascript
上一篇博客咱們知道詞法做用域是由變量書寫的位置決定的,那this
又是在哪裏肯定的呢?如何可以精準的判斷this
的指向?這篇博客會逐條闡述java
書中有這樣幾句話:segmentfault
this
是在運行時進行綁定的,並非在編寫時綁定,它的上下文取決於函數調用時的各類條件
this
的綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式當一個函數被調用時,會建立一個活動記錄(有時候也稱爲執行上下文)。這個記錄會包含函數在哪裏被調用(調用棧)、函數的調用方法、傳入的參數等信息。this 就是記錄的其中一個屬性,會在函數執行的過程當中用到。閉包
關於執行上下文,能夠參考《javascript高級程序設計》筆記:內存與執行環境app
最經常使用的函數調用類型——獨立函數調用,使用的即爲默認綁定規則,在非
strict mode
下,this指向全局對象
function foo1() { console.log(this.a); } var a = 10; foo1(); // 10 // 即便函數嵌套比較深 function foo2() { foo1(); } function foo3() { foo2(); } foo3();
固然,咱們實際使用中,難以判別的並非直接型的默認綁定模式,而是隱式綁定丟失型的默認綁定(下面會着重說明)函數
調用的位置是否有上下文對象,或者說被某個對象擁有或包含
// 基本形式 function foo() { console.log(this.a); } var obj = { a: 10, foo }; obj.foo(); // 10
隱式綁定中的幾個雷區:oop
1. 多個對象嵌套引用時,只有最後一層在調用位置中起做用this
function foo() { console.log(this.a); } var obj2 = { a: 42, foo }; var obj1 = { a: 10, obj2 }; obj1.obj2.foo(); // 42
2.【隱式丟失】當調用函數被從新賦值爲新變量,調用新變量時this
指向會有不一樣prototype
// 共用部分 function foo(){ console.log(this.a); } var obj = { a: 10, foo }; var a = 'opps, global'; // 直接賦值 var bar = obj.foo; bar(); // 'oops, global' // 回調間接賦值1 function doFoo(fn) { fn(); } doFoo(obj.foo); // 'oops, global' 至關於間接賦值 // 回調間接賦值2 setTimeout(obj.foo, 100); // 'oops, global' 內置的setTimeout也至關於間接賦值
經典綜合案例:設計
var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); arguments[0](); } }; obj.method(fn, 123);
分析:fn()
爲函數fn
的引用,默認綁定,指向全局;arguments[0]();
至關於下面的引用,數據隱式綁定,綁定對象爲arguments
,其屬性length
值爲參數數量2
arguments: { '0': function fn(){ console.log(this.length); } }
答案:10 2
call()
/apply()
/bind()
可以顯式修改this
指向
經過上述方法調用的方式爲顯示綁定,它們第一個參數是一個對象,在調用函數時,綁定在this
中。
關於三者的基本用法和說明在以前博客《javascript高級程序設計》函數調用模式 & this深度理解中已做說明,在此不作嘮述
兩點注意:
1. 經過顯式綁定的不能再修改它的this
指向
function foo() { console.log(this.a); } var obj = { a: 2 }; var bar = function() { foo.call(obj); } bar(); // 2 setTimeout(bar, 200); // 2 bar.call(window); // 2
2. 將null
/undefined
做爲第一個參數時,調用會忽略這些值,採用默認綁定規則
function foo() { console.log(this.a); } var a = 2; foo.call(null); // 2
new
綁定使用關鍵字new
執行函數,當函數無返回值或返回值非對象時,this
指向爲實例對象
new
關鍵字執行函數流程:
this
上須知:構造函數與普通函數無異,做爲區分,咱們通常講經過new
調用的函數稱爲構造函數,並大寫第一個單詞。全部函數都可由關鍵字new
調用
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); // 2
new
綁定 --> 顯式綁定 --> 隱式綁定 --> 默認綁定
new
綁定】函數是否在new
中調用?若是是,this
綁定的是新建立的對象call
/aplly
/bind
中調用?若是是,this
綁定的是指定對象this
綁定到那個上下文對象this
綁定嚴格模式下爲undefined
,非嚴格模式下爲全局對象this
ES6中箭頭函數不使用上面this
的四種標準規格,而是根據外層(函數或者全局)做用域來決定this
指向
下面是一個普通函數和箭頭函數的對比:
function foo1() { setTimeout(() => { console.log(this.a) }, 100) } function foo2() { setTimeout(function() { console.log(this.a) }, 100) } var a = 10; var obj = { a: 2 }; foo1.call(obj); // 2 箭頭函數this指向外層(obj) foo2.call(obj); // 10 隱式丟失,默認綁定
【利用閉包】理解箭頭函數中的this
:
// 上例中的箭頭函數至關於 function foo1() { var self = this; setTimeout(function() { console.log(self.a) }, 100) }