在很多编程语言中都有this这个特殊关键字的存在,比如Java中的this,还有本文要说到的JavaScript中的this。那么,JavaScript中this究竟有什么特性和用法呢?它又是如何定义的呢?

先来看看ECMAScript 标准规范对this 的定义:

「The this keyword evaluates to the value of the ThisBinding of the current execution context.」
「this 这个关键字代表的值为当前执行上下文的ThisBinding。」

然后再来看看MDN 对this 的定义:

「In most cases, the value of this is determined by how a function is called.」
「在大多数的情况下,this 其值取决于函数的调用方式。」

而JavaScript中this有个有趣的特性,就是它不是固定不变的,它会随着执行环境的改变而改变  大致如下

  ①在函数(方法)被调用时,在方法中的this 表示始终指向最后调用该方法时的那个对象;

  

   在上面的例子中可以看出当全局环境下定义了和对象obj上属性同名的变量时,在对象上的方法被调用的会先在方法作用域内查找需要的变量如name、fn,如果能够找到就取值使用,找不到就沿着作用域链往创建这个方法fn的那个作用域obj去查找,如此一层一层网上一直找到最顶层的window为止。但是本例子关注的是this的指向,通过打印知道是指向了obj,而调用对象方法fn最近也就是最后的那个对象刚好就是obj,因此佐证了this的通俗定义【始终指向最后调用该方法的那个对象】。

  另外在本例子中可能还会有人疑惑为何obj方法fn里面的name打印出来不是obj的那个name值123,反而是全局变量的2333?这里解释一下,首先我们知道要访问一个对象上的属性,规定的格式是 obj.属性或者obj[属性]。而此时打印的name并没有obj,因此会被当成一个变量去解析,这时候会在fn函数作用域查找有没有name变量,没有就往作用域链一层一层往上找(也有人认为是当没有明确的调用对象比如obj时,this直接指向了window对象)。此时的作用域链是这样子的:obj._proto_===window.prototype===window._proto_ ,根据这个作用域链最终找到了window的对象原型上有name这个变量,这就找到了!

  ②在全局环境中,无论是否是在严格模式下,this 都是指向全局对象,在浏览器中指向 window 对象,在Nodejs中的Global对象,在严格模式下指向的是undefined,因此严格模式下定义的全局变量在调用时就不可以使用this调用;

1 var num = 123;
2 console.log(this.num ) ; // 123
3 console.log(this.num === num ) ; // true
4 console.log(this === window) ; // true

严格模式下:

"use strict"     // 使用严格模式
var num= 123; function fn() {
console.log(this); // undefined
console.log(this.num); // 报错 "Cannot read property 'num' of undefined",因为此时 this 是 undefined
} fn();

  ③在构造函数中,this就是被指向通过构造方法创建的那个实例对象。

 1 var name="JavaScript";
2
3 function Student(sName,sAge){
4 this.name=sName;
5 this.age=sAge;
6 console.log(this); //打印实例对象Student{name:"张三",18}和Student{name:"李四",20}
7 }
8
9 var s1=new Student("张三",18);
10 var s2=new Student("李四",20);

  以上都是讲了怎么讲this的指向的那个对象找出来,以便达到我们使用对象上的属性和方法的目的。然而,this的指向还可以人为地手动通过call、apply、bind这三个方法进行改变,这样有时候能满足某个方法里直接使用this重新指向的那个对象obj上的方法和属性,但是又不改变方法原来的对象。

  从上图打印可以看出call将原来ok方法this的指向由obj变为newObj,这样ok方法就可以使用newObj对象上的属性和方法了,而第17行的打印输出说明原对象obj上的属性方法并没有被破坏。

  call、apply、bind三个方法实现的功能(都是用来扩充函数运行时的作用域)是一样的,最后顺便补充说说三者之间的写法上一些小区别:

    1)、bind()方法会返回一个函数,将接受多个参数的函数变换成接受一个单一参数。

      注意:bind(thisArg[, arg1[, arg2[, ...]]]), 将接受多个参数的函数变换成接受一个单一参数。bind()方法所返回的函数的length(形参数量)等于原函数的形参数量减去传入bind()方法中的实参数量(第一个参数以后的所有参数),因为传入bind中的实参都会绑定到原函数的形参。

    2)、apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。

      注意:apply([thisObj [,argArray] ]),调用一个对象的一个方法,2另一个对象替换当前对象。如果argArray不是一个有效数组或不是arguments对象,那么将导致一个TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。

    3)、call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

      注意:call([thisObject[,arg1 [,arg2 [,...,argn]]]]);,应用某一对象的一个方法,用另一个对象替换当前对象。call方法可以用来代替另一个对象调用一个方法,call方法可以将一个函数的对象上下文从初始的上下文改变为thisObj指定的新对象,如果没有提供thisObj参数,那么Global对象被用于thisObj。

  【三个方法记忆小窍门】call就像打电话召集需要的参数,一个一个跟在thisObj后面,apply就像填表格申请某样东西一样把需要的参数打包在一个数组里,bind是把参数一个一个捆绑装订在thisObj后面,跟call类似,但最后bind只返回一个函数,还需要自己手动调用一下(像快递员集中揽件后还要发货一样)。这三个方法如果用在定时器的匿名回调函数中时有破坏定时器的效果,因为他们会立即执行!

   ④都说ES6大法好,那么this在ES6中又是如何表现的呢?ES6带来的箭头函数让开发者眼前一亮的不止代码写法更简洁优雅了,还让函数中飘忽不定的this有了官方指定的去处!

  在箭头函数中,this区别于传统的普通函数中的this,普通函数中this指向的是最后调用函数的那个对象(也就是函数被调用运行时的对象);而箭头函数的this却是在定义箭头函数时由外层函数的this“继承”(不是真正的继承,有点像借用更合适)过来的,换句话说就是实际上箭头函数自身并没有this,它依赖的是外层代码定义时那个this。箭头函数的this不是调用的时候决定的,而是在定义的时候包含着箭头函数的对象就是它的this。这里面其实也应该包含一个查找过程,如下:箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window

