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日历控件实现方法分享
Mar 07 Javascript
AngularJS表单编辑提交功能实例
Feb 13 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
Apr 26 Javascript
深入理解JS DOM事件机制
Aug 06 Javascript
一句jQuery代码实现返回顶部效果(简单实用)
Dec 28 Javascript
webpack学习教程之publicPath路径问题详解
Jun 17 Javascript
react 父组件与子组件之间的值传递的方法
Sep 14 Javascript
Webpack devServer中的 proxy 实现跨域的解决
Jun 15 Javascript
Angular7创建项目、组件、服务以及服务的使用
Feb 19 Javascript
微信小程序实现pdf、word等格式文件上传的方法
Sep 10 Javascript
在vscode 中设置 vue模板内容的方法
Sep 02 Javascript
浅谈Vue static 静态资源路径 和 style问题
Nov 07 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 ctype函数中文翻译和示例
2014/03/21 PHP
利用php下载xls文件(自己动手写的)
2014/04/18 PHP
PHP错误WARNING: SESSION_START() [FUNCTION.SESSION-START]解决方法
2014/05/04 PHP
百度地图经纬度转换到腾讯地图/Google 对应的经纬度
2015/08/28 PHP
PHP快速排序quicksort实例详解
2016/09/28 PHP
PHP中的密码加密的解决方案总结
2016/10/26 PHP
PHP+RabbitMQ实现消息队列的完整代码
2019/03/20 PHP
PHP Swoole异步MySQL客户端实现方法示例
2019/10/24 PHP
什么是JavaScript
2009/08/13 Javascript
js 加载并解析XML字符串的代码
2009/12/13 Javascript
JS request函数 用来获取url参数
2010/05/17 Javascript
javascript setAttribute, getAttribute 在不同浏览器上的不同表现
2010/08/05 Javascript
javascript实现TreeView 无刷新展开的实例代码
2013/07/13 Javascript
Vue的Flux框架之Vuex状态管理器
2017/07/30 Javascript
knockoutjs模板实现树形结构列表
2017/07/31 Javascript
NodeJS模块与ES6模块系统语法及注意点详解
2019/01/04 NodeJs
RxJS在TypeScript中的简单使用详解
2020/04/13 Javascript
[16:21]教你分分钟做大人:圣堂刺客
2014/12/03 DOTA
Python里隐藏的“禅”
2014/06/16 Python
Django处理多用户类型的方法介绍
2019/05/18 Python
jenkins+python自动化测试持续集成教程
2020/05/12 Python
详解CSS3 rem(设置字体大小) 教程
2017/11/21 HTML / CSS
意大利运动服减价商店:ScontoSport
2020/03/10 全球购物
新闻专业应届生求职信
2013/10/31 职场文书
小组口号大全
2014/06/09 职场文书
风雨哈佛路观后感
2015/06/03 职场文书
2015国庆节宣传语
2015/07/14 职场文书
银行培训心得体会范文
2016/01/09 职场文书
《乌鸦喝水》教学反思
2016/02/19 职场文书
56句经典英文座右铭
2019/08/09 职场文书
2019年教师节:送给所有老师的祝福语
2019/09/05 职场文书
浅谈Python实现opencv之图片色素的数值运算和逻辑运算
2021/06/23 Python
Node与Python 双向通信的实现代码
2021/07/16 Javascript
SpringBoot2零基础到精通之数据与页面响应
2022/03/22 Java/Android
让JavaScript代码更加精简的方法技巧
2022/06/01 Javascript
Linux下搭建SFTP服务器的命令详解
2022/06/25 Servers