阮一峰的JavaScript 的 this 原理
一、问题的由来
学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。
var obj = {foo: function () {} };var foo = obj.foo;// 写法一 obj.foo()// 写法二 foo()
上面代码中,虽然obj.foo
和foo
指向同一个函数,但是执行结果可能不一样。请看下面的例子。
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.foo
,foo()
就变成在全局环境执行?
本文就来解释 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()
就变成在全局环境执行。
总结:
this是用于在函数体内部,指代函数当前的运行环境。
阮一峰的JavaScript 的 this 原理相关推荐
- 阮一峰的Javascript模块化编程(三):require.js的用法
写的很好 链接地址 :http://www.ruanyifeng.com/blog/2012/11/require_js.html 转载于:https://www.cnblogs.com/susan- ...
- react 阮一峰_React 最简单的入门应用项目
学习一项工具,最快的方式就是边学便用.在学习 GUI 时我会边看API边写一个记事本,学习 web 框架时我会边学边写一个留言板. 学习和工作上一直是在写后端代码,有一点前端基础,但没有用过JS框架, ...
- 下面属于javascript内部对象的有_JavaScript quot;thisquot;原理-转载阮一峰
作者: 阮一峰 JavaScript 的 this 原理www.ruanyifeng.com 一.问题的由来 学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果. v ...
- Javascript 基础教程 阮一峰
Javascript 基础教程 阮一峰 2021-11-16 阮一峰推荐的入门教程,重在查漏补缺 https://wangdoc.com/javascript/index.html 第一章 入门 JS ...
- 读阮一峰对《javascript语言精粹》的笔记,我有疑问。
<javascript语言精粹>是一本很棒的书籍,其中作者在附录列出了12种他所认为的javascript语言中的糟粕. 我最近开始跟读前端前辈的博客,其中读到了阮一峰的<12种不宜 ...
- 学习阮一峰Javascript模块化编程,requireJS使用
使用背景NOW: 网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式. 项目需要一个团队分工协作.进度管理.单元 ...
- 我看朴灵评注阮一峰的《JavaScript 运行机制详解:再谈Event Loop》
阮一峰和朴灵对我来说都是大牛,他们俩的书我都买过,阮老师的译作<软件随想录>和朴灵的<深入浅出node.js>.这个事情已经过了4个月了,所以我拿来讲应该也没啥问题. 这件事情 ...
- Javascript 面向对象编程(一):封装 ——转自阮一峰博客
Javascript 面向对象编程(一):封装 作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的 ...
- 前端知乎:关于阮一峰博客《学习Javascript闭包》章节中最后两个思考题
阮一峰博客:<学习Javascript闭包>章节中最后有个思考题: 如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了. 代码片段一 var name = "The ...
最新文章
- 使用read write 读写socket
- springboot 中的 这种策略模式运用实战
- UA PHYS515A 电磁理论III 静磁学问题3 静磁学问题的边界条件与标量势方法的应用
- Java必会的基础知识(3)
- Drop Table对MySQL的性能影响分析
- Acrobat Reader DC 2020 for mac(最好用的免费PDF阅读器) 2020新增功能
- JDK/Java 14 可能带来什么新特性?
- Ubuntu Linux下使用锐捷认证的方法
- c语言log_C语言最大难点揭秘:编程的祸根!
- 关于ReactNative0.56版本Flatlist列表内容跳动的问题
- oracle12c dba或者sys身份的账户和密码,怎么一次性安装好oracle 12c依赖包
- javascript及css实现居中效果
- Web大学生网页作业成品~美食餐饮网站设计与实现(HTML+CSS+JavaScript)
- 2.7 矩阵分块及矩阵乘法的四种方式
- JAVA中成员变量和局部变量区别
- onkeyup+onafterpaste 只能输入数字和小数点--转载
- 数值分析常见算法C++实现
- android 第三方SDK接入一般流程
- Revit综合软件【加强过滤】的使用方法
- win10-SW2016工程图关联零件属性链接操作
热门文章
- python整数类型没有取值范围限制_详解Python中6种数据类型
- Python | Lambda函数与示例
- oracle创建用户名了,oracle创建用户名
- java中map的遍历方法_Java中Map的三种遍历方式
- 链接服务器访问接口返回了消息没有活动事务,因为链接服务器 SQLEHR 的 OLE DB 访问接口 SQLNCLI10 无法启动分布式事务。...
- Java SimpleTimeZone setStartRule()方法与示例
- Java SecurityManager checkAwtEventQueueAccess()方法与示例
- 终极解密输入网址按回车到底发生了什么?
- Spring中的重试功能!嗯,有点东西
- 一文学搞懂阿里开源的微服务新贵Nacos!