博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
走进JavaScript之this篇
阅读量:5919 次
发布时间:2019-06-19

本文共 4505 字,大约阅读时间需要 15 分钟。

前言

在这篇文章中,你将会弄清this关键字指的是什么,在为你讲解this同时,你还将学习到.call,.apply,.bindnew以及箭头函数等知识。

this是什么

this 是JavaScript中很特别的一个关键字,被自动定义在所有函数作用域中,但是它即不指向函数自身也不指向函数的词法作用域,它指向的是调用函数的对象。

this到底指向哪里

要判断this指向哪里,我们必须理解每个函数的this并不是在声明时就被绑定的,而是在调用时被绑定。

正如上文所说this指向的是调用函数的对象,所以要判断this到底指向哪里,首先我们要知道 “是哪个对象调用了函数?”

举个例子来帮助同学们理解这一点:

例子1:

123function person(name) {  console.log(name);}复制代码

可以看到例子里声明了一个person函数,接收一个name参数,想知道name会打印出什么,必须得看person函数调用过程中传入参数是什么。同样的道理想判断this指向哪里,就得看函数调用方式是什么。

根据函数调用方式不同,我将其分为下面?几种情况:

1、首先就是最常用的函数调用方法:函数名直接调用

例2:

123456789101112function person() {  console.log(this);}function personStrict() {  'use strict'  console.log(this);}person(); //  windowpersonStrict(); // undefined复制代码

可以看到,函数被直接调用时,就相当于全局对象调用的;这样它的 this就指向全局对象:window

PS:但是在严格模式下,this不会指向全局对象,而是指向undefined,这是为了尽量减少不严谨的出错行为,你只需要在你所写代码作用域的最顶端加上use strict;建议将其放在一个立即执行函数中,避免污染全局。

例3:

