> For the complete documentation index, see [llms.txt](https://shenjunhong.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://shenjunhong.gitbook.io/blog/js/js-zhi-this-zhi-xiang.md).

# js之this指向

两种错误认识

1. this 指向自身

this 的指向在函数定义阶段是无法确定的，只有函数执行时才能确定 this 到底指向谁，实际 this 的最终指向是调用它的那个对象。

```js
function foo(num) {
  this.count++; // 记录 foo 被调用次数
}
foo.count = 0;
window.count = 0;
for (let i = 0; i < 10; i++) {
  if (i > 5) {
    foo(i);
  }
}
console.log(foo.count, window.count); // 0 4
```

2. this 指向函数作用域

```js
function foo() {
  var a = 2;
  this.bar();
}
function bar() {
  console.log(this.a);
}
foo(); // undefined
bar(); // undefined
```

* 浏览器：在浏览器环境里是没有问题的，全局声明的函数放在了 window 对象下，foo 函数里面的 this 代指的是 window 对象，在全局环境中并没有声明变量 a，因此在 bar 函数中的 this.a 自然没有定义，输出 undefined。
* Node.js：在 Node.js 环境下，声明的 function 不会放在 global 全局对象下，因此在 foo 函数里调用 this.bar 函数会报 TypeError: this.bar is not a function 错误。要想运行不报错，调用 bar 函数时省去前面的 this。

### This 四种绑定规则

1. 默认绑定

当函数调用属于独立调用，无法调用其他规则时，我们给它一个称呼“默认绑定”。

```js
function demo() {
  console.log(this.a); // 1
}
var a = 1;
demo();
```

非严格模式下调用， 浏览器会将 a 绑定到 window\.a，以下代码使用 var 声明的变量 a 会输出 1.

以下代码使用 let 或 const 声明变量 a 结果会输出 undefined

```js
function demo() {
  console.log(this.a); // undefined
}
let a = 1;
demo();
```

在举例子的时候其实想要重点说明 this 的默认绑定关系的，但是你会发现上面两种代码因为分别使用了 var、let 进行声明导致的结果也是不一样的，归其原因涉及到 顶层对象的概念

顶层对象（浏览器环境指 window、Node.js 环境指 Global）的属性和全局变量属性的赋值是相等价的，使用 var 和 function 声明的是顶层对象的属性，而 let 就属于 ES6 规范了，但是 ES6 规范中 let、const、class 这些声明的全局变量，不再属于顶层对象的属性。

2. 隐式绑定

在函数的调用位置处被某个对象包含，拥有上下文，看以下示例：

```js
function child() {
  console.log(this.name);
}
let parent = {
  name: "zhangsan",
  child,
};
parent.child(); // zhangsan
```

函数在调用时会使用 parent 对象上下文来引用函数 child，可以理解为 child 函数被调用时 parent 对象拥有或包含它。

3. 显示绑定

使用 call、apply、bind 方法可以改变 this 的指向，看以下示例：

```js
function test(...arg) {
  console.log(this.variable + arg);
}

var obj = {
  variable: 1,
};

test();

test.apply(obj, [2, 2, 3]);
test.call(obj, 2);
var c = test.bind(obj, 3);
c();
```

把 obj 绑定到 thisObj,这时 thisObj 就具备了 obj 的属性和方法。

与 call 和 apply 不同的是，bind 绑定之后返回绑定完成的函数， 不会立即执行，需要再显式执行一次此函数才能完成调用。

4. new 绑定

new 绑定也可以影响 this 调用，它是一个构造函数，每一次 new 绑定都会创建一个新对象。

```js
function Fruit(name) {
  this.name = name;
}

const f1 = new Fruit("apple");
const f2 = new Fruit("banana");
console.log(f1.name, f2.name); // apple banana
```

优先级

如果 this 的调用位置同时应用了多种绑定规则，它是有优先级的：new 绑定 -> 显示绑定 -> 隐式绑定 -> 默认绑定。

箭头函数

箭头函数并非使用 function 关键字进行定义，也不会使用上面所讲解的 this 四种标准规范，箭头函数会继承自外层函数调用的 this 绑定。

```js
function fruit() {
  return () => {
    console.log(this.name);
  };
}
var apple = {
  name: "苹果",
};
var banana = {
  name: "香蕉",
};
var fruitCall = fruit.call(apple);
fruitCall.call(banana); // 苹果
```

### This 指向问题遇到的坑

1. 原型链上使用箭头函数

```js
function Fruit(name) {
  this.name = name;
}
Fruit.prototype.info = () => {
  console.log(this.name);
};
var name = "Banana";
const f1 = new Fruit("Apple");
f1.info(); // Banana
```

2. 通过函数和原型链模拟类

```js
function Fruit(name) {
  this.name = name;
}
Fruit.prototype.info = function () {
  console.log(this.name);
};
var name = "Banana";
const f1 = new Fruit("Apple");
f1.info(); // Apple
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shenjunhong.gitbook.io/blog/js/js-zhi-this-zhi-xiang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
