深入理解JavaScript系列:各种上下文中的this
开头闲扯几句。上篇写对象原型的文章获得了1K多的阅读和几条评论,心里还是蛮欣喜的。那种写出来然后有人跟你讨论的感觉很不错。
公告里已经有写,自己开这个博客以及为什么要写文章的原因就是为了能把自己所思所想以文字的形式表述出来。有时候自己以为理解了某个知识点,但是当你尝试着去给别人讲的时候却发现原来自己一直是半知半解而已,会用不代表理解,所以能够把一个知识点很全面又极尽清晰的写下来的时候才能发现自己还有哪些死角没有注意到还有哪些方面没有考虑到。很明显,一篇文章肯定会有各种的表述性错误,所以写下来的过程也是自己认识自己错误的过程。
共勉,成长。
下面试着总结下JavaScript中的this关键字。
还是按照概念相关性的顺序按照1234展开来讲。
1.this关键字在何处出现?
this他只能出现在函数中。当然在全局作用域中是个例外,意思是this只可能在两种情境下出现,一个是在函数体内,另一个是在全局作用域。
2.this是什么?
this是关键字,语言规范里规定他指向函数执行时的当前对象。它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
3.this到底指向哪?
首先明确this在JavaScript中和函数的执行环境而不是声明环境相关。
第一条中已经说过,this只能出现在函数中和全局作用域中,全局作用域中this指向全局对象(全局对象在浏览器这个环境中指window)。
如果this出现在函数中,那就要分情况来看this到底指向哪了。指向的依据就是函数的执行环境而不是声明环境。其实可以以一句话来概括就是this永远指向所在函数的所有者,当没有显示的所有者的时候,那么this指向全局对象。
4.各种情况下的this的具体指向?
(1).全局作用域
console.log(this)
直接在全局作用域中打印this,其指向为window。
所以在全局作用域中this指向全局对象。
(2).函数作为某个对象的成员方法调用
var name = "chirenmiao1";
var obj= {
name: "chirenmiao2",
getName: function () {
console.log(this.name);
}
}
obj.getName();//chirenmiao2
在全局作用域中声明全局变量name,在obj对象中声明同时也声明一个name。当用对象obj调用他的成员方法getName的时候,this指向这个obj,因此打印出来的this.name为obj的name。
所以函数作为某个对象的成员方法调用时this指向该对象。
(3).函数作为函数直接使用
var name = "chirenmiao1";
var obj= {
name: "chirenmiao2",
getName: function () {
console.log(this.name);
}
}
var getName= obj.getName;
getName(); //chirenmiao1
同样的还是上边的一段代码,只不过这次我们把getName这个函数直接执行,这时在函数执行的时候他没有明确的当前对象,所以默认这时this就指向了全局对象。
所以函数作为函数直接使用时this指向全局对象。
function myFun() {
console.log(this);
}
myFun();
还有就是函数声明直接执行的时候,this也指向全局对象。
其实上边三条就已经简单覆盖了this指向的所有情况,下面紧接着讲述一些稍微特殊的情况。
(4).函数作为构造函数调用
var name = 'chirenmiao1';
var Obj = function (x, y) {
this.name = 'chirenmiao2';
}
Obj.prototype.getName = function () {
console.log(this.name);
}
var myObj = new Obj();
myObj.getName();//chirenmiao2
函数作为构造函数调用时this指向用该构造函数构造出来的新对象。
(5).setTimeout和setInterval以及匿名函数
var name = "chirenmiao1";
var obj = {
name: "chirenmiao2",
getName: function () {
setTimeout(function () {
console.log(this.name);
}, 1000);
},
}; obj.getName();//chirenmiao1
这两个函数执行的时候第一个参数可以为一个匿名函数,也可以是一个声明好的函数引用,所以this指向也就是指这个匿名函数或者函数引用的this的指向。通过第一条已经知道匿名函数或者在全局作用域中声明的函数直接执行的时候,其中的this指向全局对象,所以在这里也一样,setTimeout和setInterval两者运行时,this指向全局对象。
这个时候如果还想输出的是chirenmiao2,也就是this指向obj的话就需要做点手脚了。
var name = "chirenmiao1";
var obj = {
name: "chirenmiao2",
getName: function () {
var self = this;
setTimeout(function () {
console.log(self.name);
}, 1000);
},
}; obj.getName();//chirenmiao2
当然这样是改变不了this指向的,但是可以通过把this赋值给self,就实现了保存this指向的作用。
紧接着是匿名函数。
(function () {
console.log(this);
})()//window
匿名函数中的this指向全局对象,因为他没有显示的所有者。
(6)apply、call、bind
这三个函数是函数对象的一个方法,他们的作用就是为了改变函数执行时候的this指向,具体用法如下:
call:call(obj[,arg1][,arg2]);第一个参数为强制改变需要指向的对象,后边可选的是该函数的参数,如果不传obj的话默认为window。
apply:apply(obj[,arr]);第一个参数为强制改变需要指向的对象,后边可选的是该参数集合的数组形式,如果不传obj的话默认为window。
apply和call的作用和调用形式基本一致,不同的是call后面的参数与方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和方法中一一对应的,这就是两者最大的区别。两者都可以不传参数,此时默认改变指向的对象为全局对象。
bind:bind的调用形式和call相同,但是他返回的是改变调用对象后的函数引用,所以还要再执行一次,也就是obj.fun().bind()()。
总结:this作为函数运行时,自动生成的一个内部对象,只能在函数内部使用。具体this指向谁,要看this的所有函数是谁调用的,具体情况可分为全局作用域、作为某对象的方法调用、直接执行、匿名函数直接执行、call、apply、bind强制改变调用对象等。
完!
祝愉快。
深入理解JavaScript系列:各种上下文中的this的更多相关文章
- 深入理解JavaScript系列(20):《你真懂JavaScript吗?》答案详解
介绍 昨天发的<大叔手记(19):你真懂JavaScript吗?>里面的5个题目,有很多回答,发现强人还是很多的,很多人都全部答对了. 今天我们来对这5个题目详细分析一下,希望对大家有所帮 ...
- 深入理解JavaScript系列(16):闭包(Closures)
介绍 本章我们将介绍在JavaScript里大家经常来讨论的话题 —— 闭包(closure).闭包其实大家都已经谈烂了.尽管如此,这里还是要试着从理论角度来讨论下闭包,看看ECMAScript中的闭 ...
- 深入理解JavaScript系列(15):函数(Functions)
介绍 本章节我们要着重介绍的是一个非常常见的ECMAScript对象——函数(function),我们将详细讲解一下各种类型的函数是如何影响上下文的变量对象以及每个函数的作用域链都包含什么,以及回答诸 ...
- 深入理解JavaScript系列(14):作用域链(Scope Chain)
前言 在第12章关于变量对象的描述中,我们已经知道一个执行上下文 的数据(变量.函数声明和函数的形参)作为属性存储在变量对象中. 同时我们也知道变量对象在每次进入上下文时创建,并填入初始值,值的更新出 ...
- 深入理解JavaScript系列(13):This? Yes,this!
介绍 在这篇文章里,我们将讨论跟执行上下文直接相关的更多细节.讨论的主题就是this关键字.实践证明,这个主题很难,在不同执行上下文中this的确定经常会发生问题. 许多程序员习惯的认为,在程序语言中 ...
- 深入理解JavaScript系列(12):变量对象(Variable Object)
介绍 JavaScript编程的时候总避免不了声明函数和变量,以成功构建我们的系统,但是解释器是如何并且在什么地方去查找这些函数和变量呢?我们引用这些对象的时候究竟发生了什么? 原始发布:Dmitry ...
- 深入理解JavaScript系列(10):JavaScript核心(晋级高手必读篇)
本篇是ECMA-262-3 in detail系列的一个概述(本人后续会翻译整理这些文章到本系列(第11-19章).每个章节都有一个更详细的内容链接,你可以继续读一下每个章节对应的详细内容链接进行更深 ...
- 深入理解JavaScript系列(9):根本没有“JSON对象”这回事!
前言 写这篇文章的目的是经常看到开发人员说:把字符串转化为JSON对象,把JSON对象转化成字符串等类似的话题,所以把之前收藏的一篇老外的文章整理翻译了一下,供大家讨论,如有错误,请大家指出,多谢. ...
- 深入理解javascript系列(4):立即调用的函数表达式
本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...
- 深入理解javascript系列,读书笔记
深入理解JavaScript系列(2):揭秘命名函数表达式 1.讲了函数声明和函数表达式的区别,包括一些在函数提升上的区别 2.如果给函数表达式的函数也取名,会在调试的时候受益 3.不要在block( ...
随机推荐
- DPDK内存管理(1)
1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal 是统一 ...
- C#获取全部目录和文件
public class FileAccess{ //储存所有文件夹名 private ArrayList dirs; public FileAccess() { dirs = new ArrayLi ...
- MacOS长按无效问题
defaults write -g ApplePressAndHoldEnabled -bool FALSE 注销并重新登录系统使其更改生效. 如果需要恢复长按键盘可以重音字符或非英文字符的功能,请打 ...
- Java自由块(静态和非静态)(转载)
java中的自由块分为两种: 静态块和非静态块 静态块: public class Test { 2 static int x = 10; 3 //静态块:静态块的执行时机是在class文件装载的时候 ...
- 三星四核RP4412开发板的root问题
问:荣品四核RP4412开发板的板子是root权限吗? 或者怎么root? 答:su . android 我们提供的是root用户 问:root以后的授权管理器没法运行. 我需要root,我要在and ...
- 转: Rest简介及Spring实现
一 Roy Fielding 2000年Rest被Roy Fielding提出来的,我对Roy Fielding的印象有以下几个. 一是RoyFielding做为Http协议的起草者,在Http协议发 ...
- 160个crackme-之Acid burn.exe
工具: Ollydbg(OD) 中文版 运行: 我们拿到一个小程序时,总要看看它到底有什么功能,或者说它阻碍了我们什么,也就是寻找突破口! 这就是程序运行后的主界面 我们进入Serial/Name后, ...
- mysql-front导出数据库字典
直接导出HTML,然后打开HTML最后直接复制到word就可以了!!!之前一直在找navicat如何导出数据字典.现在发现就是这样就可以了!
- 几个实用的mysql函数
在工作中,处理数据时候往往使用php要废很多脑筋和写很多东西,如果不考虑代码的阅读性试试几个mysql的函数可以解决许多常见需求: 1.截取字符串函数: left() 从左开始截取字符串 right ...
- C# 数据类型
1.整数类型: int 只能 存储证书,不能存储小数. 2.小数类型: doubie 机能存储整数,也能存储小数,小数点后面的额 15-16位. 3.金钱类型: decimal:用来存储金钱, ...