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 ...
随机推荐
- Amazon S3 分布式存储的 python 接口实现
Amazon s3 是一种分布式的对象存储.用键值对的方式,来存储数据.其中,存入的所有数据都是一个对象(object),每一个对象都有一个键(key)存在. 具有非常方便的 web 访问接口,以及权 ...
- unsqueeze 和 squeeze
squeeze压缩的意思 就是在第几维为1 去掉 unsqueeze 解缩 在第几维增加 变成*1 squeeze用法 c = b.view(1, 1, 1, 2, 3) c.squeeze(0) # ...
- React单页面应用使用antd的锚点跳转失效
首先在react项目中引用antd的锚点 import {Anchor} from 'antd';const { Link } = Anchor; <Anchor> <Link hr ...
- 五分钟学会悲观乐观锁-java vs mysql vs redis三种实现
1 悲观锁乐观锁简介 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果 ...
- Java虚拟机详解(六)------内存分配
我们说Java是自动进行内存管理的,所谓自动化就是,不需要程序员操心,Java会自动进行内存分配和内存回收这两方面. 前面我们介绍过如何通过垃圾回收器来回收内存,那么本篇博客我们来聊聊如何进行分配内存 ...
- 源码分析Retrofit请求流程
Retrofit 是 square 公司的另一款广泛流行的网络请求框架.前面的一篇文章<源码分析OKHttp执行过程>已经对 OkHttp 网络请求框架有一个大概的了解.今天同样地对 Re ...
- Python 标识符说明
在Python中,标识符有字母.数字.下划线组成 所有标识符都可以包括英文.数字.下划线,但不能以数字开头 Python标识符区分大小写 ※以下划线开头的标识符有特殊含义. 例如:以单下划线开头(_t ...
- Okhttp3源码解析(3)-Call分析(整体流程)
### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...
- CSS3的滤镜filter属性
css3的滤镜filter属性,可以对网页中的图片进行类似Photoshop图片处理的效果,例如背景的毛玻璃效果.老照片(黑白照片).火焰效果等. 一.blur(px)高斯模糊 二.brightnes ...
- java 路径问题
java路径存在两种写法"/"和"\\" String path="D:\\1.txt"; String path1="D:/1. ...