转载阮一峰博客:

www.ruanyifeng.com/blog/2018/06/javascript-this.html

一、问题的由来

 

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

JS的this原理的更多相关文章

  1. Sea.Js的运行原理(转)

    1.CMD(Common Module Definition)规范 Sea.js采用了和Node相似的CMD规范,使用require.exports和module来组织模块.但Sea.js比起Node ...

  2. 深入研究Node.js的底层原理和高级使用

    深入研究Node.js的底层原理和高级使用

  3. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  4. vue.js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  5. 深入解析vue.js响应式原理与实现

    vue.js响应式原理解析与实现.angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新并且重新渲染页面.vue.js ...

  6. 如何编写高质量的js代码--底层原理

    转自: 如何编写高质量的 JS 函数(1) -- 敲山震虎篇   本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm ...

  7. JS简单回弹原理

    /* *JS简单回弹原理 */ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  8. 函数式 js 接口实现原理,以及 lodash/fp 模块

    函数式 js 接口 之前在 youtube 上看到一个技术视频,讲“underscore.js的接口为什么不好用”,以及什么样的接口更好用.演讲者是 lodash.js 的作者,他提出了一种“全面函数 ...

  9. js瀑布流 原理实现揭秘 javascript 原生实现

    web,js瀑布流揭秘 瀑布流再很久之前流行,可能如我一样入行晚的 ,可能就没有机会去使用.但是这个技术终究是个挺炫酷的东西,花了一个上午来研究,用原生js实现了一个,下面会附上源码,供大家解读. 说 ...

  10. Deffered.js的实现原理

    在艾伦的推荐下,看了一个日本人写的延时加载库,非常轻量,写的很棒.作为我的源码学习的第一编. 在认真看了两天之后,才看懂它的实现原理,我下面把通自己的理解,进行了精简.只程现原理,方便日后的回顾.&l ...

随机推荐

  1. Shell之内容匹配与格式输出

    对于大文本或者有些特定格式的文本,有时我们要查找特定内容或定位指定的区域,这样就需要内容匹配. 关于内容匹配,我们常使用的有几个命令: grep,支持正则,查找包含有匹配项的行. cut,提取指定的列 ...

  2. [CPP - STL] functor刨根问底儿

    作为STL六大组件之一,在STL源代码及其应用中,很多地方使用了仿函数(functor),尤其在关联型容器(如set.map)以及algorithm(如find_if.count_if等)中.虽然已经 ...

  3. javascript学习第一天

    从大学第一次接触到JavaScript,到现在一直是个软肋,之前也是学习过一遍,但是缺乏系统学习,基础不牢,那么今天开始从基础部分学起来,今天是第一天,每天至少要保证效率,也要保证学习质量. 恩,要按 ...

  4. git多人协作冲突解决方法

    http://www.trinea.cn/dev-tools/git-skill/ http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361 ...

  5. jquery特效(2)—选项卡

    最近公司有个页面正好用到了选项卡,我就写了一下,感觉还不错,都挺简单的. 下面来看动态效果: 一.主体程序 <!DOCTYPE html> <html> <head> ...

  6. 青岛理工ACM交流赛 J题 数格子算面积

    数格子算面积 Time Limit: 1000MS Memory limit: 262144K 题目描述 给你一个多边形(用’\’和’/’表示多边形的边),求多边形的面积. 输入  第一行两个正整数h ...

  7. HDU2896 病毒侵袭 —— AC自动机

    题目链接:https://vjudge.net/problem/HDU-2896 病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit ...

  8. bzoj3669【NOI2014】魔法森林

    题面一道最短路好题…… 开始和喻队长讨论了一下,喻队长一眼切:枚举ai的上界MAX,每次把ai小于等于MAX的边加到图里,以bi为边权跑最短路. 但是,这样做是O(ai*m)的,妥妥TLE,于是我们想 ...

  9. blog.codedream.ren

    博客将转到 CodeDream  ,新的链接是 http://blog.codedream.ren

  10. [SHOI 2017] 组合数问题

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4870 [算法] 回顾组合数的定义 : C(N , M)表示将N个小球放入M个盒子里的 ...