ES6学习笔记之 this 详解
1.非箭头函数下的 this
var obj = {
x: 0,
f1: function () {
console.log(this.x);
}
}
var f1 = obj.f1;
var x = 1; obj.f1(); //0
f1(); //1
上面代码中,虽然 obj.f1 和 f1 指向的是同一个函数,但是执行的结果却不一样。这种差异的原因,就在于函数体内使用了 this 关键字。我们都知道,this 指的是函数运行时所在的环境。对于 obj.f1() 来说,f1 运行在 obj 环境下,所以this 指向obj ;对于 f1() 来说,f1() 运行在全局环境,所以 this 指向全局环境。因此,两者的运行结果不一样。
现在我们来想想,为什么会这样呢?为什么obj.f1() 就是在 obj 环境执行,而 var f1 = obj.f1 之后,f1() 就是在全局环境执行呢?
那就要从内存里面的数据结构说起了,我们一步一步来看。
var obj = {
x: 0,
f1: function () {
console.log(this.x);
}
}
上面代码中,将一个对象赋值给变量 obj ,javascript 引擎会先在内存中,生成一个对象,然后再将这个对象的内存地址赋值给变量 obj。也就是说,变量obj 是一个地址。后面如果要读取 obj.x,引擎首先从 obj 拿到内存地址,然后再从该地址读出原始的对象,返回 x 属性。
如上图所示,对象的每一个属性名都对应一个属性描述对象,属性的值保存在属性描述对象的 value 属性里面。
属性的值为函数时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给 f1 属性的 value 属性。由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。
我们可以在函数内部,引用当前环境的其他变量。那么,是怎样在函数内部获得当前的运行环境的呢?答案就是 this ,this 的设计目的就是在函数体内部,指代函数当前的运行环境。
现在我们可以回答一开始的问题了, obj.f1() 是通过 obj 里存的地址找到 f1, 所以是在 obj 环境下执行的;而 var f1 = obj.f1 之后,f1() 直接指向函数本身,所以 f1() 就是在全局环境执行.
2.箭头函数中的this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。箭头函数导致 this 总是指向函数定义生效时所在的对象。
function Timer(){
this.s1 = 0;
this.s2 = 0;
//箭头函数
setInterval(() => this.s1++, 1000);
//普通函数
setInterval(function (){
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100); //s1: 3
setTimeout(() => console.log('s2: ',timer.s2), 3100); //s2: 0
上面代码中, Timer 函数内部设置了两个定时器,分别使用了箭头函数和普通函数。箭头函数的 this 绑定定义时所在的作用域(即 Timer 函数),普通函数的 this 指向运行时所在的作用域(即全局对象)。var timer = new Timer() 这条语句执行之后,再过1000毫秒,箭头函数定义生效,this总是指向函数定义生效时所在对象,即timer;对于普通函数,因为setTimeout()
调用的代码运行在与所在函数完全分离的执行环境上,这会导致 this 指向 window 对象。所以3100毫秒之后,timer.s1 被更新了3次,而 timer.s2 一次都没更新。
箭头函数中,this 对象的指向是固定的。这种指向的固定化,实际是因为箭头函数根本没有自己的 this ,导致内部的 this 就是外层代码块的 this 。正是因为它没有this,所以也就不能用作构造函数。
var name = 'window';
var A = {
name : 'A',
show: () => {
console.log(this.name);
}
}
A.show(); //window
如上面代码中的箭头函数,即 show 函数内没有 this,其内部的 this 就是外层代码块的 this,因为没有其他函数的包裹,所以最外层代码块的this指向的就是window对象。所以最后会输出window。
那么,怎样改成永远绑定A呢?
var name = 'window';
var A = {
name: 'A',
show: function() {
var s = () => console.log(this.name);
return s;
}
}
var show = A.show();
show(); //A
var B = {
name: B
}
show.call(B); //A
show.call(); //A
这样就做到了永远指向 A 对象,我们再来分析一下:
原代码中 show 即是箭头函数,没有自己的 this;修改之后的代码中,箭头函数所在的作用域是在 show 函数内,show 是普通函数,有自己的 this,在函数调用时生效。A.show() 指向的对象是 A。所以箭头函数 s 中的 this 就是指向 A 了。
ES6学习笔记之 this 详解的更多相关文章
- expect学习笔记及实例详解【转】
1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...
- ES6学习笔记之变量的解构赋值
变量的解构赋值 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 数组的解构赋值 以前,为变量赋值,只能直接指定值: 1 2 3 var a = 1; var b = 2; ...
- Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解
前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY <源路径> .. ...
- Redis学习笔记4-Redis配置详解
在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...
- Struts2学习笔记(二)——配置详解
1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...
- Struts2学习笔记二 配置详解
Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...
- Android学习笔记之Activity详解
1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...
- [C#] 类型学习笔记二:详解对象之间的比较
继上一篇对象类型后,这里我们一起探讨相等的判定. 相等判断有关的4个方法 CLR中,和相等有关系的方法有这么4种: (1) 最常见的 == 运算符 (2) Object的静态方法ReferenceEq ...
- vue.js学习笔记(二)——vue-router详解
vue-router详解 原文链接:www.jianshu.com 一.前言 要学习vue-router就要先知道这里的路由是什么?为什么我们不能像原来一样直接用<a></a> ...
随机推荐
- debian系统搭建telnet服务器以及telnet远程登陆--加油
1.安装软件 sudo apt-get install telnet* 2.创建telnet文件 vim /etc/xinetd.d/telnet telnet内容 1 service telnet ...
- ES6学习-4 解构赋值(1)数组的解构赋值
解构赋值是ES6很大的一个提升,为我们带来了很多方便,但用不好,会使程序的可读性变差,所以用时要注意,尽量保持程序的易读性. 数组解构赋值 在JS没有支持解构赋值之前,我们声明几个变量并赋值通常都是像 ...
- 6.注册CRT 以及SecureCRT访问
1.什么是 SecureCRT SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,简单地说是Windows下登录Unix或Linux服务器主 机的软件. 1)准备工作:安装好Se ...
- Nginx导航
简介 最近都在弄微服务的东西,现在来记录下收获.我从一知半解到现在能从0搭建使用最大的感触有两点 1.微服务各大组件的版本很多,网上很多博客内容不一定适合你的版本,很多时候苦苦琢磨都是无用功 2.网上 ...
- shell中 -eq,-ne,-gt,-lt,-ge,-le数字比较符
使用说明: -eq //equals等于 -ne //no equals不等于 -gt //greater than 大于 -lt //less than小于 -ge ...
- Linux PATH环境变量及作用(初学者必读)
Linux PATH环境变量及作用(初学者必读) < 什么是环境变量,Linux环境变量有哪些?Linux打包(归档)和压缩 > <Linux就该这么学>是一本基于最新Linu ...
- MyBatis 延迟加载(十四)
什么是延迟加载 延迟加载又叫懒加载,也叫按需加载,也就是说先加载主表信息,需要的时候,再去加载从表信息.代码中有查询语句,当执行到查询语句时,并不是马上去数据库中查询,而是根据设置的延迟策略将查询向后 ...
- workbench msvcr120.dll 文件缺失问题
开始以为是dll文件缺失,后来下载了好几个版本的替换到system32文件夹下.依然不起作用. 后来看到解决办法了,原文在此:http://forums.mysql.com/read.php?169, ...
- 10.1 ifconfig:配置或显示网络接口信息
ifconfig命令 用于配置网卡IP地址等网络参数或显示当前网络的接口状态,其类似于Windows下的ipconfig命令,这两个命令很容易混淆,读者需要区分一下.此外,ifconfig命令在配置网 ...
- Objective Evaluation Index of image
图像质量客观评价指标 在做红外图像细节增强算法研究时,很重要一点就是要对经过算法处理的图像结果进行评价,分成两种评价方法.一种是视觉效果评价:主观的人眼观察,主要是通过观察者能否看到更多图像细节,给人 ...