1234567(function(){  //'use strict'  function getDoc() {    console.log(this.document);  }  getDoc();})();复制代码

可以看到,如果程序在非严格模式下运行,不会有错误抛出,那是因为在全局对象window中存在一个名为document的属性,而在严格模式下,由于此时this指向undefined,于是抛出一个错误。

2、作为对象的方法调用

例4:

12345678let name = 'window';let person = {  name : 'Heternally',  getName : function(){    console.log(this.name);  }}person.getName(); // 'Heternally'复制代码
123456789let name = 'window';let person = {  name : 'Heternally',  getName}function getName(){  console.log(this.name)}person.getName(); // 'Heternally'复制代码

可以看到在上面?例子中,getName函数是对象person调用的,所以打印出来的值是person中name的值

例5:

12345678910let name = 'window';let person = {  name : 'Heternally',  getName : function () {    console.log(this.name);  }}let getName = person.getName;getName(); // 'window'复制代码

例5对例4做了一点点小改动,可以看到打印出的结果就是window了,这是因为getName函数最终还是被window调用,所以这个this指向的是window

这又应了上文的话,this的指向不能在声明的时候确定,而是取决于谁调用了它

例6:

12345678910111213141516171819202122232425let person1 = {  name : 'person1',  getThis: function () {    console.log(this);  }}let person2 = {  name : 'person2',  getThis: function () {    return person1.getThis();  }}let person3 = {  name : 'person3',  getThis: function () {    var getThis3 = person1.getThis;    return getThis3();  }}person1.getThis(); // person1person2.getThis(); // person1person3.getThis(); // window复制代码

看到这可能有同学会问,不是说this的指向取决于谁调用了它吗,那为什么person3.getThis()打印出来的是window呢,因为在person3.getThis里,调用this的函数是getThis3,所以此时this指向了window

由上面?几个例子可以得出,this指向最后调用它的那个对象。

常用改变this指向方法

1、call、apply、bind

这三个函数的作用都是改变函数执行时的上下文,即改变函数运行时的this指向。有了这个人生,接下来我们通过几个例子来学习如何使用这三个函数。

简单说一下三个方法的用法:

1.1 call
1fun.call(thisArg[, arg1[, arg2[, ...]]])复制代码

它会立即执行函数,第一个参数时指定执行函数中this的上下文,如果不传或者传null、undefined,则表示this指向window,后面的参数是执行函数所需的参数;

1.2 apply
1fun.apply(thisArg[, [arg1, arg2, ...]])复制代码

它会立即执行函数,第一个参数时指定执行函数中this的上下文,如果不传或者传null、undefined,则表示this指向window,第二个参数接收一个数组(这是与call唯一的区别);

1.3 bind
1var foo = fun.bind(thisArg[, arg1[, arg2[, ...]]]);复制代码

它不会立即执行函数,而是返回一个心得函数,这个新的函数被指定了this上下文,接收的参数与call一致;

例7:

1234567891011let person = {  name : 'Heternally'}var name = 'window';function getName() {  console.log(`Hello, my name is ${this.name}`);}getName(); // 'Hello, my name is window'getName.call(person); // 'Hello, my name is Heternally'getName.apply(person); // 'Hello, my name is Heternally'getName.bind(person)(); // 'Hello, my name is Heternally'复制代码

可以看到,使用call、apply、bind方法后,可以动态改变函数执行上下文的this指向

2、new关键字

每当使用new关键字调用函数时,会自动把this绑定在新对象上,然后再调用这个函数

例8:

12345678function Person(name) {  this.name = name;  console.log(this);}var people = Person('Heternally'); // windowvar people1 = new Person('Heternally'); // Person {name: "Heternally"}people.name; //Cannot read property 'name' of undefinedpeople1.name; // 'Heternally'复制代码

3、ES6箭头函数

在ES6中,新加入了箭头函数,它和普通函数最不同的一点就是,对于箭头函数的this指向,只需要看它是在哪里创建即可

例9:

123456789101112131415var person = {  name : 'Heternally',  getName1 : function () {    setTimeout(function(){      console.log(this);    },1000)  },  getName2 : function () {    setTimeout(()=>{      console.log(this);    },1000)  }}person.getName1(); //windowperson.getName2(); // {name:'Heternally',getName1:f,getName2:f}复制代码

可以看到,在getName2方法的setTimeout函数中,没有跟getName1中setTimeout函数一样打印window,而是打印出person对象。

简单说:箭头函数中的this只和定义它时作用域有关,并不受在哪里及如何调用的影响;

优先级

了解了this指向及多种改变this指向的方法后,我们还需要了解这多种方法的优先级,

1函数直接调用  < 对象方法调用 < call/apply < bind < new < 箭头函数复制代码

总结

要判断this指向,需要找到是这个函数的直接调用位置,找到之后可以依据如下方法进行判断this的指向:

1、 是否由箭头函数调用 ?指向箭头函数外层非箭头函数的this指向 : ‘’

2、 是否由new调用 ?指向新创建的对象 : ‘’;

3、 是否由call || apply || bind 调用 ? 指向指定的对象 : ‘’;

4、 是否由对象调用 ? 指向这个对象 : ‘’;

5、 上面几种情况都不是:严格模式下指向undefined,非严格模式下指向全局对象

转载于:https://juejin.im/post/5d01e8fcf265da1bae38f521

你可能感兴趣的文章
第13代PowerEdge强劲升级 五大独有技术是什么?
查看>>
Facebook新地图增加灾难救援功能!
查看>>
日本电气公司1000万美元建大数据分析中心
查看>>
Ovum点评微信小程序:或对应用商店产生破坏性作用
查看>>
《Arduino开发实战指南:LabVIEW卷》——1.2 Arduino的硬件组成
查看>>
《2040大预言:高科技引擎与社会新秩序》——2.11 坐二手无人车的体力工人
查看>>
阿里研究院启动2017年度淘宝村辅助认证活动(附表格下载)
查看>>
《 FreeSWITCH权威指南》——1.7 VoIP
查看>>
消除障碍 加速推进T-SDN产业发展
查看>>
紧紧跟随NSX认证的步伐
查看>>
“大数据”要这样用才赚钱!
查看>>
大数据:如何将信息转化为洞察力?
查看>>
安防行业做大做强 市场需求与行业技术双向驱动
查看>>
《液晶显示器和液晶电视维修核心教程》——导读
查看>>
《NX-OS与Cisco Nexus交换技术:下一代数据中心架构(第2版)》一2.8 Cisco FabricPath...
查看>>
《贝叶斯思维:统计建模的Python学习法》——2.6 M&M豆问题
查看>>
《Sony Vegas Pro 12标准教程》——导读
查看>>
2017 会成为 PaaS 模式的终结年吗?
查看>>
大数据揭秘:在阿里巴巴待满五年的秘诀竟然是……
查看>>
《Excel高手捷径:一招鲜,吃遍天》一第4招 怎样在多张工作表做相同的操作——创建工作组...
查看>>