图解JavaScript中的this关键字


Posted in Javascript onMay 28, 2020

JavaScript 是一种脚本语言,支持函数式编程、闭包、基于原型的继承等高级功能。JavaScript一开始看起来感觉会很容易入门,但是随着使用的深入,你会发现JavaScript其实很难掌握,有些基本概念让人匪夷所思。其中JavaScript 中的 this 关键字,就是一个比较容易混乱的概念,在不同的场景下,this会化身不同的对象。有一种观点认为,只有正确掌握了 JavaScript 中的 this 关键字,才算是迈入了 JavaScript 这门语言的门槛。在主流的面向对象的语言中(例如Java,C#等),this 含义是明确且具体的,即指向当前对象。一般在编译期绑定。而 JavaScript 中this 在运行期进行绑定的,这是JavaScript 中this 关键字具备多重含义的本质原因。

JavaScript由于其在运行期进行绑定的特性,JavaScript 中的 this 可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用,和使用 apply 或 call 调用。常言道,字不如表,表不如图。为了让人更好的理解JavaScript this 到底指向什么?下面用一张图来进行解释:

 图解JavaScript中的this关键字

上图我称之为"JavaScript this决策树"(非严格模式下)。下面通过例子来说明这个图如何来帮助我们对this进行判断:

var point = { 
 x : 0, 
 y : 0, 
 moveTo : function(x, y) { 
 this.x = this.x + x; 
 this.y = this.y + y; 
 } 
 };
 //决策树解释:point.moveTo(1,1)函数不是new进行调用,进入否决策,
 //是用dot(.)进行调用,则指向.moveTo之前的调用对象,即point
 point.moveTo(1,1); //this 绑定到当前对象,即point对象

point.moveTo()函数在 "JavaScript this决策树"中进行判定的过程是这样的:

1)point.moveTo函数调用是用new进行调用的么?这个明显不是,进入“否”分支,即函数是否用dot(.)进行调用?;

2)point.moveTo函数是用dot(.)进行调用的,即进入“是”分支,即这里的this指向point.moveTo中.之前的对象point;

图解point.moveTo函数的this指向什么的解析图如下图所示:

图解JavaScript中的this关键字 

再举例,看下面的代码:

function func(x) { 
 this.x = x; 
 } 
func(5); //this是全局对象window,x为全局变量
 //决策树解析:func()函数是用new进行调用的么?为否,进入func()函数是用dot进行调用的么?为否,则 this指向全局对象window
 x;//x => 5

func()函数在 "JavaScript this决策树"中进行判定的过程是这样的:

1)func(5)函数调用是用new进行调用的么?这个明显不是,进入“否”分支,即函数是否用dot(.)进行调用?;

2)func(5)函数不是用dot(.)进行调用的,即进入“否”分支,即这里的this指向全局变量window,那么this.x实际上就是window.x;

图解func函数的this指向什么的解析图如下图所示:

 图解JavaScript中的this关键字

针对作为函数直接调用的方式,下面看一个复杂的例子:

var point = { 
 x : 0, 
 y : 0, 
 moveTo : function(x, y) { 
 // 内部函数
 var moveX = function(x) { 
 this.x = x;//this 指向什么?window
 }; 
 // 内部函数
 var moveY = function(y) { 
 this.y = y;//this 指向什么?window
 }; 
 moveX(x); 
 moveY(y); 
 } 
 }; 
 point.moveTo(1,1); 
 point.x; //=>0 
 point.y; //=>0 
 x; //=>1 
 y; //=>1

point.moveTo(1,1)函数实际内部调用的是moveX()和moveY()函数, moveX()函数内部的this在 "JavaScript this决策树"中进行判定的过程是这样的:

1)moveX(1)函数调用是用new进行调用的么?这个明显不是,进入“否”分支,即函数是否用dot(.)进行调用?;

2)moveX(1)函数不是用dot(.)进行调用的,即进入“否”分支,即这里的this指向全局变量window,那么this.x实际上就是window.x;

