JavaScript——this与箭头函数
首先了解this运行环境
一、问题的由来
学懂 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()
就变成在全局环境执行。
================================================================================================
然后再了解箭头函数
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与箭头函数相关推荐
- JavaScript中的箭头函数
箭头函数 1.用法 //常规的定义 var func1 = function(a,b){...} //箭头函数 var func1 = (a,b) => {...}//常规(函数体中只有一行re ...
- javascript Arrow functions(箭头函数)
Syntax (param1, param2, -, paramN) => { statements } (param1, param2, -, paramN) => expression ...
- 如何优雅地使用 ES6 箭头函数
作者简介: 李中凯 八年多工作经验 前端负责人, 擅长JavaScript/Vue. 掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/po ...
- JavaScript 初学者必看“箭头函数”
译者按: 箭头函数看上去只是语法的变动,其实也影响了this的作用域. 原文: JavaScript: Arrow Functions for Beginners 译者: Fundebug 本文采用意 ...
- JavaScript箭头函数(Arrow Function)
2019独角兽企业重金招聘Python工程师标准>>> ES6标准新增了一种新的函数:Arrow Function(箭头函数). 更简洁的语法 我们先来按常规语法定义函数: func ...
- JavaScript ES6箭头函数指南
前言 胖箭头函数(Fat arrow functions),又称箭头函数,是一个来自ECMAScript 2015(又称ES6)的全新特性.有传闻说,箭头函数的语法=>,是受到了CoffeeSc ...
- 如何理解JavaScript多个连续箭头函数书写方式
导言: 本菜鸡在学习Vue编程的时候,看到有大佬写的代码用了多个连续箭头函数,完全不能理解是什么意思.经过多方调查和思考才初步理解.本篇文章记录一下自己学习和理解的心得. 有多个箭头函数的代码如何执行 ...
- javascript箭头函数和this的指向问题
箭头函数 下面两代码等价: const fun1 = function(x){return x*x;}const fun = x => x*x; function换成=>,放在参数和函数体 ...
- JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼?
摘要: 箭头函数极大地简化了this的取值规则. 普通函数与箭头函数 普通函数指的是用function定义的函数: var hello = function () {console.log(" ...
最新文章
- 链接3: SQL语句教程
- 一个CV算法工程师的小反思
- EJSS: 南土所梁玉婷组-生境决定了土壤植物系统中细菌、抗性基因和可移动元件间的关系...
- 跳出数据计算拯救人工智能之分布式逻辑
- Oracle中 的 DBMS_CRYPTO加密包
- 华为emui10是鸿蒙,昨日,华为EMUI10,鸿蒙系统正式发布!
- 【杂谈】为何有三AI只做原创,从不转载
- 你了解 Assembly.Load 吗?
- 无代码iVX编程实现简单魂斗罗
- [剑指offer]面试题31:连续子数组的最大和
- php mysql 随机字符串_MySQL_Mysql 自定义随机字符串的实现方法,前几天在开发一个系统,需要 - phpStudy...
- c语言较大的整型相加,二个超长正整数的相加
- Java并发之AQS同步器学习
- LabView学习笔记(四):动态数据类型
- ADB命令行工具使用
- 【程序员的吃鸡大法】利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏...
- Python文本处理(3)——文本表示之 one-hot 词向量(1)——纯小白都能懂!
- 企业运营管理体系是什么?
- 记录vant weapp 小程序组件库遇到的坑以及ios和安卓兼容问题 SubmitBar
- FortiGate 流量整形限速
热门文章
- python的对象和方法_python--类方法、对象方法、静态方法
- iView UI常用组件DatePicker清空技巧
- linux命令之tee,linux tee命令
- createprocess 系统找不到指定的文件_告别文件混乱和找不到,文件管理的新思路...
- 7个JavaScript在IE和Firefox浏览器下的差异写法
- spring boot初体验(三)Spring AOP
- eclipse-阶段四-Server Tomcat v8.5 Server at localhost failed to start.
- image.merge图像有什么变化_图像特征工程:HOG特征描述子介绍
- k8s自定义指标HPA实践(微服务基于自定义指标自动扩缩容的实践)附demo
- pinpoint agent性能优化方面官方文档翻译