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 相关文章推荐
javascript面向对象之Javascript 继承
May 04 Javascript
iframe 父窗口和子窗口相互的调用方法集锦
Dec 15 Javascript
Javascript查询DBpedia小应用实例学习
Mar 07 Javascript
浏览器图片选择预览、旋转、批量上传的JS代码实现
Dec 04 Javascript
javascript实现一个数值加法函数
Jun 26 Javascript
jquery实现的淡入淡出下拉菜单效果
Aug 25 Javascript
ionic实现可滑动的tab选项卡切换效果
Apr 15 Javascript
Bootstrap文件上传组件之bootstrap fileinput
Nov 25 Javascript
JavaScript中数组的各种操作的总结(必看篇)
Feb 13 Javascript
基于Node.js的WebSocket通信实现
Mar 11 Javascript
JS/CSS实现字符串单词首字母大写功能
Sep 03 Javascript
VUE 项目在IE11白屏报错 SCRIPT1002: 语法错误的解决
Sep 27 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
Codeigniter整合Tank Auth权限类库详解
2014/06/12 PHP
php多重接口的实现方法
2015/06/20 PHP
jquery 操作单选框,复选框,下拉列表实现代码
2009/10/27 Javascript
Js-$.extend扩展方法使方法参数更灵活
2013/01/15 Javascript
JS中window.open全屏命令解析及使用示例
2013/12/11 Javascript
JavaScript实现文字跟随鼠标特效
2015/08/06 Javascript
JS根据浏览器窗口大小实时动态改变网页文字大小的方法
2016/02/25 Javascript
JavaScript位移运算符(无符号) >>> 三个大于号 的使用方法详解
2016/03/31 Javascript
Bootstrap弹出带合法性检查的登录框实例代码【推荐】
2016/06/23 Javascript
一种基于浏览器的自动小票机打印实现方案(js版)
2016/07/26 Javascript
jQuery复制节点用法示例(clone方法)
2016/09/08 Javascript
js获取指定字符前/后的字符串简单实例
2016/10/27 Javascript
谈谈因Vue.js引发关于getter和setter的思考
2016/12/02 Javascript
jQuery实现简单的抽奖游戏
2017/05/05 jQuery
浅谈Vuex@2.3.0 中的 state 支持函数申明
2017/11/22 Javascript
基于ionic实现下拉刷新功能
2018/05/10 Javascript
vue keep-alive请求数据的方法示例
2018/05/16 Javascript
10分钟彻底搞懂Http的强制缓存和协商缓存(小结)
2018/08/30 Javascript
微信小程序开发摇一摇功能
2019/11/22 Javascript
[02:44]完美大师赛主赛事淘汰赛第二日观众采访
2017/11/24 DOTA
Windows下安装python MySQLdb遇到的问题及解决方法
2017/03/16 Python
读取json格式为DataFrame(可转为.csv)的实例讲解
2018/06/05 Python
python使用matplotlib库生成随机漫步图
2018/08/27 Python
python实现集中式的病毒扫描功能详解
2019/07/09 Python
windows下python虚拟环境virtualenv安装和使用详解
2019/07/16 Python
Python随机函数库random的使用方法详解
2019/08/21 Python
解决python中的幂函数、指数函数问题
2019/11/25 Python
python中利用matplotlib读取灰度图的例子
2019/12/07 Python
tensorflow实现从.ckpt文件中读取任意变量
2020/05/26 Python
python实现ping命令小程序
2020/12/28 Python
IE兼容css3圆角的实现代码
2011/07/21 HTML / CSS
Ticketmaster德国票务网站:购买音乐会和体育等门票
2016/11/14 全球购物
Ray-Ban雷朋瑞典官方网站:全球领先的太阳眼镜品牌
2019/08/22 全球购物
2015高中教师个人工作总结
2015/07/21 职场文书
利用python调用摄像头的实例分析
2021/06/07 Python
Python中Selenium对Cookie的操作方法
2021/07/09 Python