javascript中this关键字详解

不管学习什么知识,习惯于把自己所学习的知识列成一个list,会有助于我们理清思路,是一个很好的学习方法。强烈推荐。

以下篇幅有点长,希望读者耐心阅读。

以下内容会分为如下部分:

1.涵义

  1.1:this涵义

  1.2:this指向的可变性

2.使用场合

  2.1:全局环境

  2.2:构造函数

  2.3:对象的方法

3.使用注意点

  3.1:避免多层嵌套this

  3.2:避免数组处理方法中的this

  3.3:避免回调函数中的this

1.涵义

1.1:this涵义

在我写的一篇关于 构造函数与new关键字 的关系的博文中谈及,new关键字总是会返回一个对象。这个对象可以是new调用构造函数时返回的空对象,也可以是在构造函数中使用return语句返回的复杂数据类型(包括对象,数组等)。

同样,与new关键字相同,this关键字总是返回一个对象。再说的详细一些,就是属性或方法“当前”所在的对象。

var Keith = {
  firstName: 'Chou',
  describe: function() {
   return this.firstName;
  }
 };
console.log(Keith.describe()); //'Chou'

上面代码中,this.firstName表示describe方法当前所在对象的firstName属性。也就是说,在全局作用域下调用describe方法时,describe方法所在的当前对象是Keith,所以就是调用Keith.firstName。

1.2:this指向的可变性

由于对象的属性可以赋给另外一个对象,所以属性所在的当前对象是可变的。也就是说,this的指向是可变的。

var Keith = {
  firstName: 'Chou',
  describe: function() {
   return this.firstName;
  }
 };
 var Rascal={
  firstName: 'King'
 }
 Rascal.describe=Keith.describe;
 console.log(Rascal.describe()); //'King'

上面代码中,Keith对象中的describe属性赋给Rascal,于是describe方法中当前所在的对象就是Rascal,所以this.firstName就指向Rascal。因为是传址传递,所以修改firstName会对原对象有影响。这个例子可能不便于理解,再看看下面这个例子。

function f(){
  return this.firstName;
 }
 var Keith = {
  firstName: 'Chou',
  describe:f
 };
 var Rascal={
  firstName: 'King',
  describe:f
 }
 console.log(Keith.describe()); //'Chou'
 console.log(Rascal.describe()); //'King'

上面代码中,把方法移到全局作用域下,函数f内部使用了this关键字。随着f所在的对象不同,this指向也就不同。

在全局作用域下this关键字会指向顶层对象(也就是window对象)。

var name='keith';
 function person(){
  var name='rascal';
  return this.name;
 }
console.log(person()); //'keith'

上面代码中,返回的是keith而不是rascal。原因在于this指向的是全局作用域。在全局作用域中定义一个函数,默认是指向window对象,而不是函数本身。但是,如果在函数内部不使用var来声明一个局部变量,那结果也会不同。

var name='keith';
 function person(){
  name='rascal';
  return this.name;
 }
console.log(person()); //'rascal'

上面代码中,在函数内部没有使用var来声明一个局部变量,那么此时函数内部的name属性不是局部变量,而是全局变量。所以会覆盖掉前面的name属性。如果对于局部变量和全局变量不了解,可以访问 这篇文章 。 

只要函数被赋给另外一个变量,this的指向会发生改变。

var Keith={
  name:'keith',
  describe:function(){
   return this.name;
  }
 }
var name='rascal';
var f=Keith.describe;
console.log(f()) //'rascal'

上面代码中,返回的是rascal,而不是keith。因为Keith.describe被赋值给了f变量,而全局作用域下有一个name变量,所以Keith内部的函数的this指向就会指向f运行时所在的对象(顶层对象,也就是window对象)

总结一下:

1.javascript语言中,一切皆为对象(除了 undefined 和 null 之外),运行环境也是对象,所以函数都是在某个对象之中运行,this就是这个对象(环境)。

2.this的指向是动态的。如果函数在全局作用域中,那么this就会指向全局环境;如果函数位于某个对象中,那么this就会指向该对象。

2.使用场合

this的使用场合可以分为以下几个场合。

2.1:全局环境(全局作用域)

在全局作用域中使用this对象,它指向的就是顶层对象,也就是window对象。

 function keith() {
  return (this === window)
  }