情景一:箭头函数的外层是函数,此时的外层函数是由obj最后调用了,于是this指向了obj,箭头函数“继承”了它。

情景二:对象上的方法直接定义为箭头函数时,由于箭头函数外层是对象,不是一个函数,此时this直接指向了window。

  箭头函数带来便捷的同时也有一些需要留意的点,如下:

①在箭头函数中使用call、apply、bind时this参数绑定失效了,this被强制指向了window,至于原因本人尚未清楚,如有人知道可以在评论告知,不甚感激。  

 1 var name="Hello watching me!";
2 var obj={
3 name:"coder4web",
4 arrowFn:()=>{ //直接将对象属性设置为箭头函数情况
5 console.log("this===newObj的结果是:"+(this===newObj));
6 console.log("this===obj的结果是:"+(this===obj));
7 console.log(this.name+"--is testing :I'm an arrow function!");
8 }
9 };
10 var newObj={
11 name:123,
12 ok:function(){
13 console.log("哈哈哈哈~~");
14 }
15 };
16 // obj.arrowFn.apply();
17 // obj.arrowFn.apply(undefined);
18 // obj.arrowFn.apply(null);
19 obj.arrowFn.apply(newObj); //这4种方式的效果是一样的

②箭头函数不能作为构造函数,因为箭头函数都是匿名函数,而构造函数是具名函数,因此箭头函数也不能使用new,箭头函数也不能用argument,没有prototype属性。

 1 var Student=(name)=>{
2 this.name=name;
3 }
4 // var s=new Student("李雷");
5 // console.log(s); //Uncaught TypeError: Student is not a constructor
6
7 var fn=(x)=>{
8 console.log(x);
9 // console.log(arguments); //Uncaught ReferenceError: arguments is not defined
10 }
11 // fn(11);
12
13 var t1=function(){}
14 var t2=function teacher(){}
15 var t3=()=>{}
16 console.log(t1);
17 console.log(t1.prototype);
18 console.log(t2);
19 console.log(t2.prototype);
20 console.log(t3);
21 console.log(t3.prototype);

  至此,JavaScript中的this指向问题探究完毕,以上内容的大部分结论都是阅读思考后自己的总结,鉴于水平有限难免有认识上误差,如果有更好的见解,欢迎在评论区指正提建议哦!谢谢大家的阅读~

  本文属于本人在博客园的第一篇原创文章,希望是个好的开始,一起加油!

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

