javascript中的this指向问题

最近一直在看慕课上看一些关于面向对象的开发教程,看的是一头雾水。对于面向对象开发,肯定少不了this。整套逻辑写下来,各种this指向,看得确实头皮发麻。而一些面试题里面,也常常会涉及到关于this指向的考题。所以,吃透javascript中this知识点是很重要的。

之前也在网上看了一些文章,个人觉得阮一峰老师的那篇文章很容易理解,还有一篇也写的不错,所以就打算融合两者中的一些点,整合记录一下。以后要是忘记了还可以拿出来复习一下。

关于this的知识点,就不写出来了。这里的这篇文章介绍的还不错,关于this的用法有哪些都涵盖了。大家可以看看是否可以理解。《JavaScript中知而不全的this》。

this指的是函数运行时所在的环境,或者普通函数中this指向全局对象window。或许看代码会更直观一些。

 

var obj = {
    foo:function(){
         console.log(this.bar)
  },
   bar:1
};
  var foo=obj.foo;
  var bar=2;

  obj.foo()   //1
  foo()       //2

对于 obj.foo()来说,它的运行所在的环境应该是在obj这个环境里。所以this.bar指向的就是当前环境里的bar的值;而foo()来说,这个函数运行时所在的环境是全局环境,所以调用的也是全局环境中this.bar的值,也就是2。

或许这种解释你并不能理解。为什么会这样呢?换句话说,函数的运行环境到底是怎么决定的?下面的部分我就摘抄下阮一峰老师的文章了。仔细看,然后在去脑子里构思一下运行原理,没准你就理解进去了。

JavaScript 语言之所以有this的设计,跟内存里面的数据结构有关系。

 

var obj = { foo:  5 };

上面的代码将一个对象赋值给变量obj。JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 },然后把这个对象的内存地址赋值给变量obj。

变量的储存

也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo属性,实际上是以下面的形式保存的。

对象的储存方式

对于属性值是一个数值或者是字符串大家很容易理解,但是假若属性名的属性值是一个函数呢,它的保存方式也就不同了。

 

var obj = { foo: function () {} };

这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。

函数的存储方式

而由于函数function(){}是一个单独的值,所以它可以在任何环境中被调用执行。比如:

var f = function () {};
var obj = { f: f };
f()         // 单独执行
obj.f()    // obj 环境执行

在javascript中,可以允许在函数体内调用当前运行环境中的变量,例如:

var f = function () {
  console.log(this.x);
}

这里的x就是当前环境中的变量,现在问题就来了,由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部指代函数当前的运行环境。而this.x指的就是当前函数的运行环境。

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

这里的f运行所在的环境指的是全局环境,this.x就是全局中的变量x。就是1。

全局变量中的x

 

而obj.f()的运行环境是在obj这个类里面。this.x指向的就是当前这个类里面的x。也就是2

类里面的运行环境

回到本文开头提出的问题,obj.foo()是通过obj找到foo,所以就是在obj环境执行。一旦var foo = obj.foo,变量foo就直接指向函数本身,所以foo()就变成在全局环境执行。这里大家可能有点绕,不妨在耐心看完下面这个面试题,或许你就能清晰一点了。

var x = 10;
function func() {
    alert(this.x)
}
var obj = {
    x: 20,
    fn: function() {
        alert(this.x)
    }
}
var fn = obj.fn
func()   // 10
obj.fn()  //20
fn()   // 10

这里的func()方法运行的环境在全局里,所以this.x指向的就是全局的x,也就是10;而obj.fn()运行的环境在obj这个方法里,this.x指向的就是当前运行环境的x,就是20;fn()是定义一个变量来保持obj.fn这个函数。所以this.x指向的就是当前这个变量fn的运行环境中的x,也就是10.

阮一峰那篇文章的地址:http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

陈健的个人博客,记录生活所见所感、学习笔记。专注于Web前端_SEO教程_读书心得。

1 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

返回主页看更多
狠狠的抽打博主 支付宝 扫一扫