console.log(keith()) //true

上面代码中,不管是不是在函数内部,只要在全局作用域下运行,this就是指向顶层对象window。

2.2:构造函数

构造函数中的this,指向的是将要创建的对象实例。

function Keith() {
  this.sex = 'boy';
 }
 var person = new Keith();
 console.log(person.sex); //'boy'

上面代码中,在全局作用域下定义了Keith构造函数,然后调用构造函数并赋值给person对象实例。

构造函数创建的三个基本要求:函数名首字母大写;构造函数内部使用this关键字来指向即将生成的对象实例;使用new关键字来调用构造函数并返回对象实例。

如果想更进一步深入了解构造函数与new关键字的关系,请移步至 这篇文章 。

2.3:对象的方法

当A对象的方法被赋予B对象,该方法中的this就从指向A对象变成指向B对象。所以要特别小心,将某个对象的方法赋值个另外一个对象时,会改变this的指向。

var keith = {
  sex: 'boy',
  foo: function() {
   return this.sex;
  }
 };
 var rascal = {
  sex: 'girl'
 };
 rascal.foo = keith.foo;
 console.log(keith.foo()); //'boy'
 console.log(rascal.foo()); //'girl'

上面代码中,把keith的foo函数赋值给了rascal,那么this的指向就从keith变成了rascal。

如果某个方法位于多层对象的内部,这时为了简化书写,把该方法赋值给一个变量,往往会得到不一样的结果。

var a = {
  b: {
   p: 'keith',
   c: function() {
    return this.p;
   }
  }
 };
 var person = a.b.c;
 console.log(person()); //undefined

上面代码中,c是两层对象里面的一个方法。为求简便,将其赋值给全局变量person,结果调用时,this指向了顶层对象window。而在window中变量p默认值为undefined。

要解决这个问题,可以只将c所在的对象赋值给person变量,或者是直接调用。

var person = a.b;
console.log(person.c()); //'keith'
console.log(a.b.c()); //'keith'

3.使用注意点

3.1:避免多层嵌套this

当在闭包中使用多层this,则this都会指向window。

function keith() {
  console.log(this);
  return function() {
   return this;
  }
 }
 keith(); //window
 keith()(); //window

上面代码中,在一个函数中返回另外一个匿名函数是闭包的特点之一,可以看出,当在闭包中使用this对象都会指向全局作用域中的window对象。

如果在函数外包含一个对象,则内部this指向全局作用域,而外部this对象指向当前作用域。

var o = {
  f1: function() {
   console.log(this);
   (function() {
    console.log(this)
   })();
  }
 };
 o.f1(); //Object , Window

上面代码包含两层this,结果运行后,第一层指向当前对象,第二层指向全局对象。

实际执行的是如下代码。

function keith() {
  console.log(this);
 }
 var o = {
  f1: function() {
   console.log(this);
   var f2 = keith();
  }
 };
 o.f1(); //Object , Window

要实现多层this嵌套,有两种解决方法:

一是在第二层中改用一个指向外层this的变量。

var o = {
  f1: function() {
   console.log(this);
   var that = this;
   (function() {
    console.log(that);
   })();
  }
 };
 o.f1(); //Object , Object

上面代码中,定义了局部变量that,固定指向了外层的this,然后在内层中使用that,就不会发生this指向的改变。但是如果函数外部内有嵌套一个对象,this还是会指向全局。

二是Javascript中的严格模式。在严格模式下,如果内部函数的this指向了window对象,就会报错。

var a = {
  count: 0,
  fun: function() {
   'use strict';
   return this.count++;
  }
 }
 var f = a.fun;
 console.log(f()) //'TypeError: this is undefined'

上面代码中,fun方法使用严格模式声明。把a对象中的fun方法赋值给全局变量f,那么this此时指向window对象,在严格模式下,就会报错。如果函数外部没有嵌套一个对象,那么不会报错,而是会返回undefined。

3.2:避免数组处理方法中的this

数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this

var keith = {
  a: 'Hello',
  b: ['b1', 'b2'],
  c: function() {
   this.b.forEach(function(item) {
    console.log(this.a + ' ' + item);
   })
  }
 };
 keith.c();
 //undefined b1
 //undefined b2

