五分钟让你了解ES5和ES6中this指向问题

首先对this的下个定义:this是在执行上下文创建时确定的一个在执行过程中不可更改的变量。

this只在函数调用阶段确定,也就是执行上下文创建的阶段进行赋值,保存在变量对象中。这个特性也导致了this的多变性:即当函数在不同的调用方式下都可能会导致this的值不同:

vara =1;functionfun(){  'use strict';vara =2;returnthis.a;}fun();//报错 Cannot read property 'a' of undefined

严格模式下,this指向undefined;👆

vara =1;functionfun(){vara =2;returnthis.a;}fun();//1

即在不同模式下之所以有不同表现,就是因为this在严格模式,非严格模式下的不同。👆

结论:当函数独立调用的时候,在严格模式下它的this指向undefined,在非严格模式下,当this指向undefined的时候,自动指向全局对象(浏览器中就是window)

在全局环境下,this就是指向自己:

this.a =1;varb =1;c =1;console.log(this===window)//true//这三种都能得到想要的结果,全局上下文的变量对象中存在这三个变量

当this不在函数中用的时候,this还是指向了window:

vara =100;varobj = {a:1,b:this.a +1}functionfun(){varobj = {a:1,c:this.a +2//严格模式下这块报错 Cannot read property 'a' of undefined}returnobj.c;}console.log(fun());//102console.log(obj.b);//101

结论:当obj在全局声明的时候,obj内部属性中的this指向全局对象,当obj在一个函数中声明的时候,严格模式下this会指向undefined,非严格模式自动转为指向全局对象。

现在知道了严格模式和非严格模式下this的区别,然而我们日常应用最多的还是在函数中用this,上面也说过了this在函数的不同调用方式还有区别,那么函数的调用方式都有哪些呢?四种:

在全局环境或是普通函数中直接调用

作为对象的方法

使用apply和call

作为构造函数

下面分别就四种情况展开:

直接调用

fun函数虽然在obj.b方法中定义,但它还是一个普通函数,直接调用在非严格模式下指向undefined,又自动指向了全局对象,正如预料,严格模式会报错undefined.a不成立,a未定义。

vara =1;varobj  =  {a:2,b:function(){functionfun(){returnthis.a        }console.log(fun());    }} obj.b();//1

作为对象的方法

b所引用的匿名函数作为obj的一个方法调用,这时候this指向调用它的对象。这里也就是obj:

vara =1;varobj = {a:2,b:function(){returnthis.a;  }}console.log(obj.b())//2

那么如果b方法不作为对象方法调用:

vara =1;varobj = {a:2,b:function(){returnthis.a;  }}vart = obj.b;console.log(t());//1

如上,t函数执行结果竟然是全局变量1,为啥呢?这就涉及Javascript的内存空间了,就是说,obj对象的b属性存储的是对该匿名函数的一个引用,可以理解为一个指针。当赋值给t的时候,并没有单独开辟内存空间存储新的函数,而是让t存储了一个指针,该指针指向这个函数。相当于执行了这么一段伪代码:

vara =1;functionfun(){//此函数存储在堆中returnthis.a;}varobj = {a:2,b: fun//b指向fun函数}vart = fun;//变量t指向fun函数console.log(t());//1

此时的t就是一个指向fun函数的指针,调用t,相当于直接调用fun,套用以上规则,打印出来1自然很好理解了。

使用apply,call

这是个万能公式,实际上上面直接调用的代码,我们可以看成这样的:

functionfun(){returnthis.a;}fun();//1//严格模式fun.call(undefined)//非严格模式fun.call(window)

这时候我们就可以解释下,为啥说在非严格模式下,当函数this指向undefined的时候,会自动指向全局对象,如上,在非严格模式下,当调用fun.call(undefined)的时候打印出来的依旧是1,就是最好的证据。

为啥说是万能公式呢?再看函数作为对象的方法调用:

vara =1;varobj = {a:2,b:function(){returnthis.a;  }}obj.b()obj.b.call(obj)

如上,是不是很强大,可以理解为其它两种都是这个方法的语法糖罢了,那么apply和call是不是真的万能的呢?并不是,ES6的箭头函数就是特例,因为箭头函数的this不是在调用时候确定的,这也就是为啥说箭头函数好用的原因之一,因为它的this固定不会变来变去的了。关于箭头函数的this我们稍后再说。

作为构造函数

何为构造函数?所谓构造函数就是用来new对象的函数,像Function、Object、Array、Date等都是全局定义的构造函数。其实每一个函数都可以new对象,那些批量生产我们需要的对象的函数就叫它构造函数罢了。注意,构造函数首字母记得大写。

functionFun(){this.name ='Lili';this.age =21;this.sex ='woman';this.run =function(){returnthis.name +'正在跑步';  }}Fun.prototype = {contructor: Fun,say:function(){returnthis.name +'正在说话';  }}varf =newFun();f.run();//Lili正在跑步f.say();//Lili正在说话

如上,如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。为啥呢?new做了啥呢?

伪代码如下:

functionFun(){//new做的事情varobj = {};  obj.__proto__ = Fun.prototype;//Base为构造函数obj.name ='Lili';  ...//一系列赋值以及更多的事returnobj}

也就是说new做了下面这些事:

创建一个临时对象

给临时对象绑定原型

给临时对象对应属性赋值

将临时对象return

也就是说new其实就是个语法糖,this之所以指向临时对象还是没逃脱上面说的几种情况。

当然如果直接调用Fun(),如下:

functionFun(){this.name ='Damonre';this.age =21;this.sex ='man';this.run =function(){returnthis.name +'正在跑步';  }}Fun();console.log(window)

其实就是直接调用一个函数,this在非严格模式下指向window,你可以在window对象找到所有的变量。

另外还有一点,prototype对象的方法的this指向实例对象,因为实例对象的proto已经指向了原型函数的prototype。这就涉及原型链的知识了,即方法会沿着对象的原型链进行查找。

箭头函数

刚刚提到了箭头函数是一个不可以用call和apply改变this的典型。

我们看下面这个例子:

vara =1;varobj = {a:2};varfun =()=>console.log(this.a);fun();//1fun.call(obj)//1

以上,两次调用都是1。

那么箭头函数的this是怎么确定的呢?箭头函数会捕获其所在上下文的 this 值,作为自己的 this 值,也就是说箭头函数的this在词法层面就完成了绑定。apply,call方法只是传入参数,却改不了this。

vara =1;varobj = {a:2};functionfun(){vara =3;letf =()=>console.log(this.a);      f();};fun();//1fun.call(obj);//2

如上,fun直接调用,fun的上下文中的this值为window,注意,这个地方有点绕。fun的上下文就是此箭头函数所在的上下文,因此此时f的this为fun的this也就是window。当fun.call(obj)再次调用的时候,新的上下文创建,fun此时的this为obj,也就是箭头函数的this值。

再来一个例子:

functionFun(){this.name ='Damonare';}Fun.prototype.say =()=>{console.log(this);}varf =newFun();f.say();//window

有的同学看到这个例子会很懵,感觉上this应该指向f这个实例对象啊。不是的,此时的箭头函数所在的上下文是proto所在的上下文也就是Object函数的上下文,而Object的this值就是全局对象。

那么再来一个例子:

functionFun(){this.name ='Damonare';this.say =()=>{console.log(this);    }}varf =newFun();f.say();//Fun的实例对象

如上,this.say所在的上下文,此时箭头函数所在的上下文就变成了Fun的上下文环境,而因为上面说过当函数作为构造函数调用的时候(也就是new的作用)上下文环境的this指向实例对象。

作者:未来的IT女神

链接:https://www.jianshu.com/p/77cff23936b4

來源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,094评论 0 13
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,494评论 0 5
  • 前 言 学过程序语言的都知道,我们的程序语言进化是从“面向机器”、到“面向过程”、再到“面向对象”一步步的发展而来...
    小风飞鱼阅读 511评论 0 9
  • 时间过得真快,这两只小乌龟转眼来到我们家就十多天了。 去年年底,一个同事就说要送两只乌龟给我们小孩玩,于是我们孩子...
    西瓜甜甜啦阅读 506评论 6 22
  • 【七律(新韵)】 感怀 -文/大漠 斜阳一抹映高台,几片闲云淡淡来。 煮酒一壶今欲醉,放歌几曲寄心怀。 年年独自追...
    大漠qxy阅读 207评论 13 0