176 lines
5.6 KiB
Markdown
176 lines
5.6 KiB
Markdown
---
|
||
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) |