上面代码中,forEach方法的回调函数中的this,其实指向的是window对象,因此取不到keith.a的值,同上也属于避免多层嵌套this。也就是说,内层的this不指向外部函数,而是指向顶层对象。

要解决这个方法,可以使用that变量来代替回调函数中的this。

var keith = {
  a: 'Hello',
  b: ['b1', 'b2'],
  c: function() {
   var that = this;
   this.b.forEach(function(item) {
    console.log(that.a + ' ' + item);
   })
  }
 };
 keith.c();
 //Hello b1
 //Hello b2

另外一种方法,就是让this做为forEach方法的第二个参数,来固定它的运行环境。

var keith = {
  a: 'Hello',
  b: ['b1', 'b2'],
  c: function() {
   this.b.forEach(function(item) {
    console.log(this.a + ' ' + item);
   }, this)
  }
 };
 keith.c();
 //Hello b1
 //Hello b2

3.3:避免回调函数中的this

回调函数中的this往往会改变指向。

var o = {
  f: function() {
   console.log(this === o);
  }
 };
 o.f(); // true;

上面代码中,调用o对象的f方法,返回true。

但是,如果将f方法指定给某个按钮的click事件,this的指向就变了。

$('button').on('click',o.f);

上面代码中,使用了jquery方法来获取button元素,并绑定click事件。点击按钮后控制台会显示false。原因是此时this不再指向o对象了,而是指向按钮的DOM对象,因为f方法是在按钮对象的环境中被调用的。

总结一下:

a:如果想要多层嵌套this关键字,最常用的解决方法就是使用that变量,固定指向外层的this,然后在内层中使用that变量。就不会发生内层this指向全局的问题。

