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 ...
随机推荐
- C#.Net实现AutoCAD块属性提取
https://blog.csdn.net/dengyiyu/article/details/2201175 本文主要给大家介绍一下SmartSoft中用C#.Net实现AutoCAD块属性提取的方法 ...
- python 3.7.4下载与安装的问题
发病时间:2019 年 8 月12 日 周一 1.操作系统环境: Win10 64位 2.pyhon版本3.7.4 python官网地址:www.python.org 本机下载的文件名为:python ...
- Leetcode之二分法专题-275. H指数 II(H-Index II)
Leetcode之二分法专题-275. H指数 II(H-Index II) 给定一位研究者论文被引用次数的数组(被引用次数是非负整数),数组已经按照升序排列.编写一个方法,计算出研究者的 h 指数. ...
- MSIL实用指南-加载和保存参数
本篇讲解怎么加载和保存参数,以及参数起始序号的确定. 参数的加载加载参数的指令是Ldarg.Ldarg_S.Ldarg_0.Ldarg_1.Ldarg_2.Ldarg_3.Ldarg_0是加载第0个参 ...
- EF的3种开发模式
那么明显开发模式是三种. 即:DateBase First(数据库优先).Model First(模型优先)和Code First(代码优先). 当然,如果把Code First模式的两种具体方式独立 ...
- 体验SpringCloud Gateway
Spring Cloud Gateway是Spring Cloud技术栈中的网关服务,本文实战构建一个SpringCloud环境,并开发一个SpringCloud Gateway应用,快速体验网关服务 ...
- Java连载26-方法(语法结构)
一.方法 1.返回值类型如果不是void,表示这个方法执行结束之后必须返回一个具体的数值,当方法执行结束的时候没有返回任何数值,编译器会报错,怎么返回值呢?并且要求“值”的数据类型必须和“方法的返回值 ...
- Keras 实例 MNIST
import numpy from keras.datasets import mnist from keras.models import Sequential from keras.layers ...
- 【selenium】- webdriver常见元素定位(中)
本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1.By.tagName 遇到hidden就break,继续下一个循环. 2.By.linkText 对上图中的“糯米”进行定位: 3.By. ...
- zstuoj 4423: panda和卡片
传送门:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4423 题意: 给定许多数字,这些数字都是2的倍数,问可以用这些数字组成多少个数字. ...