this是困惑JavaScript开发者的一大‘毒瘤’,在开发过程中,但凡用到this的时候,我们都会很头疼,那么这个this在JavaScript中到底是怎么样的?身为一个前端coder,这是一个避不开的话题。

经典代码

下面,我们先开看一段社区里面的经典的精华代码,看看它到底试图说明什么:

function foo() {
var a = 2;
this.bar();
} function bar() {
console.log(this.a);
} foo(); // ReferenceError: a is not defined

看了这一段代码,我们不由再想一下两个问题

this指向函数自身吗(×)?

如果this指向函数自身,foo函数中的this.bar()竟然神奇的调用成功了,这显然是不对的。这时候如果打印this,很明显this指向全局对象window。

this指向词法作用域吗(×)?

如果this指向词法作用域,那么为什么bar()会引发引用错误?很明显,this也并不指向词法作用域。

我想,社区经典代码,大概就是为了陈述我们经常会有的这两种错误的观念,那么,我们这时候不仅要思考了,this到底是什么?

为什么会出现this?

说明JavaScript为什么要用this之前,我们先看看下面代码:

function printName(obj){
console.log(obj.name)
} var obj1 = {
name: 'obj1Name'
} var obj2 = {
name: 'obj2Name'
} printName(obj1); // obj1Name
printName(obj2); // obj2Name

在这段代码中,如果要打印出某对象的name属性,那么就需要显示的将对象传递进入方法参数,那么如果不想要传递参数,有没有什么办法来实现这样的操作?

这个时候,this便应运而生了。看下面代码:

function printName(){
console.log(this.name)
} var obj1 = {
name: 'obj1Name'
} var obj2 = {
name: 'obj2Name'
} printName.call(obj1); // obj1Name
printName.call(obj2); // obj2Name

这就是this出现的原因,this出现的宗旨是想要在函数调用的时候隐式的传递对象引用,想要使得我们的代码看起来更优雅,但是this在JavaScript的引入真的完美做到我们想要的事情了吗?

不,并没有,最起码this的指向就让大多数前端开发者头疼不已,甚至用词法作用域的概念去避免(self = this or 箭头函数)。

this的特点

有上述描述,我们可以得出this的一些特点:

1、隐式传递对象引用,但并不能穿透作用域(经典代码的bar)

2、运行时调用才会产生this

3、this不指向函数自身,也不指向词法作用域

所以,this到底是什么?

当函数调用时,this在运行时绑定,而函数调用此时产生了执行上下文,执行上下文中包括了调用栈、参数信息等,当然也包括了this。this正是为了在运行时绑定而存在的。

那么,this的绑定又是怎么样的呢,或者说this到底是指向了什么?

this指向(绑定)

先说JavaScript的this避坑三连:

1、当函数作为对象的方法调用的时候,函数中this指向该对象(上述call调用代码)。

2、当函数被正常调用(全局作用域下),this指向window。(注意:严格模式指向undefined)。

3、this不会有函数穿透现象(箭头函数或者匿名函数除外)

在这里说说第三点的函数穿透,其实和作用域穿透是相同的概念。那么为什么箭头函数和匿名函数可以穿透到外层this呢?

因为箭头函数没有自己的执行上下文,而this又是执行上下文的一个属性,所以,箭头函数的this或者说在其中如果调用this的话,其实就是调用的箭头函数外层的this。

this默认指向

要说this默认指向,只看简单的一个普通函数调用即可,一般来说,this的默认指向是全局对象。看下面代码:

var obj = {
name: 'objName',
printThis: function(){
console.log(this);
function innerFunc() {
console.log(this);
}
innerFunc();
}
} obj.printThis();

这段代码中,我们执行代码,会发现,innerFunc的this打印出来的竟然是全局对象window(严格模式下,undefined),同时,这一段代码也印证了,我们obj调用函数时候,外层函数的this指向的是obj,并且没有this指向穿透现象。

显式this

那么有什么办法显式让对象调用this呢?(最上面的call)

看下面代码:

var obj = {
name: 'objName',
printThis: function(){
console.log(this);
var self = this;
function innerFunc() {
console.log(self);
}
innerFunc();
}
} obj.printThis();

这一段代码,毫无疑问是对this默认指向的代码的修复(通过self避免,并非修改this指向,inner中this依旧指向全局对象)

箭头函数,和self避免的方式差不多,因为箭头函数没有执行上下文,它内部的this相当于是外部函数的this。

所以,如果是应用self避免,和箭头函数,我们相当于是撇开了this问题,是用词法作用域来避免我们不熟悉的东西,如果针对到this,我们依旧感觉到有些头疼。

那么,这时候,就需要显式执行this了。还是上述代码,做如下修改:

var obj = {
name: 'objName',
printThis: function(){
console.log(this);
function innerFunc() {
console.log(this);
}
innerFunc.call(obj); // 显式绑定this
}
} obj.printThis();

这个时候,我们打印出来的两个this也就完全一致,都是obj对象,因为在这里我们用call来显式绑定了this。

除了call,我们还可以用bind和apply来实现如此效果。

总结