b:如果在回调函数中使用this关键字,注意this的指向问题。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • js中的this关键字详解

    this是Javascript语言的一个关键字. 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.比如, 复制代码 代码如下: function test(){ this.x = 1; } 随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this指的是,调用函数的那个对象. 下面分四种情况,详细讨论this的用法. 情况一:纯粹的函数调用 这是函数的最通常用法,属于全局性调用,因此this就代表全局对象Global. 请看下面这段代码,它的运行结果是1.

  • 关于js里的this关键字的理解

    this关键字在c++,java中都提供了这个关键字,在刚开始学习时觉得有难度,但是只要理解了,用起来就方便多了,下面通过本篇文章给大家详解js里this关键字的理解. 关于this,是很多前端面试必考的题目,有时候在网上看到这些题目,自己试了一下,额,还真的错了!在实际开发中,也会遇到 this 的问题(虽然一些类库会帮我们处理),例如在使用一些框架的时候,例如:knockout,有时候不明白为什么不直接使用this,而要把 this 作为参数传入. 接下来你谈谈我对它的理解,也作为一个笔记,

  • 图解JavaScript中的this关键字

    JavaScript 是一种脚本语言,支持函数式编程.闭包.基于原型的继承等高级功能.JavaScript一开始看起来感觉会很容易入门,但是随着使用的深入,你会发现JavaScript其实很难掌握,有些基本概念让人匪夷所思.其中JavaScript 中的 this 关键字,就是一个比较容易混乱的概念,在不同的场景下,this会化身不同的对象.有一种观点认为,只有正确掌握了 JavaScript 中的 this 关键字,才算是迈入了 JavaScript 这门语言的门槛.在主流的面向对象的语言中(

  • Javascript中this关键字的一些小知识

    Javascript应该是现在最流行的跨平台语言之一,一直在玩前端的一些有意思的东西,发现竟然没有掌握好这门语言.有点舍本逐末,于是想趁着现在这有空的时候好好补充一点遗漏的东西. this的隐性绑定 一开始这是我很迷惑的东西,刚开始看到的时候,不理解.而后,在相似的情况下,又能用类似的方法解决同样的问题.便试着理清这其中的知识,方便于查找. 这是一个Javascript语言上设计的错误,但是似乎这个错误是不可避免的,函数是对象,数组是对象等等.引用<Javascript: The Good Pa

  • JavaScript中的this关键字使用方法总结

    在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代. 它可以是全局对象.当前对象或者任意对象,这完全取决于函数的调用方式.JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用,和使用 apply 或 call 调用. 1.作为对象方法调用 在 JavaScript 中,函数也是对象,因此函数可以作为一个对象的属性,此时该函数被称为该对象的方法,在使用这种调用方式时,this 被

  • 跟我学习javascript的this关键字

    本文仅就这一问题展开讨论,阅罢本文,读者若能正确回答 JavaScript 中的 What 's this 问题,作为作者,我就会觉得花费这么多功夫,撰写这样一篇文章是值得的. 我们要记住一句话:this永远指向函数运行时所在的对象!而不是函数被创建时所在的对象.也即:谁调用,指向谁.切记- 本文将分三种情况来分析this对象到底身处何方. 1.普通函数中的this 无论this身处何处,第一要务就是要找到函数运行时的位置. var name="全局"; function getNam

  • Javascript之this关键字深入解析

    首先,我先抛出一个定论:"在Javascript中,This关键字永远都指向函数(方法)的所有者". 函数 复制代码 代码如下: function introduce() {     alert("Hello, I am Laruence\r\n");} 对于这个函数,this关键字指向谁呢? 如我之前的文章所述(Javascript作用域),定义在全局的函数,函数的所有者就是当前页面,也就是window对象. 这也就是为什么,我把函数用引号引起来,因为定义在全局的

  • 精通JavaScript的this关键字

    JS中的this关键字让很多新老JS开发人员都感到困惑.这篇文章将对this关键字进行完整地阐述.读完本文以后,您的困惑将全部消除.您将学会如何在各种不同的情形正确运用this. 我们和在英语.法语这样的自然语言中使用名词一样地使用this.比如,"John飞快地跑着,因为他想追上火车".请注意这句话中的代指John的代名词"他".我们原本也可以这样表达,"John飞快地跑着,因为John想追上火车".按照正常的语言习惯,我们并不按第二种方式表达

  • JavaScript中的this关键字介绍与使用实例

    当创建一个类的时候,如果希望下面new出来的每个类都拥有一些通用的变量或者其他的函数,这个this关键字这是最好的方式. 当然,既然是面向对象的语言,必然存在访问权限的问题,这里也和this关键字息息相关.下面我们来演示一个例子来说明一下这个类的访问权限的问题. 复制代码 代码如下: //Person类     function Person(){     var name="abc";//var声明的都是类内部的私有变量,外部无法访问      var age = 20; this.

  • JavaScript中的this关键字使用详解

    和其它许多面向对象的语言一样,JavaScript 中也有 this 关键字,this 在函数中用来指向调用此方法的对象.实际编程中要判断 this 到底指向谁,一般可遵循以下原则: 如果该函数被 Function.call 或者 Function.apply 调用,那么 this 指向 call/apply 的第一个参数,如果参数是 null 或者 undefined,this 则指向全局对象(在浏览器中的话,全局对象就是 window 对象). 如果该函数被 Function.bind 调用

  • 深入理解Javascript中的this关键字

    自从接触javascript以来,对this参数的理解一直是模棱两可.虽有过深入去理解,但却也总感觉是那种浮于表面,没有完全理清头绪. 但对于this参数,确实会让人产生很多误解.那么this参数到底是何方神圣? 理解this this是一个与执行上下文(execution context,也就是作用域)相关的特殊对象.因此,它可以叫作上下文对象(也就是用来指明执行上下文是在哪个上下 文中被触发的对象). 任何对象都可以做为上下文中的this的值.在一些对ECMAScript执行上下文和部分th

  • javascript与jquery中的this关键字用法实例分析

    本文实例分析了javascript与jquery中的this关键字用法.分享给大家供大家参考,具体如下: this 表示当前的对象,这个当前对象可以是表单,<p>等任何元素 1.javascript中this的用法: JS部分: <script type="text/javascript"> function chimg(obj){ obj.src="./images/2.jpg"; } </script> HTML部分: 复制代

  • 关于javascript中this关键字(翻译+自我理解)

    下文有大概70%的内容出自http://www.quirksmode.org/js/this.html,另外30%是我自己对它的理解和感想.希望能对有需要的人一点帮助... 首先,先看一个很典型的关于this关键字题目: 复制代码 代码如下: var name = 'hong' var obj = { name: 'ru', getName: function(){ return function(){ return this.name; }; } } alert(obj.getName()()

随机推荐