freeCodeCamp/guide/chinese/javascript/this-reference/index.md

176 lines
5.6 KiB
Markdown
Raw Normal View History

---
title: this reference
localeTitle: 这个参考
---
## `this`参考
在JavaScript中每个函数都有`this`引用在声明它自动创建。该参考颇为相似, `this`在其他基于类的语言如Java或C参考JavaScript是一种基于原型的语言并没有“阶级”的概念 _它指向哪个对象有时调用的函数_ 该对象称为_上下文_ 。但是在JavaScript中 _函数内部的`this`引用可以绑定到不同的对象具体取决于调用函数的位置_ 。以下是JavaScript中`this`绑定的5个基本规则
### 规则1
在全局范围中调用函数时, `this`引用默认绑定到**全局对象** (浏览器中的`window`或Node.js中的`global` )。例如:
```javascript
function foo() {
this.a = 2;
}
foo();
console.log(a); // 2
```
注意:如果在严格模式下声明上面的`foo()`函数,那么在全局范围内调用此函数, `this`将是`undefined`并且赋值`this.a = 2`将抛出`Uncaught TypeError`异常。
### 规则2
我们来看下面的例子:
```javascript
function foo() {
this.a = 2;
}
var obj = {
foo: foo
};
obj.foo();
console.log(obj.a); // 2
```
显然,在上面的代码片段中, `foo()`函数被调用, _上下文_是`obj`对象,现在`this`引用绑定到`obj` 。因此,当使用上下文对象调用函数时, `this`引用将绑定到此对象。
### 规则3
`.call` `.apply`和`.bind`都可以在调用点使用显式绑定`this` 。使用`.bind(this)`是你可以在很多React组件中看到的东西。
```javascript
var foo = function() {
console.log(this.bar)
}
foo.call({ bar: 1 }) // 1
```
这是一个快速的例子,说明如何使用每个绑定`this`
* `fn.call(thisObj, fnParam1, fnParam2)` `.call()` `fn.call(thisObj, fnParam1, fnParam2)`
* `.apply()` `fn.apply(thisObj, [fnParam1, fnParam2])`
* `.bind()` `const newFn = fn.bind(thisObj, fnParam1, fnParam2)`
### 规则4
```javascript
function Point2D(x, y) {
this.x = x;
this.y = y;
}
var p1 = new Point2D(1, 2);
console.log(p1.x); // 1
console.log(p1.y); // 2
```
您必须注意的是使用`new`关键字调用的`Point2D`函数,并且`this`引用绑定到`p1`对象。因此,当使用`new`关键字调用函数时,它将创建一个新对象,并且`this`引用将绑定到此对象。
注意:当您使用`new`关键字调用函数时我们也将其称为_构造函数_ 。
### 规则5
的JavaScript确定的值`this`在运行时,基于所述当前上下文。所以`this`有时会指向你期望的东西。
考虑这个带有一个名为`makeSound()`的方法的Cat类示例遵循规则4上面中的模式带有构造函数和`new`关键字。
```javascript
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.makeSound(); // Fat Daddy says: Mrrooowww
```
现在让我们试着给猫一个方法来`annoy()`人们通过重复他的声音100次每半秒一次。
```javascript
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var t = setInterval(function() {
this.makeSound(); // <-- this line fails with `this.makeSound is not a function`
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
```
这不起作用,因为在`setInterval`回调中我们创建了一个具有全局范围的新上下文,所以`this`不再指向我们的kitty实例。在Web浏览器中 `this`将指向Window对象该对象没有`makeSound()`方法。
有几种方法可以使它工作:
1创建新的上下文之前分配`this`名为局部变量`me` ,或`self` ,或任何你想将它命名,并使用回调内部的变量。
```javascript
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var self = this;
var t = setInterval(function() {
self.makeSound();
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
```
2同ES6就可以避免分配`this`通过使用箭头功能,其结合本地变量`this`到它的限定的周围的代码的情况下。
```javascript
var Cat = function(name, sound) {
this.name = name;
this.sound = sound;
this.makeSound = function() {
console.log( this.name + ' says: ' + this.sound );
};
this.annoy = function() {
var count = 0, max = 100;
var t = setInterval(() => {
this.makeSound();
count++;
if (count === max) {
clearTimeout(t);
}
}, 500);
};
}
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
kitty.annoy();
```
### 其他资源
* [javascriptissexy.com](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/)
* [你不懂JS](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md)