JavaScript 中的 this 工作原理


Posted in Javascript onJune 20, 2018

一、问题的由来

学懂 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()就变成在全局环境执行。

总结

以上所述是小编给大家介绍的JavaScript 中的 this 工作原理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JQuery 构建客户/服务分离的链接模型中Table分页代码效率初探
Jan 22 Javascript
js arguments,jcallee caller用法总结
Nov 30 Javascript
JavaScript中的style.cssText使用教程
Nov 06 Javascript
js中遍历Map对象的方法
Jul 27 Javascript
微信小程序  网络请求API详解
Oct 25 Javascript
使用JavaScript为一张图片设置备选路径的方法
Jan 04 Javascript
node.js(express)中使用Jcrop进行图片剪切上传功能
Apr 21 Javascript
JavaScript实现为事件句柄绑定监听函数的方法分析
Nov 14 Javascript
Angular使用ControlValueAccessor创建自定义表单控件
Mar 08 Javascript
js中async函数结合promise的小案例浅析
Apr 14 Javascript
Vue 实现从文件中获取文本信息的方法详解
Oct 16 Javascript
详解vue 组件的实现原理
Nov 12 Javascript
如何用webpack4带你实现一个vue的打包的项目
Jun 20 #Javascript
JavaScript对象拷贝与Object.assign用法实例分析
Jun 20 #Javascript
vue打包的时候自动将px转成rem的操作方法
Jun 20 #Javascript
详解基于vue的服务端渲染框架NUXT
Jun 20 #Javascript
JS中call和apply函数用法实例分析
Jun 20 #Javascript
微信小程序模拟cookie的实现
Jun 20 #Javascript
JS伪继承prototype实现方法示例
Jun 20 #Javascript
You might like
php生成随机密码自定义函数代码(简单快速)
2014/05/10 PHP
Javascript 作用域使用说明
2009/08/13 Javascript
为调试JavaScript添加输出窗口的代码
2010/02/07 Javascript
使用jquery实现select添加实现后台权限添加的效果
2011/05/28 Javascript
Prototype源码浅析 Enumerable部分之each方法
2012/01/16 Javascript
设为首页加入收藏兼容360/火狐/谷歌/IE等主流浏览器的代码
2013/03/26 Javascript
JQuery设置获取下拉菜单某个选项的值(比较全)
2014/08/05 Javascript
js中style.display=""无效的解决方法
2014/10/30 Javascript
在浏览器中实现图片粘贴的jQuery插件-- pasteimg使用指南
2014/12/29 Javascript
在javascript中随机数 math random如何生成指定范围数值的随机数
2015/10/21 Javascript
jquery中checkbox使用方法简单实例演示
2015/11/24 Javascript
jQuery实现的超简单点赞效果实例分析
2015/12/31 Javascript
无缝滚动的简单实现代码(推荐)
2016/06/07 Javascript
原生JS实现获取及修改CSS样式的方法
2018/09/04 Javascript
vue项目使用axios发送请求让ajax请求头部携带cookie的方法
2018/09/26 Javascript
JS实现的进制转换,浮点数相加,数字判断操作示例
2019/11/09 Javascript
微信小程序实现自定义动画弹框/提示框的方法实例
2020/11/06 Javascript
[00:57]辉夜杯战队访谈宣传片—VG
2015/12/25 DOTA
Python中关于使用模块的基础知识
2015/05/24 Python
python删除过期log文件操作实例解析
2018/01/31 Python
Python使用win32 COM实现Excel的写入与保存功能示例
2018/05/03 Python
python爱心表白 每天都是浪漫七夕!
2018/08/18 Python
对python 自定义协议的方法详解
2019/02/13 Python
python sorted函数的小练习及解答
2019/09/18 Python
Python转换itertools.chain对象为数组的方法
2020/02/07 Python
安装python3.7编译器后如何正确安装opnecv的方法详解
2020/06/16 Python
Django基于Models定制Admin后台实现过程解析
2020/11/11 Python
小狗电器官方商城:中国高端吸尘器品牌
2017/03/29 全球购物
Groupon西班牙官方网站:在线优惠券和交易,节省高达70%
2021/03/13 全球购物
医学专业本科毕业生自我鉴定
2013/12/28 职场文书
优秀大学生求职自荐信范文
2014/04/19 职场文书
无毒社区工作方案
2014/05/23 职场文书
群众路线教育实践活动学习心得体会
2014/10/30 职场文书
退休职工欢送会致辞
2015/08/01 职场文书
浅析Python实现DFA算法
2021/06/26 Python
实现GO语言对数组切片去重
2022/04/20 Golang