首先必须要说的是,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,那么为什么对象Fn中会有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就会被这个空的对象替代。

this指针指向的彻底理解的更多相关文章

  1. JavaScript中this指针指向的彻底理解

    this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象 这一点与函数中自由变量Action-varibal不同 var ...

  2. 结合示例说明C++中const和指针结合时怎么理解

    在之前随笔<C++中const使用要点(一)>中简单叙述了const int*.int* const和const int* const的区别,记住三句话就能在实际运用时用对,但是看书时发现 ...

  3. 对C/C++指针问题的彻底理解(复习1)

    理解第一篇 上完大学不是我吹(仅仅说我认识的本学校本专业)估计很明白指针的人绝对不超过百分之50,学校low不low另说(因为问他们讲得断断续续的自己也说不明白,只知道那样可以用) 学链表树形结构.. ...

  4. C语言重点——指针篇(一文让你完全搞懂指针)| 从内存理解指针 | 指针完全解析

    有干货.更有故事,微信搜索[编程指北]关注这个不一样的程序员,等你来撩~ 注:这篇文章好好看完一定会让你掌握好指针的本质 C语言最核心的知识就是指针,所以,这一篇的文章主题是「指针与内存模型」 说到指 ...

  5. 指针的指针&指向指针数组的指针

    一.指针的指针    指针的指针看上去有些令人费解.它们的声明有两个星号.例如:        char ** cp;    如果有三个星号,那就是指针的指针的指针,四个星号就是指针的指针的指针的指针 ...

  6. OC3-父类指针指向子类对象

    // // Cat.h // OC3-父类指针指向子类对象 // // Created by qianfeng on 15/6/17. // Copyright (c) 2015年 qianfeng. ...

  7. 关于C++的子类指针指向父类

    基类指针引用派生类对象 用基类指针引用一个派生类对象,由于派生类对象也是基类的对象,所以这种引用是安全的; 但是只能引用基类成员. 若试图通过基类指针引用那些只在派生类中才有的成员,编译器会报告语法错 ...

  8. restrict关键字(暗示编译器,某个指针指向的空间,只能从该指针访问)

    我们希望某个对象(内存空间)不被修改的通常做法是什么?声明该空间的const类型,但是这样真的可以吗?是不是的,由于const空间对象的指针是可以付给一个非const值指针的.所以这仍然无法不让该空间 ...

  9. c++ 动态判断基类指针指向的子类类型(typeid)

    我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 本文提供了两种方法 ( ...

随机推荐

  1. C++中的多态

    多态性是面向对象程序设计的重要特征之一.多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态的实现方式包括以下3种:函数重载.运算符重载.虚函数. 1.运算符重载: #inc ...

  2. FPGA使用技巧

    1 IOB       为了保证FPGA输入输出接口的时序,一般会要求将输入管脚首先打一拍再使用,输出接口也要打一拍再输出FPGA.将信号打一拍的方法是将信号通过一次寄存器,而且必须在IOB里面的寄存 ...

  3. FPGA/CPLD设计思想与技巧

    本文讨论的四种常用FPGA/CPLD设计思想与技巧:乒乓操作.串并转换.流水线操作.数据接口同步化,都是FPGA/CPLD逻辑设计的内在规律的体现,合理地采用这些设计思想能在FPGA/CPLD设计工作 ...

  4. Java中提供的工具类

    System.arraycopy介绍 (1).System.arraycopy用于拷贝数组 arraycopy(Object src, int srcPos, Object dest, int des ...

  5. NaN属性,isNaN函数

    NaN:Not a Number,顾名思义,表示不是一个数字. 可以把 Number 对象设置为该值,来指示其不是数字值. 使用 isNaN() 全局函数来判断一个值是否是 NaN 值 详见 Java ...

  6. angular这个大梗的学习笔记

    angular定义一个模块(module)及控制器(controller)的局部声明方法: var app=angular.module("Myapp",[]); myapp.co ...

  7. $.each遍历json对象

    查看一个简单的jQuery的例子来遍历一个JavaScript数组对象. var json = [ {"id":"1","tagName": ...

  8. 使用 rem 实现 适配各种屏幕布局

    年数已久!!!技术更新太快,谨慎观看,不过作为了解一下思路还是可以的 在此呢,我只大略的谈一下在研究了px,em,rem,和手淘的做法之后,我所采用的做法及硬性规则: 我就不再过多的将上面三种单位的区 ...

  9. Docker无法启动 Could not find a free IP address range for interface 'docker0' 最方便的解决办法

    阿里云的CentOS 6.5上安装Docker会无法启动,如果直接运行docker -d会看到错误提示:Could not find a free IP address range for inter ...

  10. Sql Server数据库

    1.表分区 http://www.cnblogs.com/huangxincheng/p/3565755.html 2.MVP教程地址:http://www.cnblogs.com/lyhabc/p/ ...