阮一峰的JavaScript 的 this 原理

一、问题的由来

学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。


var obj = {foo: function () {}
};var foo = obj.foo;// 写法一
obj.foo()// 写法二
foo()

上面代码中,虽然obj.foofoo指向同一个函数,但是执行结果可能不一样。请看下面的例子。


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.foofoo()就变成在全局环境执行?

本文就来解释 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是用于在函数体内部,指代函数当前的运行环境。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win7系统5分钟自动注销的解决方法

我们在电脑使用的过程中,有时候会遇到过5分钟就自动注销的情况。一般来说都是因为电脑中了病毒,启动程序遭到了恶意修改,或者系统启动文件因为某些操作删除或损坏了,我们可以用下面的方法尝试解决。 win7系统5分钟自动注销的解决…

计算机基础:IP地址,子网掩码,默认网关,DNS服务器

如图各项IP地址、子网掩码、默认网关、DNS服务器分别都代表什么意思 (一)IP地址 IP是32位二进制数据,通常以十进制表示,并以“.”分隔。IP地址是一种逻辑地地址,用来标识网络中一个个主机,IP有唯一性&#…

win7系统如何更改密码策略

win7的密码策略关系着我们的密码格式、密码需要的字符等,如果我们设置的密码策略太过复杂,可能会让我们在使用密码时非常麻烦,但是也会让我们的密码更难被入侵,那么win7系统如何更改密码策略呢?就此问题,下面一起来看…

js基础中Null、undefined、NaN、false、0、{}的理解及使用

数据类型: 值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。 引用数据类型:对象(Object)、数组(Array)、函数…

解决vue的{__ob__: observer}取值问题

vue编码中经常出现获取到的数据是:{__ob__: Observer} 格式的,详细如下 可能导致后续数据操作错误,如何获取其中的数值呢 解决方法如下: 将返回的数据data先转换为JSON字符串形式,然后再从字符串形式转换成JSON格式JS…

Js数组去重的多种方法

方法一 原理&#xff1a;利用双层循环将相邻元素 arr[i]和arr[i1] 进行比较&#xff0c;相等则数组删除arr[i1] 下标元素 var arr [1,23,1,1,1,3,23,5,6,7,9,9,8,5]; function removeDuplicatedItem(arr) {for(var i 0; i < arr.length-1; i){for(var j i1; j < ar…

qq浏览器网站禁止访问怎么办 qq浏览器网站禁止访问如何解决

打开手机的QQ浏览器说访问网页被禁止&#xff0c;是设置错误造成的&#xff0c;解决方法如下&#xff1a; 1、首先在手机屏幕上左右滑动&#xff0c;找到安装好的QQ浏览器的图标。 <a styleqq浏览器网站禁止访问怎么办 qq浏览器网站禁止访问如何解决"> 2、接下来…

计算机基础:程序、进程、线程

进程、线程、多线程相关总结 一、说说概念 1、进程&#xff08;process&#xff09; 狭义定义&#xff1a;进程就是一段程序的执行过程。 广义定义&#xff1a;进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元&#xff0…

Win7系统局域网抢网速的方法

Win7旗舰版局域网怎么抢占网速?最近有很多使用Win7系统的用户问小编&#xff0c;反应自己在局域网下玩游戏的时候很卡&#xff0c;因为很多人在用网络&#xff0c;导致自己的游戏、看电影很不爽。那么遇到这样的问题怎么办呢?下面&#xff0c;就给大家介绍Win7系统局域网抢网…

win7打印机提示无法保存设置错误0x00006cc的处理方法

win7允许快速连接共享打印机&#xff0c;这让用户少了不少设置烦恼&#xff0c;那如果在打印机的快速设置中提示错误0x00006cc代码要怎么解决呢?快跟小编一起来看看win7打印机提示无法保存设置错误0x00006cc的处理方法吧。 win7打印机提示无法保存设置错误0x00006cc的处理方法…

磁卡、ID卡、IC卡、M1卡、CPU卡的理解区分

