JavaScript中的this到底是怎样的?
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到底是怎样的?的更多相关文章
- Javascript中的Prototype到底是什么
Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言.在Javascript中,类和对象看起来没有太多的区别. 什么是prototype: funct ...
- Javascript中的Prototype到底是啥
Javascript也是面向对象的语言,但它是一种基于原型Prototype的语言,而不是基于类的语言.在Javascript中,类和对象看起来没有太多的区别. 通常,这样创建一个对象: functi ...
- this详解:JAVASCRIPT中的this到底是谁?
语法 this 全局对象 在全局执行上下文(函数之外),this引用的是全局对象. console.log(this.document === document); // true // In web ...
- javascript中的this到底指什么?
来自百度知道解释 JavaScript:this是什么? 定义:this是包含它的函数作为方法被调用时所属的对象.说明:这句话有点咬嘴,但一个多余的字也没有,定义非常准确,我们可以分3部分来理解它!1 ...
- 简单谈谈JavaScript中的this
是夜,想着考量下小黄毛近期的JavaScript进阶如何了,鉴于近期一直在接触Vue 2.0,索性就围绕this编写了个代码片段, 给其一个测量,毕竟写js的程序员都知道,JavaScript的函数调 ...
- Javascript中的this指向。
一.JavaScript中的函数 在了解this指向之前,要先弄明白函数执行时它的执行环境是如何创建的,这样可以更清楚的去理解JavaScript中的this指向. function fn(x,y,n ...
- Javascript中的循环变量声明,到底应该放在哪儿?
相信很多Javascript开发者都在声明循环变量时犹豫过var i到底应该放在哪里:放在不同的位置会对程序的运行产生怎样的影响?哪一种方式符合Javascript的语言规范?哪一种方式和ecma标准 ...
- javaScript中this到底指向谁
1.前言 在JavaScript中,this的指向一直是大多数初学者的易错点,总是搞不清楚this到底指向谁,而在求职面试中,this的指向问题往往又是高频考点.本篇博文就来总结一下在JavaScri ...
- Javascript中的valueOf与toString
基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...
随机推荐
- 7.26 面向对象_封装_property_接口
封装 封装 就是隐藏内部实现细节, 将复杂的,丑陋的,隐私的细节隐藏到内部,对外提供简单的访问接口 为什么要封装 1.保证关键数据的安全性 2.对外部隐藏实现细节,隔离复杂度 什么时候应该封装 1.当 ...
- Oralce PL/SQL 调用C
1.要把C写成扩展的形式 ex.c文件 int __declspec(dllexport) sum(int a,int b) { return a+b; } 2.把C代码编译成动态库(*.dll 或 ...
- Day 02--选题与设计(二)
1.今天我们主要设计了一下我们微信小程序可以实现的功能,客户操作的基本流程,研究了墨刀这个工具的使用方法并试着将想法转化为原型设计项目.我们给自己的系统起名为“天天好餐”.我们认为食堂订送餐与网络上的 ...
- Linux 终端命令格式
Linux 终端命令格式 一.目标 了解终端命令格式 知道如何查阅终端命令帮助信息 二. 终端命令格式 command [-options] [parameter] 说明: command:命令名,相 ...
- 入门MySQL——用户与权限
前言: 前面几篇文章为大家介绍了各种SQL语法的使用,本篇文章将主要介绍MySQL用户及权限相关知识,如果你不是DBA的话可能平时用的不多,但是了解下也是好处多多. 1.创建用户 官方推荐创建语法为 ...
- mybatis多表查询之多对多关系查询的实现-xml方式
Mybatis对于多对多关系下的查询提供了集合(collection)的概念来解决,collection属性是resultMap高级结果映射的子集,首先,在本例中我们使用的是集合元素来解决多对多的查询 ...
- Mac忘记MySQL root密码解决方法(亲测有效)
重置MySQL root密码 重置MySQL root用户的密码: 1)新建一个文本文件sql.txt,写入修改用户密码的SQL语句. MySQL 5.7.6及更高版本写这句: ALTER USER ...
- Docker安装Skywalking APM分布式追踪系统
环境介绍 本文使用虚拟机unbutu18+docker.本unbutu18系统IP地址为:192.168.150.134 大家在使用时记得将此地址换成自己的实际地址. docker的安装可参考:htt ...
- Liunx学习总结(八)--服务
什么是服务 服务是向外提供服务的进程,一般来说都会放在后台,既然要持续不断的提供外界随时发来的服务请求,服务进程就需要常驻在内存中,且不应该和终端有关,否则终端退出服务程序就退出了.另外,要能够接待外 ...
- .netcore CAP2.6 快速入门
CAP介绍: CAP是一个用来解决微服务或者分布式系统中分布式事务问题的一个开源项目解决方案.可以解决跨服务器的数据一致性问题.一个简单的列子,如:订单系统创建订单后需要通知邮件通知用户下单成功,解决 ...