作者: 阮一峰

JavaScript 的 this 原理​www.ruanyifeng.com

一、问题的由来

学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。

var obj = { foo: function () {} };
var foo = obj.foo; // 写法一 obj.foo()  // 写法二 foo()

上面代码中,虽然obj.foofoo指向同一个函数,但是执行结果可能不一样。请看下面的例子。

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

这种差异的原因,就在于函数体内部使用了this关键字。很多教科书会告诉你,this指的是函数运行时所在的环境。对于obj.foo()来说,foo运行在obj环境,所以this指向obj;对于foo()来说,foo运行在全局环境,所以this指向全局环境。所以,两者的运行结果不一样。

这种解释没错,但是教科书往往不告诉你,为什么会这样?也就是说,函数的运行环境到底是怎么决定的?举例来说,为什么obj.foo()就是在obj环境执行,而一旦var foo = obj.foofoo()就变成在全局环境执行?

本文就来解释 JavaScript 这样处理的原理。理解了这一点,你就会彻底理解this的作用。

二、内存的数据结构

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

var obj = { foo: 5 };

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

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

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

{foo: {[[value]]: 5[[writable]]: true[[enumerable]]: true[[configurable]]: true}
}

注意,foo属性的值保存在属性描述对象的value属性里面。

三、函数

这样的结构是很清晰的,问题在于属性的值可能是一个函数。

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

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

{   foo: { [[value]]: 函数的地址     ... } }

由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

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

四、环境变量

JavaScript 允许在函数体内部,引用当前环境的其他变量。

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

上面代码中,函数体里面使用了变量x。该变量由运行环境提供。

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

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

上面代码中,函数体里面的this.x就是指当前运行环境的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

obj环境执行,this.x指向obj.x

回到本文开头提出的问题,obj.foo()是通过obj找到foo,所以就是在obj环境执行。一旦var foo = obj.foo,变量foo就直接指向函数本身,所以foo()就变成在全局环境执行。

(完)

下面属于javascript内部对象的有_JavaScript quot;thisquot;原理-转载阮一峰相关推荐

  1. 下面属于javascript内部对象的有_JavaScript从零开始——面向对象编程(2)

    之前一章节提到了构造函数和类,其中有几个重点放在接下来的两部分提一下,主要是this关键字(ES 5就已经有了)的使用,对象的继承以及类(ES 6开始引入)的继承,这里先来看看this和对象的继承. ...

  2. 下面属于javascript内部对象的有_【JavaScript 教程】面向对象编程——this 关键字...

    作者 | 阮一峰 1.涵义 this关键字是一个非常重要的语法点.毫不夸张地说,不理解它的含义,大部分开发任务都无法完成. 前一章已经提到,this可以用在构造函数之中,表示实例对象.除此之外,thi ...

  3. 读阮一峰对《javascript语言精粹》的笔记,我有疑问。

    <javascript语言精粹>是一本很棒的书籍,其中作者在附录列出了12种他所认为的javascript语言中的糟粕. 我最近开始跟读前端前辈的博客,其中读到了阮一峰的<12种不宜 ...

  4. 学习阮一峰Javascript模块化编程,requireJS使用

    使用背景NOW: 网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式. 项目需要一个团队分工协作.进度管理.单元 ...

  5. 我看朴灵评注阮一峰的《JavaScript 运行机制详解:再谈Event Loop》

    阮一峰和朴灵对我来说都是大牛,他们俩的书我都买过,阮老师的译作<软件随想录>和朴灵的<深入浅出node.js>.这个事情已经过了4个月了,所以我拿来讲应该也没啥问题. 这件事情 ...

  6. Javascript 基础教程 阮一峰

    Javascript 基础教程 阮一峰 2021-11-16 阮一峰推荐的入门教程,重在查漏补缺 https://wangdoc.com/javascript/index.html 第一章 入门 JS ...

  7. Javascript 面向对象编程(一):封装 ——转自阮一峰博客

    Javascript 面向对象编程(一):封装 作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的 ...

  8. 前端知乎:关于阮一峰博客《学习Javascript闭包》章节中最后两个思考题

    阮一峰博客:<学习Javascript闭包>章节中最后有个思考题: 如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了. 代码片段一 var name = "The ...

  9. java和javascript有什么区别_javascript与java有什么区别?

    java和javascript之间有什么区别?本篇文章就给大家介绍java和javascript之间的区别,让大家了解java和javascript是什么?它们之间的差异有哪些.有一定的参考价值,有需 ...

最新文章

  1. COGS 2769. mk去撸串
  2. 基于STVD给stm8编程遇到的问题
  3. 【Python-pywt】 小波变化库—Pywavelets 学习笔记
  4. linux 找不到php命令,bash scp:未找到命令的解决方法
  5. 设计模式学习笔记——代理(Proxy)模式
  6. 异常的概念和Java异常体系结构
  7. Xcode8 报 ”xx“is missing from working copy 的问题解决方法
  8. Word 2013 使用技巧
  9. Python实现聚类 KMeans算法
  10. java仿QQ2.0版(一直忘了更)
  11. nginx 支持HTTPS fdfs
  12. 筑巢引凤 - 男人25后是蓝筹股
  13. cs架构(cs架构和bs架构的区别)
  14. java poi 替换word,POI替换Word中的mark标记(指定字符串)
  15. 基于闪存存储原理的U盘数据安全测试和U盘数据保护软件
  16. 【matlab教程】20、简单网格细分
  17. 纽约2050交通发展战略——高效移动性
  18. 智慧城市2020的三个焦点:网格化、健康码、老年人
  19. 自然语言理解应用API对比报告
  20. QTP10 R6025 Runtime Error解决方法

热门文章

  1. Linux内核 触摸板,Linux下关闭触摸板和触摸杆
  2. Python——元组Tuple
  3. 【VS】项目属性配置(中)
  4. Delphi Open Tools Api实例研究(一)
  5. C++ 读取CSV文件中的数据到Mat
  6. python常见的函数和类方法
  7. Java——Set 集合
  8. 企业面试之LeetCode刷题心得
  9. Laravel 调试利器 Laravel Debugbar 扩展包安装及使用教程
  10. github-ssh