在很多编程语言中都有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. 关于H标签 DL DT DD标签的一个小故事

    看了一篇关于SEO论坛的论文,大概故事内容是:一个专业的销售公司,里面SEO  技术多多,可就是销售网站的SEO的情况极为恼火.这天,老板又招到了一个SEO,直接聘为SEO主管全权负责网站的SEO,并 ...

  2. SpringBoot输出日志到文件

    1 基本信息 SpringBoot版本2.2.5 日志框架SLF4J 日志框架的实现LockBack 2 输出文件的配置 2.1 logging.file.name 指定日志文件的位置. 2.1.1 ...

  3. Charles 断点修改Response

    前言: 我们可以通过map功能进行重定向,但如果同一个域名进行的是不同请求与返回.此时map在这里就不适用了. 我们可以通关对某一请求进行断点,在进行修改请求或者返回.这样就可以满足我们的需求了. 一 ...

  4. react+antd的todolist开发

    使用localStorage缓存在cookie里刷新不会充重置 参考链接 create-react-app入门教程https://www.jianshu.com/p/77bf3944b0f4 http ...

  5. js大数字转换,将大额数字转换为万、千万、亿等

    代码 /** * 大数字转换,将大额数字转换为万.千万.亿等 * @param value 数字值 */ export function bigNumberTransform (value) { co ...

  6. MySQL添加外键报错 - referencing column 'xx' and referenced column 'xx' in foreign key constraint 'xx' are incompatible

    MySQL给两个表添加外键时,报错 翻译意思是:外键约束“xx”中的引用列“xx”和引用列“xx”不兼容 说明两个表关联的列数据类型不一致,比如:varchar 与 int,或者 int无符号 与 i ...

  7. 焦大:做SEO应该研究的用户需求的方向

    http://www.wocaoseo.com/thread-60-1-1.html 最近收到打击很大,收获也颇多,这一切都莫过于用户需求的问题.我曾经给我弟说过,我对检索排名特征识别.提取和计算自认 ...

  8. google protocol buffer——protobuf的编码原理二

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...

  9. windows下安装jdk+tomcat+maven并配置

    一.下载安装jdk并配置 1.1 进行JDK下载 下载地址:一键直达 一般下载后,安装位置默认,一路下一步,一直到安装完毕-"关闭". 1.2 环境变量配置 不要管是不是一般情况, ...

  10. Oracle RAC与DG

    RAC RAC: real application clustersrac RAC: real application clustersrac 单节点数据库:数据文件和示例文件一一对应 实例损坏时数据 ...