首先了解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()就变成在全局环境执行。

================================================================================================

然后再了解箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。

为什么叫Arrow Function?因为它的定义用的就是一个箭头:

x => x * x

上面的箭头函数相当于:

function (x) {return x * x;
}

在继续学习箭头函数之前,请测试你的浏览器是否支持ES6的Arrow Function:

'use strict';
console.log('你的浏览器支持ES6的Arrow Function!');

Run

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }return

x => {if (x > 0) {return x * x;}else {return - x * x;}
}

如果参数不是一个,就需要用括号()括起来:

// 两个参数:
(x, y) => x * x + y * y// 无参数:
() => 3.14// 可变参数:
(x, y, ...rest) => {var i, sum = x + y;for (i=0; i<rest.length; i++) {sum += rest[i];}return sum;
}

如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

// SyntaxError:
x => { foo: x }

因为和函数体的{ ... }有语法冲突,所以要改为:

// ok:
x => ({ foo: x })

this

箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

回顾前面的例子,由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:

var obj = {birth: 1990,getAge: function () {var b = this.birth; // 1990var fn = function () {return new Date().getFullYear() - this.birth; // this指向window或undefined};return fn();}
};

现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj

var obj = {birth: 1990,getAge: function () {var b = this.birth; // 1990var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象return fn();}
};
obj.getAge(); // 25

===============================================================================================

所以本版的目的就是让你知道this所属的环境是什么,然后调用箭头函数中的this指的环境是什么,了解这个就达到目的了,ojb98k==

再附加一个小例子,isShow1是和mounted函数平级的属性,这个里面this指的是window,你判断对了没

    mounted(){window.setTimeout(function () {this.isShow1= true},2000)},

这个里面的this是mounted函数所属的对象,这里具体是vue对象,我没列出来,能判断对了没

    mounted(){window.setTimeout(()=> {this.isShow1= true},2000)},

一般匿名函数的this都会指的外面的环境

JavaScript——this与箭头函数相关推荐

  1. JavaScript中的箭头函数

    箭头函数 1.用法 //常规的定义 var func1 = function(a,b){...} //箭头函数 var func1 = (a,b) => {...}//常规(函数体中只有一行re ...

  2. javascript Arrow functions(箭头函数)

    Syntax (param1, param2, -, paramN) => { statements } (param1, param2, -, paramN) => expression ...

  3. 如何优雅地使用 ES6 箭头函数

    作者简介: 李中凯 八年多工作经验 前端负责人, 擅长JavaScript/Vue. 掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/po ...

  4. JavaScript 初学者必看“箭头函数”

    译者按: 箭头函数看上去只是语法的变动,其实也影响了this的作用域. 原文: JavaScript: Arrow Functions for Beginners 译者: Fundebug 本文采用意 ...

  5. JavaScript箭头函数(Arrow Function)

    2019独角兽企业重金招聘Python工程师标准>>> ES6标准新增了一种新的函数:Arrow Function(箭头函数). 更简洁的语法 我们先来按常规语法定义函数: func ...

  6. JavaScript ES6箭头函数指南

    前言 胖箭头函数(Fat arrow functions),又称箭头函数,是一个来自ECMAScript 2015(又称ES6)的全新特性.有传闻说,箭头函数的语法=>,是受到了CoffeeSc ...

  7. 如何理解JavaScript多个连续箭头函数书写方式

    导言: 本菜鸡在学习Vue编程的时候,看到有大佬写的代码用了多个连续箭头函数,完全不能理解是什么意思.经过多方调查和思考才初步理解.本篇文章记录一下自己学习和理解的心得. 有多个箭头函数的代码如何执行 ...

  8. javascript箭头函数和this的指向问题

    箭头函数 下面两代码等价: const fun1 = function(x){return x*x;}const fun = x => x*x; function换成=>,放在参数和函数体 ...

  9. JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼?

    摘要: 箭头函数极大地简化了this的取值规则. 普通函数与箭头函数 普通函数指的是用function定义的函数: var hello = function () {console.log(" ...

最新文章

  1. 链接3: SQL语句教程
  2. 一个CV算法工程师的小反思
  3. EJSS: 南土所梁玉婷组-生境决定了土壤植物系统中细菌、抗性基因和可移动元件间的关系...
  4. 跳出数据计算拯救人工智能之分布式逻辑
  5. Oracle中 的 DBMS_CRYPTO加密包
  6. 华为emui10是鸿蒙,昨日,华为EMUI10,鸿蒙系统正式发布!
  7. 【杂谈】为何有三AI只做原创,从不转载
  8. 你了解 Assembly.Load 吗?
  9. 无代码iVX编程实现简单魂斗罗
  10. [剑指offer]面试题31:连续子数组的最大和
  11. php mysql 随机字符串_MySQL_Mysql 自定义随机字符串的实现方法,前几天在开发一个系统,需要 - phpStudy...
  12. c语言较大的整型相加,二个超长正整数的相加
  13. Java并发之AQS同步器学习
  14. LabView学习笔记(四):动态数据类型
  15. ADB命令行工具使用
  16. 【程序员的吃鸡大法】利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏...
  17. Python文本处理(3)——文本表示之 one-hot 词向量(1)——纯小白都能懂!
  18. 企业运营管理体系是什么?
  19. 记录vant weapp 小程序组件库遇到的坑以及ios和安卓兼容问题 SubmitBar
  20. FortiGate 流量整形限速

热门文章

  1. python的对象和方法_python--类方法、对象方法、静态方法
  2. iView UI常用组件DatePicker清空技巧
  3. linux命令之tee,linux tee命令
  4. createprocess 系统找不到指定的文件_告别文件混乱和找不到,文件管理的新思路...
  5. 7个JavaScript在IE和Firefox浏览器下的差异写法
  6. spring boot初体验(三)Spring AOP
  7. eclipse-阶段四-Server Tomcat v8.5 Server at localhost failed to start.
  8. image.merge图像有什么变化_图像特征工程:HOG特征描述子介绍
  9. k8s自定义指标HPA实践(微服务基于自定义指标自动扩缩容的实践)附demo
  10. pinpoint agent性能优化方面官方文档翻译