探寻JavaScript中this指针指向

探寻JavaScript中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,那么为什么对象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就会被这个空的对象替代。

时间: 2016-04-21

对JavaScript中this指针的新理解分享

一直以来对this的理解只在可以用,会用,却没有去深究其本质.这次,借着<JavaScript The Good Parts>,作了一次深刻的理解.(所有调试都可以在控制台中看到,浏览器F12键) 下面我们一起来看看这个this吧. 在我们声明一个函数时,每个函数除了有定义时的parameters(形参),自身还会有额外的两个参数,一个是this,一个是arguments(实参).arguments就是函数实际接受到的参数,是一个类数组.arguments我只做个简略的介绍,重点我们放在thi

浅谈JavaScript中的this指针和引用知识

this是javascript的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. this指针在传统OO语言中,是在类中声明的,表示对象本身.在JavaScript中,this表示当前上下文,即调用者的引用 ********this永远指向的是(函数对象)的所有者 this和全局对象: var a = 1; function foo(){ var b = 2; console.log(this.a+b);//3 } foo();

老生常谈Javascript中的原型和this指针

1.Javascript中的原型: 原型prototype是Javascript中特有的一个概念.通过原型,Javascript可以实现继承机制. Javascript本身是基于原型的,每一个对象都有一个prototype属性.而Object对象的prototype属性为null. 下面来看一个使用原型实现继承的例子: 1.1使用原型实现继承: function Person(name){ this.name = name; this.getName = function(){ return t

Javascript this指针

前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript 可以通过一定的设计模式来实现面向对象的编程,其中this "指针"就是实现面向对象的一个很重要的特性.但是this也是Javascript中一个非常容易理解错,进而用错的特性.特别是对于接触静态语言比较久了的同志来说更是如此. 示例说明 我们先来看一个最简单的示例: <script type="text/javascript&

小议Javascript中的this指针

(1) 在全局执行环境中使用this,标识Global对象,在浏览器中就是window对象. (2)当在函数执行环境中使用this时,如果函数没有明显的作为非window对象的属性,而是只是定义了函数,不管这个函数是不是定义在另一个函数中,这个函数中的this仍然标识window对象.如果函数显示地作为一个非window对象的属性,那么函数中的this就代表这个对象. 复制代码 代码如下: var o=new Object; o.func=function() { alert((this===o

你必须知道的Javascript知识点之&quot;this指针&quot;的应用

很多人都知道this指针,这篇文章的主要目的是为了培训我们公司的新人.默认的this指针指向规则1this指针默认指向方法调用时为其指定的对象,如:obj.fun(),fun方法体中的this指针指向obj. 复制代码 代码如下: var user = { name: '段光伟' };user.getName = function(){ return this.name; };user.getName();  //返回'段光伟' 复制代码 代码如下: var user = { name: '段光

你必须知道的Javascript知识点之&quot;字面量和对应类型&quot;说明介绍

代码示例: 复制代码 代码如下: var date1 = new Date(2013,1,1); var date2 = new Date(2013,1,1); date1 == date2;  //执行结果为false date1 === date2;  //执行结果为false var num1 = new Number(10); var num2 = new Number(10); num1 == num2;  //执行结果为false num1 === num2;  //执行结果为fal

你必须知道的Javascript知识点之&quot;单线程事件驱动&quot;的使用

复制代码 代码如下: var intervalBody = function(){     console.log('interval'); } var startInterval = function(){     setInterval(intervalBody,1000); } var timeoutBody = function(){     console.log('timeout'); } var startTimeout = function(){     setTimeout(t

你必须知道的Javascript知识点之&quot;深入理解作用域链&quot;的介绍

示例代码: 复制代码 代码如下: var xxxVar1 = 1; var outer = function(){     var xxxVar2 = 2; var results = []; for(var i = 0; i< 3; i++)    {       var inner = function(){          var xxxVar3 = 3;          return xxxVar3 + xxxVar2 +xxxVar1 + i;       }       resu

jQuery 剧场版 你必须知道的javascript

一.摘要 本文是jQuery系列教程的剧场版, 即和jQuery这条主线无关, 主要介绍大家平时会忽略的一些javascript细节.  适合希望巩固javascript理论知识和基础知识的开发人员阅读. 二.前言 最近面试过一些人, 发现即使经验丰富的开发人员, 对于一些基础的理论和细节也常常会模糊. 写本文是因为就我自己而言第一次学习下面的内容时发现自己确实有所收获和感悟.  其实我们容易忽视的javascript的细节还有更多, 本文仅是冰山一角. 希望大家都能通过本文有所斩获. 三.Ja

你必须知道的JavaScript 中字符串连接的性能的一些问题

而JavaScript的核心是ECMAScript .与其他语言类似,ECMAScript 的字符串是不可变的,即它们的值不能改变. 请考虑下面的代码: 复制代码 代码如下: var str = "hello ";str += "world";实际上,这段代码在幕后执行的步骤如下: 1.创建存储 "hello " 的字符串.2.创建存储 "world" 的字符串.3.创建存储连接结果的字符串.4.把 str 的当前内容复制到结

你必须知道的JavaScript 变量命名规则详解

变量命名还应遵守以下某条著名的命名规则: 著名的变量命名规则Camel 标记法首字母是小写的,接下来的字母都以大写字符开头.例如: 复制代码 代码如下: var testValue = 0, secondValue = "hi";Pascal 标记法 首字母是大写的,接下来的字母都以大写字符开头.例如: 复制代码 代码如下: var TestValue = 0, SecondValue = "hi";匈牙利类型标记法 在以 Pascal 标记法命名的变量前附加一个小

前端开发必须知道的JS之闭包及应用

在前端开发必须知道的JS之原型和继承一文中说过下面写篇闭包,加之最近越来越发现需要加强我的闭包应用能力,所以此文不能再拖了.本文讲的是函数闭包,不涉及对象闭包(如用with实现).如果你觉得我说的有偏差,欢迎拍砖,欢迎指教.一. 闭包的理论 首先必须了解以下几个概念: 执行环境 每调用一个函数时(执行函数时),系统会为该函数创建一个封闭的局部的运行环境,即该函数的执行环境.函数总是在自己的执行环境中执行,如读写局部变量.函数参数.运行内部逻辑.创建执行环境的过程包含了创建函数的作用域,函数也是在

必须知道的C语言八大排序算法(收藏)

概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 1.插入排序-直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到

Android开发新手必须知道的10大严重错误

本文总结了Android开发新手必须知道的10大严重错误.分享给大家供大家参考,具体如下: 作为过去10年广泛涉猎各热门平台的经验丰富手机应用开发商,我们觉得Android平台对新手开发者来说是最通俗易懂的平台.平价的工具.友好的开发社区.及众所周知的编程语言(Java),可以说开发Android应用不是难事.但尽管如此,我们依然发现有些错误反复出现在刚涉足Android平台的新手开发者身上,下面是他们常犯的10大严重错误.希望新手朋友们能够借鉴,避免误区. 1. 未阅读Android文件 An