JavaScript的this到底代表谁?(this指向哪里?)的更多相关文章

  1. javascript的this分别代表什么

    鉴于大家对this到底代表的是什么有疑问,现在将我个人理解的this的情况整理如下.有错误请指正. 第一种情况:  如果是一个全局的function,则this相当于window对象. 这个打印出来的 ...

  2. 基于JavaScript判断浏览器到底是关闭还是刷新(超准确)

    这篇文章主要介绍了基于JavaScript判断浏览器到底是关闭还是刷新(超准确)的相关资料,需要的朋友可以参考下 本文是小编总结的一些核心内容,个人感觉对大家有所帮助,具体内容请看下文: 页面加载时只 ...

  3. 百度蜘蛛IP地址到底代表什么含义?

    百度蜘蛛IP地址到底代表什么含义,是不是不同的ip地址所代表的含义不一样呢?对权重和抓取是否有影响?哪些是无效的蜘蛛,哪些是站长工具的蜘蛛,那些又是百度自己真正的蜘蛛?百度蜘蛛,是百度搜索引擎的一个自 ...

  4. javaScript中this到底指向谁

    1.前言 在JavaScript中,this的指向一直是大多数初学者的易错点,总是搞不清楚this到底指向谁,而在求职面试中,this的指向问题往往又是高频考点.本篇博文就来总结一下在JavaScri ...

  5. JavaScript初探系列(五)——this指向

    一.涵义 this关键字是一个非常重要的语法点.毫不夸张地说,不理解它的含义,大部分开发任务都无法完成.this可以用在构造函数之中,表示实例对象.除此之外,this还可以用在别的场合.但不管是什么场 ...

  6. JavaScript 函数参数传递到底是值传递还是引用传递

    tips:这篇文章是听了四脚猫的js课程后查的,深入的理解可以参看两篇博客: JavaScript数据类型--值类型和引用类型 JavaScript数据操作--原始值和引用值的操作本质 在传统的观念里 ...

  7. JavaScript的“闭包”到底是什么

    在JavaScripot函数闭包的定义中,一般都有一个outer 函数,一个inner函数.那么“闭包”到底是指outer函数呢,还是指inner函数? 从官方定义来看,并不清楚:A closure  ...

  8. javascript DOM,它到底是什么-------Day32

    这一晚上看的我是头疼不已啊,为什么呢? 终究是半路出家,我对javascript的理解仅仅停留在:调用javascript,改变页面样式,元素和实现一些事件的响应,尽管须要的时候可能会用,可是到底使用 ...

  9. 「MYSQL」MYSQL中的int(11)到底代表什么意思?

    一.前言 在工作中经常要与mysql打交道,但是对mysql的各个字段类型一直都是一知半解,因此写本文总结记录一番. 二.简介 对于int类型的一些基础知识其实上图已经说的很明白了,在这里想讨论下常用 ...

随机推荐

  1. Java多线程_同步工具CyclicBarrier

    CyclicBarrier概念:CyclicBarrier是多线程中的一个同步工具,它允许一组线程互相等待,直到到达某个公共屏障点.形象点儿说,CyclicBarrier就是一个屏障,要求这一组线程中 ...

  2. EventLoop-浏览器篇2

    最近又碰到了event loop问题,之前研究的实在是浅显(https://www.cnblogs.com/zx0423/p/12641637.html)所以今天主要讲述promise的链式调用,as ...

  3. Mysql启动后停止的解决方法

    安装mysql后,服务无法正常启动,报错如下: 解法方法: 1           以管理员身份运行命令提示符 2           用命令进行mysql安装目录的bin目录: cd C:\Prog ...

  4. JDBC | 第七章: JDBC数据库连接池使用

    概述 数据库连接池是负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个.那么其中的运行机制又是怎样的呢?今天主要介绍一下数据库连接池原理和常用的连接池. ...

  5. 深度优先搜索(DFS)解题总结

    定义 深度优先搜索算法(Depth-First-Search),是搜索算法的一种.它沿着树的深度遍历树的节点,尽可能深的搜索树的分支. 例如下图,其深度优先遍历顺序为 1->2->4-&g ...

  6. Photon PUN 三 RPCs & RaiseEvent

    官方文档地址 https://doc.photonengine.com/en-us/pun/current/manuals-and-demos/rpcsandraiseevent 一, RPC   P ...

  7. RVO+CA

    http://gamma.cs.unc.edu/RVO/ http://gamma.cs.unc.edu/CA/ https://arongranberg.com/astar/docs/writing ...

  8. bootstrap-table存在合并单元格怎么处理数据

    效果如图: js文件如下: $(function () { initTable() $('#load_vip').change(function () { $ .ajax({ type: 'POST' ...

  9. 用Maven给一个Maven工程打包,使用阿里云镜像解决mvn clean package出错的问题,使用plugin解决没有主清单属性的问题

    本来在STS里做了一个极简Maven工程,内中只有一个Main方法的Java类,然后用新装的Maven3.6.3给它打包. 结果,Maven罢工,输出如下: C:\personal\programs\ ...

  10. Node.js连接MongoDB数据库

    首先要启动MongoDB服务器 先找到你的mongoDb安装目录,我的如下:就在bin文件夹下创建一个data文件夹,data内包含两个空文件夹,如下: 接着回到bin文件夹处,按住shift键,右击 ...