2021-05-11 11:33:55 +08:00

265 lines
8.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 彻底理解js中this的指向不必硬背。
  首先必须要说的是this的指向在函数定义的时候是确定不了的只有函数执行的时候才能确定this到底指向谁实际上this的最终指向的是那个调用它的对象这句话有些问题后面会解释为什么会有问题虽然网上大部分的文章都是这样说的虽然在很多情况下那样去理解不会出什么问题但是实际上那样理解是不准确的所以在你理解this的时候会有种琢磨不透的感觉那么接下来我会深入的探讨这个问题。
  为什么要学习this如果你学过面向对象编程那你肯定知道干什么用的如果你没有学过那么暂时可以不用看这篇文章当然如果你有兴趣也可以看看毕竟这是js中必须要掌握的东西。
例子1
```
function a(){
var user = "追梦子";
console.log(this.user); //undefined
console.log(this); //Window
}
a();
```
按照我们上面说的this最终指向的是调用它的对象这里的函数a实际是被Window对象所点出来的下面的代码就可以证明。
```
function a(){
var user = "追梦子";
console.log(this.user); //undefined
console.log(this);  //Window
}
window.a();
```
和上面代码一样吧其实alert也是window的一个属性也是window点出来的。
例子2
```
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
o.fn();
```
  这里的this指向的是对象o因为你调用这个fn是通过o.fn()执行的那自然指向就是对象o这里再次强调一点this的指向在函数创建的时候是决定不了的在调用的时候才能决定谁调用的就指向谁一定要搞清楚这个。
其实例子1和例子2说的并不够准确下面这个例子就可以推翻上面的理论。
如果要彻底的搞懂this必须看接下来的几个例子
例子3
```
var o = {
user:"追梦子",
fn:function(){
console.log(this.user); //追梦子
}
}
window.o.fn();
```
  这段代码和上面的那段代码几乎是一样的但是这里的this为什么不是指向window如果按照上面的理论最终this指向的是调用它的对象这里先说个而外话window是js中的全局对象我们创建的变量实际上是给window添加属性所以这里可以用window点o对象。
  这里先不解释为什么上面的那段代码this为什么没有指向window我们再来看一段代码。
```
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
o.b.fn();
```
  这里同样也是对象o点出来的但是同样this并没有执行它那你肯定会说我一开始说的那些不就都是错误的吗其实也不是只是一开始说的不准确接下来我将补充一句话我相信你就可以彻底的理解this的指向的问题。
  情况1如果一个函数中有this但是它没有被上一级的对象所调用那么this指向的就是window这里需要说明的是在js的严格版中this指向的不是window但是我们这里不探讨严格版的问题你想了解可以自行上网查找。
  情况2如果一个函数中有this这个函数有被上一级的对象所调用那么this指向的就是上一级的对象。
  情况3如果一个函数中有this这个函数中包含多个对象尽管这个函数是被最外层的对象所调用this指向的也只是它上一级的对象例子3可以证明如果不相信那么接下来我们继续看几个例子。
```
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
```
尽管对象b中没有属性a这个this指向的也是对象b因为this只会指向它的上一级对象不管这个对象中有没有this要的东西。
还有一种比较特殊的情况例子4
```
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
```
这里this指向的是window是不是有些蒙了其实是因为你没有理解一句话这句话同样至关重要。
  this永远指向的是最后调用它的对象也就是看它执行的时候是谁调用的例子4中虽然函数fn是被对象b所引用但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window这和例子3是不一样的例子3是直接执行了fn。
  this讲来讲去其实就是那么一回事只不过在不同的情况下指向的会有些不同上面的总结每个地方都有些小错误也不能说是错误而是在不同环境下情况就会有不同所以我也没有办法一次解释清楚只能你慢慢地的去体会。
```
构造函数版this
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子
```
  这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向将这个this指向对象a为什么我说a是对象因为用了new关键字就是创建一个对象实例理解这句话可以想想我们的例子3我们这里用变量a创建了一个Fn的实例相当于复制了一份Fn到对象a里面此时仅仅只是创建并没有执行而调用这个函数Fn的是对象a那么this指向的自然是对象a那么为什么对象a中会有user因为你已经复制了一份Fn函数到对象a中用了new关键字就等同于复制了一份。
  除了上面的这些以外我们还可以自行改变this的指向关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章详细的说明了我们如何手动更改this的指向。
更新一个小问题当this碰到return时
```
function fn()
{
this.user = '追梦子';
return {};
}
var a = new fn;
console.log(a.user); //undefined
```
再看一个
```
function fn()
{
this.user = '追梦子';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
```
再来
```
function fn()
{
this.user = '追梦子';
return 1;
}
var a = new fn;
console.log(a.user); //追梦子
```
```
function fn()
{
this.user = '追梦子';
return undefined;
}
var a = new fn;
console.log(a.user); //追梦子
```
什么意思呢?
  如果返回值是一个对象那么this指向的就是那个返回的对象如果返回值不是一个对象那么this还是指向函数的实例。
```
function fn()
{
this.user = '追梦子';
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "追梦子"}
```
  还有一点就是虽然null也是对象但是在这里this还是指向那个函数的实例因为null比较特殊。
```
function fn()
{
this.user = '追梦子';
return null;
}
var a = new fn;
console.log(a.user); //追梦子
```
知识点补充:
  1.在严格版中的默认的this不再是window而是undefined。
  2.new操作符会改变函数this的指向问题虽然我们上面讲解过了但是并没有深入的讨论这个问题网上也很少说所以在这里有必要说一下。
function fn(){
this.num = 1;
}
var a = new fn();
console.log(a.num); //1
  为什么this会指向a首先new关键字会创建一个空的对象然后会自动调用一个函数apply方法将this指向这个空对象这样的话函数内部的this就会被这个空的对象替代。
  注意: 当你new一个空对象的时候,js内部的实现并不一定是用的apply方法来改变this指向的,这里我只是打个比方而已.
  if (this === 动态的\可改变的) return true;
总结
* 在方法中this 表示该方法所属的对象。
* 如果单独使用this 表示全局对象。
* 在函数中this 表示全局对象。
* 在函数中在严格模式下this 是未定义的(undefined)。
* 在事件中this 表示接收事件的元素。
* 类似 call() 和 apply() 方法可以将 this 引用到任何对象。