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. 【POJ - 2387】Til the Cows Come Home(最短路径 Dijkstra算法)

    Til the Cows Come Home 大奶牛很热爱加班,他和朋友在凌晨一点吃完海底捞后又一个人回公司加班,为了多加班他希望可以找最短的距离回到公司.深圳市里有N个(2 <= N < ...

  2. PCB学习总结

    一.电子设计流程概述:项目立项------元件创库----------原理图设计-----------封装绘制-------pcb设计--------生产文件的输出--------pcb文件加工 二. ...

  3. RabbitMQ的基本介绍及与Spring整合

    一,场景回顾 ​ 最近做电商购物项目,在分布式中搜索服务,商品详情服务都是独立的模块.那么有一个问题就是: 商品的原始数据保存在数据库中,增删改查都在数据库中完成. 搜索服务数据来源是索引库,如果数据 ...

  4. Sqlserver 查询把多行内容拼成一个字符串

    当使用:SELECT ','+Id FROM dbo.Test FOR XML PATH('')); //这样读取的数据虽然是1,2,3,4,但是仍然是xml格式,所以当数据超过2033时候,用sql ...

  5. python-day16

    一.正则表达式 regular expression -----regex 验证匹配正则表达式使用单个字符串来描述.匹配一系列匹配某个句法规则的字符串.在很多文本编辑器里,正则表达式通常被用来检索.替 ...

  6. 在Docker for Windows中运行GUI程序

    Docker运行GUI原理 Docker目前大多应用在服务器领域,那么在Docker中可以运行GUI程序吗?怀着好奇心google了一番,还真有人写了一篇文章 running-gui-applicat ...

  7. test-HTML

    吃葡萄不吐葡萄皮- Hello, This is my first html! baidu yiciyuan 防止嗅探 faststone capture picture movie          ...

  8. 非域环境下SQL Server搭建Mirror(镜像)的详细步骤

    1.测试验证环境 服务器角色 机器名 IP SQL Server Ver 主体服务器 WIN-TestDB4O 172.83.XXX.XXX SQL Server 2012 - 11.0.5058.0 ...

  9. 基于.net EF6 MVC5+WEB Api 的Web系统框架总结(2)-业务项目搭建

    本节将介绍如何进行业务项目搭建. 本业务项目示例是简单的企业信息管理功能,业务项目采用Code First方式,搭建包括: 创建实体项目 创建实体数据表映射 创建业务处理项目 创建业务Web项目 搭建 ...

  10. hibernate 报错com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException

    解释:JavaBean的主键类型只能是int类型,因为在映射关系配置是自动增长的,String类型是不能自动增长的,所以会报错.