下面看一下作为构造函数调用的例子:

function Point(x,y){ 
 this.x = x; // this ?
 this.y = y; // this ?
 }
 var np=new Point(1,1);
 np.x;//1
 var p=Point(2,2);
 p.x;//error, p是一个空对象undefined
 window.x;//2

Point(1,1)函数在var np=new Point(1,1)中的this在 "JavaScript this决策树"中进行判定的过程是这样的:

1)var np=new Point(1,1)调用是用new进行调用的么?这个明显是,进入“是”分支,即this指向np;

2)那么this.x=1,即np.x=1;

Point(2,2)函数在var p= Point(2,2)中的this在 "JavaScript this决策树"中进行判定的过程是这样的:

1)var p= Point(2,2)调用是用new进行调用的么?这个明显不是,进入“否”分支,即函数是否用dot(.)进行调用?;

2)Point(2,2)函数不是用dot(.)进行调用的?判定为否,即进入“否”分支,即这里的this指向全局变量window,那么this.x实际上就是window.x;

3)this.x=2即window.x=2.

最后看一下函数用call 和apply进行调用的例子:

function Point(x, y){ 
 this.x = x; 
 this.y = y; 
 this.moveTo = function(x, y){ 
 this.x = x; 
  this.y = y; 
 } 
 } 
 
 var p1 = new Point(0, 0); 
 var p2 = {x: 0, y: 0}; 
 p1.moveTo.apply(p2, [10, 10]);//apply实际上为p2.moveTo(10,10)
 p2.x//10

p1.moveTo.apply(p2,[10,10])函数在 "JavaScript this决策树"中进行判定的过程是这样的:

我们知道,apply 和 call 这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。p1.moveTo.apply(p2,[10,10])实际上是p2.moveTo(10,10)。那么p2.moveTo(10,10)可解释为:

1)p2.moveTo(10,10)函数调用是用new进行调用的么?这个明显不是,进入“否”分支,即函数是否用dot(.)进行调用?;

2)p2.moveTo(10,10)函数是用dot(.)进行调用的,即进入“是”分支,即这里的this指向p2.moveTo(10,10)中.之前的对象p2,所以p2.x=10;

关于JavaScript函数执行环境的过程,IBM developerworks文档库中的一段描述感觉很不错,摘抄如下:

"JavaScript 中的函数既可以被当作普通函数执行,也可以作为对象的方法执行,这是导致 this 含义如此丰富的主要原因。一个函数被执行时,会创建一个执行环境(ExecutionContext),函数的所有的行为均发生在此执行环境中,构建该执行环境时,JavaScript 首先会创建 arguments变量,其中包含调用函数时传入的参数。接下来创建作用域链。然后初始化变量,首先初始化函数的形参表,值为 arguments变量中对应的值,如果 arguments变量中没有对应值,则该形参初始化为 undefined。如果该函数中含有内部函数,则初始化这些内部函数。如果没有,继续初始化该函数内定义的局部变量,需要注意的是此时这些变量初始化为 undefined,其赋值操作在执行环境(ExecutionContext)创建成功后,函数执行时才会执行,这点对于我们理解 JavaScript 中的变量作用域非常重要,鉴于篇幅,我们先不在这里讨论这个话题。最后为 this变量赋值,如前所述,会根据函数调用方式的不同,赋给 this全局对象,当前对象等。至此函数的执行环境(ExecutionContext)创建成功,函数开始逐行执行,所需变量均从之前构建好的执行环境(ExecutionContext)中读取。”

理解这段话对于理解Javascript函数将大有好处。 

以上就是关于JavaScript中的this关键字的详细介绍,一般图片比文字更容易让大家理解,希望这篇文章对大家的学习有所帮助。

