[TOC]
理解 `this` 的第一步就是要明白:
`this`既不指向函數自身,也不指向函數的詞法作用域;
`this`是在運行時進行綁定的,而不是在編寫時綁定,它的上下文取決于函數調用時的各種條件;
`this`的綁定和函數聲明的位置沒有任何關系,只取決于函數的調用位置和調用方式;
`this`綁定規則有4點:按優先級1到4判斷
1. 由`new`調用?綁定到新創建的空對象;
2. 由`call、apply、bind`調用?綁定到指定的參數對象;如`foo.call(obj)`
3. 由上下文對象調用?綁定到這個上下文對象;如`obj.foo()`
4. 默認情況下綁定到全局對象( `window` ),在嚴格模式下綁定到`undefined`;
# 一般情況
1. 情況1:如果一個函數中有 `this` ,但是它沒有被上一級的對象所調用,那么 `this` 指向的就是 `window`,這里需要說明的是在 js 的嚴格模式 中 `this` 指向的不是 `window`,但是我們這里不探討嚴格問題(默認的`this`不再是`window`,而是 `undefined`。),你想了解可以自行上網查找。
2. 情況2:如果一個函數中有`this`,這個函數有被上一級的對象所調用,那么`this`指向的就是上一級的對象。
3. 情況3:如果一個函數中有`this`,**這個函數中包含多個對象,盡管這個函數是被最外層的對象所調用,`this`指向的也只是它上一級的對象**
例子3可以證明,如果不相信,那么接下來我們繼續看幾個例子。
```js
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j(); // 這里在運行時是 window 環境下調用了 fn
```
# 改變this的指向請看[Javascript中apply、call、bind](Javascript中apply、call、bind.md)
解JS構造函數中 `this` 和 `return`:
先看一段代碼,
```
function Foo(name,age){
this.name=name;
this.age=age;
}
var foo=new Foo("Tom",14);
foo.name; //Tom
foo.age; //14
```
使用構造函數實例化發生的流程:
1. 建立一個`foo`的空對象。
2. 將構造函數中的`Foo`的`this`指向對象`foo`。
3. `foo`的`__proto__`屬性指向`Foo`函數的`prototype`原型。
4. 執行構造函數中的代碼。
相對于普通函數,構造函數中的 `this` 是指向實例的,而普通函數調用中的`this` 是指向`windows`的。
構造函數中如果加入了 `return` 的話,分兩種情況
```
function Foo(name,age){
this.name=name;
this.age=age;
return {name:"Jeff"}
}
var foo=new Foo("Tom",14);
foo.name; //Jeff
```
1. return 的是五種簡單數據類型:`String,Number,Boolean,Null,Undefined`。
這種情況下,忽視`return`值,依然返回this對象。
2. return 的是`Object`。
```js
function fn()
{
this.user = '追夢子';
return {};
}
var a = new fn;
console.log(a.user); //undefined
```
```js
function fn()
{
this.user = '追夢子';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
```
?這種情況下,不再返回 `this` 對象,而是返回 `return` 語句的返回值。
# 箭頭函數中的 this
箭頭函數中的 this:
* ?ES6 中箭頭函數( `=>`) 內部沒有 `this` 對象,導致 **內部的 `this`就是上一層作用域的 `this`**;默認指向在定義它時所處的對象(宿主對象),另外由于沒有 `this`,所以它不能用于定義構造函數。
* ?而不是執行時的對象,定義它的時候,可能環境是 `window`,也有可能是其他的。
由于箭頭函數不綁定 `this`, 它會捕獲其所在(即定義的位置)上下文的 `this` 值, 作為自己的 `this` 值,
1. `this`一旦綁定了上下文,就不會被任何代碼改變。 所以 `call() / apply() / bind()` 方法對于箭頭函數來說只是傳入參數,對它的 `this` 毫無影響。
2. 考慮到 `this` 是詞法層面上的,嚴格模式中與 `this` 相關的規則都將被忽略。(可以忽略是否在嚴格模式下的影響)
```js
const adder = {
base : 1,
add : function(a) {
var f = v => v + this.base
return f(a);
},
addThruCall: function inFun(a) {
var f = v => v + this.base;
var b = { base : 2 };
return f.call(b, a);
}
};
console.log(adder.add(1)); // 輸出 2
console.log(adder.addThruCall(1)); // 仍然輸出 2(而不是3,其內部的this并沒有因為call() 而改變,其this值仍然為函數inFun的this值,指向對象adder
```
## 箭頭函數當做一個方法使用
```js
function test (){
this.a = 'a1';
this.c = {
a: 'a2',
run: function (){
console.log(this.a) // 這層的作用域按照上述規則
return ()=> {
console.log(this.a) // 綁定了上層作用域
}
}
}
}
const t = new test()
t.c.run()() // 'a2' 'a2'
// const f = t.c.run
// f()(); // 'undefined' 'undefined'
```
上例子中,箭頭函數中的 `this` 綁定了上層作用域的`this`,只會受到上層作用域的影響!這里的它的上層作用域會受到
# 參考
[徹底理解js中this的指向,不必硬背。](https://www.cnblogs.com/pssp/p/5216085.html)
[meaning-of-this-in-node-js-modules-and-functions](https://stackoverflow.com/questions/22770299/meaning-of-this-in-node-js-modules-and-functions)
- 步入JavaScript的世界
- 二進制運算
- JavaScript 的版本是怎么回事?
- JavaScript和DOM的產生與發展
- DOM事件處理
- js的并行加載與順序執行
- 正則表達式
- 當遇上this時
- Javascript中apply、call、bind
- JavaScript的編譯過程與運行機制
- 執行上下文(Execution Context)
- javascript 作用域
- 分組中的函數表達式
- JS之constructor屬性
- Javascript 按位取反運算符 (~)
- EvenLoop 事件循環
- 異步編程
- JavaScript的九個思維導圖
- JavaScript奇淫技巧
- JavaScript:shim和polyfill
- ===值得關注的庫===
- ==文章==
- JavaScript框架
- Angular 1.x
- 啟動引導過程
- $scope作用域
- $q與promise
- ngRoute 和 ui-router
- 雙向數據綁定
- 規范和性能優化
- 自定義指令
- Angular 事件
- lodash
- Test