若是一個函數被做爲一個對象的方法調用,那麼this將被指派爲這個對象。數組
1
2
3
4
5
6
7
8
|
var
parent = {
method:
function
() {
console.log(
this
);
}
};
parent.method();
// <- parent
|
注意這種行爲很是「脆弱」,若是你獲取一個方法的引用而且調用,那麼this的值不會是parent了,而是window全局對象。這讓大多數開發者迷惑。app
1
2
3
4
|
var
parentless = parent.method;
parentless();
// <- Window
|
底線是你應該查看調用鏈,以理解被調用函數是一個對象的屬性仍是它本身。若是它被做爲屬性調用,那麼this的值將變成該屬性的對象,不然this的值將被指派爲全局對象或window。若是在嚴格模式下,this的值將是undefined。less
在被看成構造函數的狀況下,當使用new關鍵字時,this將被指派爲被建立的實例對象。ide
1
2
3
4
5
6
|
function
ThisClownCar () {
console.log(
this
);
}
new
ThisClownCar();
// <- ThisClownCar {}
|
注意,在這種狀況下沒有辦法識別出一個函數是否應該被用做構造函數,所以省略new關鍵字致使this的結果將是全局對象,就像咱們上面看到的沒有用parent調用的例子。函數
1
2
|
ThisClownCar();
// <- Window
|
.call
、 .apply
和.bind
方法用來操做調用函數的方式,幫咱們定義this的值和傳遞給函數的參數值。this
Function.prototype.call 能夠有任意數量的參數,第一個參數被分配給this,剩下的被傳遞給調用函數。spa
1
2
|
Array.prototype.slice.call([1, 2, 3], 1, 2)
// <- [2]
|
Function.prototype.apply 的行爲和.call相似,但它傳遞給函數的參數是一個數組,而不是任意參數。prototype
1
2
|
String.prototype.split.apply(
'13.12.02'
, [
'.'
])
// <- ['13', '12', '02']
|
Function.prototype.bind 建立一個特殊的函數,該函數將永遠使用傳遞給.bind的參數做爲this的值,以及可以分配部分參數,建立原函數的珂里化(curride)版本。code
1
2
3
4
5
6
7
8
9
10
11
|
var
arr = [1, 2];
var
add = Array.prototype.push.bind(arr, 3);
// effectively the same as arr.push(3)
add();
// effectively the same as arr.push(3, 4)
add(4);
console.log(arr);
// <- [1, 2, 3, 3, 4]
|
在下面的例子,this將沒法在做用域鏈中保持不變。這是規則的缺陷,而且經常會給業餘開發者帶來困惑。對象
1
2
3
4
5
6
7
8
9
10
11
|
function
scoping () {
console.log(
this
);
return
function
() {
console.log(
this
);
};
}
scoping()();
// <- Window
// <- Window
|
有一個常見的方法,建立一個局部變量保持對this的引用,而且在子做用域中不能有同命變量。子做用域中的同名變量將覆蓋父做用域中對this的引用。
1
2
3
4
5
6
7
8
9
10
|
function
retaining () {
var
self =
this
;
return
function
() {
console.log(self);
};
}
retaining()();
// <- Window
|
除非你真的想同時使用父做用域的this,以及當前this值,因爲某些莫名其妙的緣由,我更喜歡是使用的方法.bind函數。這能夠用來將父做用域的this指定給子做用域。
1
2
3
4
5
6
7
8
|
function
bound () {
return
function
() {
console.log(
this
);
}.bind(
this
);
}
bound()();
// <- Window
|