### 一、this 的产生
  首先this是在**函数**被调用的时候确定的,这一点至关重要,同时被确定的还有arguments。具体来说this是函数被调用时建立的一个绑定,它指向 什么是完全由函数被调用的调用点来决定的。
### 二、this的用法和指向问题
  this 有四种绑定的规则,同时这四种绑定规则对应不同this指向。
1. 隐式绑定
2. 显式绑定
3. new 绑定
4. window 绑定
**隐式绑定**
```
const user = {
name: 'Tyler',
age: 27,
greet() {
alert(`Hello, my name is ${this.name}`)
}
}
user.greet()
```
如果你要调用`user`对象上的`greet`方法,你会用到点号,这就是我们常见的点调用‘隐式绑定’。点左边就是this指向的对象。
**显式绑定**
  隐性绑定中有一个致命的限制,就是上下文必须包含我们的函数,如果不仅仅user要用到,address、test对象都要用到,不可能所有对象要一一写进去,这时候我们可以用显示绑定。call apply bind 绑定
~~~
function foo(x, y ){
console.log(this.a, x, y);
}
var obj = {
a : 10
}
foo.call(obj, 1, 3)
foo.apply(obj, [1, 3]) //接受一个数组
var newFoo = foo.bind(obj, 1, 3) //创建一个新的函数
newFoo()
~~~
**new 绑定**
   new构造函数产生一个新的对象,this绑定的就是新创建的对象。
~~~jsx
function Person(name){
this.name = name;
this.say = function(){
return "I am " + this.name;
}
}
var person1 = new Person('nicole');
person1.say(); // "I am nicole"
~~~
此时的this 指向的就是person1
**window 绑定**
函数调用,如果没有点调用,默认是window调用,所以此时的this 绑定的window。
~~~
function foo(){
var a = 1 ;
console.log(this.a); // 10
}
var a = 10;
foo();
~~~
### 三、使用this注意事项
1、事件绑定中的this,指向的是绑定的dom。
~~~
document.querySelector('.test').addEventListener('click', function() {
console.log(this)
})
~~~
this 指向document.querySelector('.test')
2、setTimeout 中this指向问题,使用setTimeout时需要注意函数this指向问题。下面函数打印出来的name为undefined,因为this指向window,
原因为setTimeout中没有保存obj.sayName的执行环境
```
var obj = {
name: 'hc3001',
sayName: function() {
console.log(this.name)
}
}
setTimeout(obj.sayName, 1000) //undefined
// 利用闭包直接调用obj.sayName()
var obj = {
name: 'hc3001',
sayName: function() {
console.log(this.name)
}
}
setTimeout(function() {
obj.sayName()
}, 1000) // 'hc3001'
//用bind解决
setTimeout(obj.sayName.bind(obj), 1000)
// 'hc3001'
```
3、箭头函数的使用,箭头函数调用时不绑定this和arguments,所以this的来源为上一个代码块的this。
~~~
var x = 11;
var obj = {
x: 22,
say: () => {
console.log(this.x);
}
}
obj.say();
//输出的值为11
~~~
此时say中的this 指向window而不是指向obj,另外注意箭头函数也是不产生arguments的。