zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    并发编程的艺术
    Redis字符串实现,SDS与C的区别,空间预分配
    Jvm
    Redis数据结构的实现
    发一篇感谢身边的所有从事it工作的朋友
    BeanFactory 默认的注入实现类DefaultListableBeanFactory
    jsSwitch语句优化
    彻底搞懂 Nginx 的五大应用场景
    Spring Boot 整合 Quartz 轻松实现任务调度!
    js计算两个给定日期之间的天数
  • 原文地址:https://www.cnblogs.com/qixingduanyan/p/11548314.html
Copyright © 2011-2022 走看看