我們先來看一個例子
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; obj.foo(); // 2
this指向了obj,因為foo執行時的call-site(可以理解為呼叫時所在作用域)在obj上面。注意是運行的時候,和在哪裡聲明的沒有關係。
call-site and call-stack
call-site姑且理解為呼叫域,call-stack為呼叫棧。如下程式碼可以輔助我們理解
function baz() { // call-stack is: `baz` // so, our call-site is in the global scope console.log( "baz" ); bar(); // <-- call-site for `bar` }
在baz()中呼叫bar(),所以bar的呼叫域是baz,此時bar的呼叫棧只有baz;而baz本身暴露在全域作用域中,所以它的呼叫域則也在全域作用域中。
function bar() { // call-stack is: `baz` -> `bar` // so, our call-site is in `baz` console.log( "bar" ); foo(); // <-- call-site for `foo` } function foo() { // call-stack is: `baz` -> `bar` -> `foo` // so, our call-site is in `bar` console.log( "foo" ); } baz(); // <-- call-site for `baz`
理解之後再回頭看開頭的例子,是不是感覺清晰了很多。其實this只是指向了它的call-site
還有以下玩法:
function foo() { console.log( this.a ); } var obj2 = { a: 42, foo: foo }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.foo(); // 42 Implicitly Lost(隐式丢失) function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // function reference/alias! var a = "oops, global"; // `a` also property on global object bar(); // "oops, global"
雖然bar引用了obj上的foo,但實際上相當於是直接對foo引用而已,所以會預設綁定到全域。
function foo() { console.log( this.a ); } function doFoo(fn) { // `fn` is just another reference to `foo` fn(); // <-- call-site! } var obj = { a: 2, foo: foo }; var a = "oops, global"; // `a` also property on global object doFoo( obj.foo ); // "oops, global"