Javascript 相关文章推荐
基于jquery的一个浮动框(扩展性比较好 )
Aug 27 Javascript
解决Extjs上传图片无法预览的解决方法
Mar 22 Javascript
jquery解决图片路径不存在执行替换路径
Feb 06 Javascript
如何用js控制frame的隐藏或显示的解决办法
Mar 20 Javascript
javascript框架设计之种子模块
Jun 23 Javascript
js实现prototype扩展的方法(字符串,日期,数组扩展)
Jan 14 Javascript
jQuery Easyui datagrid行内实现【添加】、【编辑】、【上移】、【下移】
Dec 19 Javascript
Json按某个键的值进行排序
Dec 22 Javascript
webpack写jquery插件的环境配置
Dec 21 jQuery
用 Vue.js 递归组件实现可折叠的树形菜单(demo)
Dec 25 Javascript
微信小程序全局变量改变监听的实现方法
Jul 15 Javascript
解决Vue router-link绑定事件不生效的问题
Jul 22 Javascript
jquery validate demo 基础
Oct 29 #Javascript
jQuery实现彩带延伸效果的网页加载条loading动画
Oct 29 #Javascript
jquery实现的伪分页效果代码
Oct 29 #Javascript
牛叉的Jquery——Jquery与DOM对象的互相转换及DOM的三种操作
Oct 29 #Javascript
jquery实现模拟百分比进度条渐变效果代码
Oct 29 #Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
Oct 29 #Javascript
如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)
Oct 29 #Javascript
You might like
php mssql 数据库分页SQL语句
2008/12/16 PHP
php多文件上传实现代码
2014/02/20 PHP
php打印一个边长为N的实心和空心菱型的方法
2015/03/02 PHP
再推荐十款免费的php开发工具
2015/11/09 PHP
超级简单的图片防盗(HTML),好用
2007/04/08 Javascript
syntaxhighlighter 使用方法
2007/07/02 Javascript
javascript闭包的理解
2015/04/01 Javascript
JavaScript实现DIV层拖动及动态增加新层的方法
2015/05/12 Javascript
如何使用Bootstrap的modal组件自定义alert,confirm和modal对话框
2016/03/01 Javascript
用JS生成UUID的方法实例
2016/03/30 Javascript
一次$.getJSON不执行的简单记录
2016/07/19 Javascript
jQuery实现简单的手风琴效果
2020/04/17 jQuery
利用jQuery+localStorage实现一个简易的计时器示例代码
2017/12/25 jQuery
jQuery简单判断值是否存在于数组中的方法示例
2018/04/17 jQuery
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
JS实现深度优先搜索求解两点间最短路径
2019/01/17 Javascript
实例讲解JavaScript预编译流程
2019/01/24 Javascript
Vue退出登录时清空缓存的实现
2019/11/12 Javascript
详解js创建对象的几种方式和对象方法
2021/03/01 Javascript
[00:33]2018DOTA2亚洲邀请赛TNC出场
2018/04/04 DOTA
Python的函数的一些高阶特性
2015/04/27 Python
在Python中使用base64模块处理字符编码的教程
2015/04/28 Python
Python 字符串与二进制串的相互转换示例
2018/07/23 Python
python进程和线程用法知识点总结
2019/05/28 Python
python 如何设置守护进程
2020/10/29 Python
利用HTML5+css3+jquery+weui实现仿微信聊天界面功能
2018/01/08 HTML / CSS
HTML5中实现拖放效果无须借助javascript
2012/12/26 HTML / CSS
伦敦哈德森鞋:Hudson Shoes
2018/02/06 全球购物
LVMH旗下最大的奢侈品网站平台:24S
2020/05/24 全球购物
采购员岗位职责
2013/11/15 职场文书
新生入学欢迎词
2015/01/26 职场文书
自我检讨书怎么写
2015/05/07 职场文书
联谊会开场白
2015/06/01 职场文书
职场领导同事生日简短祝福语
2019/08/06 职场文书
vue如何实现关闭对话框后刷新列表
2022/04/08 Vue.js
Go gorilla/sessions库安装使用
2022/08/14 Golang