var a = 2; function foo(){ console.log(this.a); } function bar(){ var a = 5; foo(); } bar(); // 2
function foo() { console.log( this.a ); } var obj2 = { a: 42, foo: foo }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.foo(); // 42
function foo() { console.log( this.a ); } var obj = { a: 2, foo: foo }; var bar = obj.foo; // 這裏bar將引用foo函數自己,因此不帶有函數對象的上下文 var a = "oops, global"; // a是全局對象的屬性 bar(); // "oops, global"
和回調函數的狀況下(參數傳遞時的隱式賦值)git
function foo() { console.log( this.a ); } function doFoo(fn) { // 參數傳遞時,至關於fn = obj.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"
function foo() { console.log( this.a ); } var obj = { a: 2 }; var bar = function() { foo.call( obj ); }; bar(); // 2 setTimeout( bar, 100 ); // 2 // 硬綁定後bar不管怎麼調用,都不會影響foo函數的this綁定 bar.call( window ); // 2
硬綁定的典型應用是以下的包裹函數:github
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a: 2 }; var bar = function() { return foo.apply( obj, arguments ); // 將obj對象硬編碼進去 }; var b = bar( 3 ); // 2 3 console.log( b ); // 5
即將內部函數用apply硬綁定到某個對象,不管怎麼調用這個包裹函數,都不會影響內部函數的this。
bind輔助函數以下:瀏覽器
function foo(something) { console.log( this.a, something ); return this.a + something; } // simple `bind` helper function bind(fn, obj) { return function() { return fn.apply( obj, arguments ); // 利用參數將obj傳入進去 }; } var obj = { a: 2 }; var bar = bind( foo, obj ); // bind( foo, obj )會返回一個包裹函數 var b = bar( 3 ); // 2 3 console.log( b ); // 5
總結:上述包裹函數,想要包裹其餘函數,只能一個一個重複寫,硬編碼的方式致使不能被重用,當某種功能須要屢次重複使用時,將其抽象出來,成爲函數。app
1. 建立一個新對象(若該函數不是JS內置的,則建立一個新的Object對象);
2. 將this綁定到這個對象;
3. 執行構造函數中的代碼(爲這個新對象添加屬性);
4. 若函數沒有返回其餘對象,則自動返回這個新對象;若函數有return返回的是非對象,則仍是自動返回這個新對象,即覆蓋那個非對象。函數
function foo(a) { this.a = a; } var bar = new foo( 2 ); console.log( bar.a ); // 2
function foo() { console.log( this.a ); } var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3 (p.foo = o.foo)(); // 2,因爲p.foo = o.foo的返回值是目標函數的引用,因此調用位置是foo(),而不是p.foo()或o.foo()
function foo() { // 返回一個箭頭函數 return (a) => { // `this` here is lexically adopted from `foo()` console.log( this.a ); }; } var obj1 = { a: 2 }; var obj2 = { a: 3 }; // foo()不是箭頭函數,他的this被綁定到obj1 var bar = foo.call( obj1 ); // foo.call( obj1 )返回箭頭函數,因此bar爲箭頭函數 bar.call( obj2 ); // 2! 箭頭函數的this沒法被修改,new也不行
以下爲和箭頭函數同樣的模式:oop
function foo() { var self = this; // lexical capture of `this` setTimeout( function(){ console.log( self.a ); }, 100 ); } var obj = { a: 2 }; foo.call( obj ); // 2