一、磁卡 磁卡是在一张塑料片上均匀地涂布上一层磁性微 粒材料制成的。 刚生产出来的磁卡上面的磁性微粒是不显磁性的&#xff0c; 这样的磁卡就象一张白纸&#xff0c; 人们需要在磁卡里输入一些信息才能使用。 那么信息是怎样被记录的呢&#xff1f;这就需要纪录磁头 的帮助…

U盘装win7系统出现question(1808)的原因与解决方法

U盘装系统是很多用户和电脑城装机员的首选&#xff0c;这种方法简单快捷&#xff0c;一学就会。但也有用户在安装系统过程中会碰到一些问题&#xff0c;question(1808)便是常见问题之一。这是什么原因呢?下面我们就一起来看看U盘装win7系统出现question(1808)的原因与解决方法…

软考计算机基础:存储系统

软考计算机存储系统笔记&#xff1a; 存储器分类&#xff1a; 1、按存储位置分为内存和外存&#xff1b; 2、按存储材料分为磁存储&#xff08;使用磁存储介质&#xff09;、半导体存储&#xff08;分为双极型和MOS型&#xff0c;根据数据是否需要刷新可以分为静态SRAM存储器…

Win7系统组策略怎么打开 打开组策略的几种方法

在很多情况下&#xff0c;我们都会用到组策略编辑器来对电脑进行一些高级的设置&#xff0c;组策略的作用就是将管理员为用户和计算机定义并控制程序、网络资源及操作系统行为的主要工具。那么&#xff0c;在Win7系统下&#xff0c;我们要怎么打开组策略呢?下面&#xff0c;小…

vscode统计代码行数,前端开发配置、快捷键使用

1、统计代码行数 使用场景是项目年终统计行数。 实现&#xff1a;在需要统计得文件夹右键“在文件夹中查找“ &#xff0c;后输入筛选得正则表达式 ^b*[^:b#/].*$ (注意右边小图标都点亮) 这里顺便将自己使用vscode进行前端开发环境配置归纳一下&#xff0c;便于自己以后快速…

360下载器怎么打开 360下载器使用方法

360下载器怎么打开?360下载器是360安全浏览器极速浏览器中的一个下载组件&#xff0c;组件中包含了迅雷下载支持&#xff0c;所以下载文件的速度比使用ie自带的下载器会快很多。不少刚接触360安全浏览器的用户反应在使用360安全浏览器下载文件程序之后无法找到下载器所在位置&…

vue-cli打包后怎么修改服务器地址实践有效

前言&#xff1a;公司vue项目使用 npm run build 打包生成dist文件部署后&#xff0c;当需要修改服务器端地址时候就又需要重新配置url并打包部署&#xff0c;为简化部署测试工作&#xff0c;想实现通过修改服务器地址的配置文件来实现修改打包后的项目服务器地址。 项目基于vu…

干净高效的搜索引擎

找一个干净好用的搜索引擎&#xff0c;好文转载备忘 为什么不用百度搜索引擎&#xff0c;估计一百个人会有一百个理由。 百度最让人诟病的还是它的竞价排名&#xff0c;其实要赚钱无可厚非&#xff0c;但这吃相……前几天看到知乎上有人发了张百度和谷歌搜索的对比图&#xf…

手机360浏览器怎么清空历史记录 手机360浏览器历史记录清空方法分享

任何一款浏览器产品在使用一段时间后都会出现历史记录&#xff0c;手机360浏览器自然也不能例外。而这些历史记录如果长期不清理的话&#xff0c;则导致手机越来越卡!那么&#xff0c;手机360浏览器怎么清空历史记录?不清楚具体操作的朋友&#xff0c;可以参考一下小编分享的方…

vue使用class添加动态类

<template><d2-container><h3>class使用测试页面</h3><p :class"1 < 2 ? red-font : blue-font">使用三元表达式;</p><p :class"[red-font,blue-bg]">使用数组包含多个类名;</p><p :class"{r…