this在运行时产生,率属于函数上下文的一个属性,this的指向不一而定,是在函数调用时根据上下文来确定,也可以利用显式调用的call、apply、bind方式来修改this指向。

this是个不可避免的问题,当我们用箭头函数和self避免的时候,也要思考一下this的指向,以免混淆了this和词法作用域的概念。

我的博客:http://www.gaoyunjiao.fun/?p=159

JavaScript中的this到底是怎样的?的更多相关文章

  1. Javascript中的Prototype到底是什么

    Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言.在Javascript中,类和对象看起来没有太多的区别. 什么是prototype: funct ...

  2. Javascript中的Prototype到底是啥

    Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言.在Javascript中,类和对象看起来没有太多的区别. 通常,这样创建一个对象: functi ...

  3. this详解:JAVASCRIPT中的this到底是谁?

    语法 this 全局对象 在全局执行上下文(函数之外),this引用的是全局对象. console.log(this.document === document); // true // In web ...

  4. javascript中的this到底指什么?

    来自百度知道解释 JavaScript:this是什么? 定义:this是包含它的函数作为方法被调用时所属的对象.说明:这句话有点咬嘴,但一个多余的字也没有,定义非常准确,我们可以分3部分来理解它!1 ...

  5. 简单谈谈JavaScript中的this

    是夜,想着考量下小黄毛近期的JavaScript进阶如何了,鉴于近期一直在接触Vue 2.0,索性就围绕this编写了个代码片段, 给其一个测量,毕竟写js的程序员都知道,JavaScript的函数调 ...

  6. Javascript中的this指向。

    一.JavaScript中的函数 在了解this指向之前,要先弄明白函数执行时它的执行环境是如何创建的,这样可以更清楚的去理解JavaScript中的this指向. function fn(x,y,n ...

  7. Javascript中的循环变量声明,到底应该放在哪儿?

    相信很多Javascript开发者都在声明循环变量时犹豫过var i到底应该放在哪里:放在不同的位置会对程序的运行产生怎样的影响?哪一种方式符合Javascript的语言规范?哪一种方式和ecma标准 ...

  8. javaScript中this到底指向谁

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

  9. Javascript中的valueOf与toString

    基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...

随机推荐

  1. java高并发系列 - 第27天:实战篇,接口性能成倍提升,让同事刮目相看,现学现用

    这是java高并发系列第27篇文章. 开发环境:jdk1.8. 案例讲解 电商app都有用过吧,商品详情页,需要给他们提供一个接口获取商品相关信息: 商品基本信息(名称.价格.库存.会员价格等) 商品 ...

  2. c# 将dwg文件转化为pdf

    https://blog.csdn.net/mywaster/article/details/50220379 最近做一个项目,要求将dwg文件转化为pdf,开发工具VS2010 + AutoCad ...

  3. .net测试篇之单元测试/集成测试神器Autofixture

    autofixture简介 有了单元测试框架加上Moq(后面我们会用单独章节来介绍moq),可以说测试问题基上都能搞定了.然而有了AutoFixture对单元测试来说可以说是如虎添翼,AutoFixt ...

  4. 吉特日化MES-生产制造的几种形态

    1. 订货型和备货型 工厂的生产形态是以接受订单时间和开始生产时间来划分的,因为生产要么得到销售指令要么得到备货指令不能无缘无故的生产.销售指令驱动生产直接受市场销售影响,而备货型可能是对市场的一种预 ...

  5. 解决Selenium弹出新页面无法定位元素问题(Unable to locate element)

    Python 2.7 IDE Pycharm 5.0.3 环境细节详见Python+Selenium+PIL+Tesseract真正自动识别验证码进行一键登录 对于同一页面无法定位元素问题请见姊妹篇解 ...

  6. css布局之居中

    CSS布局之居中 本文主要是介绍水平居中,垂直居中,还有水平垂直居中的方法 水平居中 1.行内元素水平居中 使用text-align:center;就可以实现行内元素的水平居中,但是记得要在父元素中设 ...

  7. Docker跨服务器通信Overlay解决方案(上) Consul单实例

    场景 公司微服务快上线了,微服务都是用Docker容器进行部署的,在同一台主机下,把服务都部署上,注册到Nacos的IP与PORT都是内网的IP与Dockerfile中定义的端口号,看起来好像也没什么 ...

  8. 【阿里云IoT+YF3300】3. Alink物模型之属性上传和下发

    [名词解释]属性:设备的功能模型之一,一般用于描述设备运行时的状态,如环境监测设备所读取的当前环境温度等.属性支持 GET 和 SET 请求方式.应用系统可发起对属性的读取和设置请求. 在上一篇文章& ...

  9. python学习之并发编程

    目录 一.并发编程之多进程 1.multiprocessing模块介绍 2.Process类的介绍 3.Process类的使用 3.1 创建开启子进程的两种方式 3.2 获取进程pid 3.3验证进程 ...

  10. 并查集(不相交集合)详解与java实现

    目录 认识并查集 并查集解析 基本思想 如何查看a,b是否在一个集合? a,b合并,究竟是a的祖先合并在b的祖先上,还是b的祖先合并在a上? 其他路径压缩? 代码实现 结语 @(文章目录) 认识并查集 ...