• 关于this


    在这里插入图片描述

    参考阮一峰老师对于this的原理理解

    一:this的定义

    严格模式下非严格模式下this的在全局中会有差别

    来自阮一峰老师对于this的由来的理解

    由于函数可以在不同的运行环境中运行,所以需要一种机制,能够在函数的内部获取当前运行环境,因此this就出现来,this的设计目的就是为了在函数的内部,指代函数当前的运行环境

    所以在绝大多数的情况下,函数当前的运行环境决定了this的值

    例如:

       var obj = {
          foo: function () { console.log(this.bar) },
          bar: 1
        };
    
        var foo = obj.foo;
        var bar = 2;
    
        obj.foo() // 1
        foo() // 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 对于obj.foo()来说,是通过obj这个对象来找到foo(),所以foo()的运行环境obj对象,因此this的值就是Obj对象
    • 对于foo()来说,foo()函数的运行环境是window,因此this的值就是window
    • image-20230911205503092

    二:绑定规则

    根据不同的使用场合,this有不同的值,主要分为下面几种情况:

    • 默认绑定
    • 隐式绑定
    • new绑定
    • 显示绑定

    1. 默认绑定

    默认绑定的意思就是,当函数独立执行,不作为一个对象的方法调用时,this绑定到全局对象中,但在严格模式下this会绑定到undefined

        function foo ()
        {
          console.log(this); // 在浏览器中通常指向 window 对象
        }
    
        foo();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. 隐式绑定

    当函数作为对象的方法调用时,this 绑定到调用该方法的对象

        var obj = {
          foo: function () { console.log(this) },
          bar: 1
        };
    
        var foo = obj.foo;
    
        obj.foo() // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

        var obj = {
          a: {
            foo: function () { console.log(this) },
          },
          bar: 1
        };
    
    
        var foo = obj.foo;
        var bar = 2;
    
        obj.a.foo() 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    foo执行的环境是a对象,所以this指向a对象

    image-20230911210131323

    再例如:

        var obj = {
          a: {
            bar: 1,
            foo: function ()
            {
              console.log(this.bar);	//2
              console.log(this)			//window
            },
          },
    
        };
    
        var bar = 2;
    
        const fn = obj.a.foo	
        fn()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 在该代码中,定义了一个变量fn,被将其赋值为obj.a.foo,这意味着fn现在引用了,obj对象中,a属性的foo方法。

    • 最后调用fn(),执行foo()函数

    • obj.a.foo复制给fn,只是将foo函数的引用复制给了fn,但并没有立即执行。所以fn只是函数的引用,它的上下文还是跟obj.a.foo相关

    • 但是当调用fn()时,这才是真正执行foo函数的时候,但由于fn是在全局上下文中调用的,JS将函数上下文this赋值为window

    3. 显示绑定

    使用 call()apply()bind() 方法显式地指定函数的 this 值。

        var obj = {
          foo: function () { console.log(this.bar) },
          bar: 1
        };
    
        var obj2 = {
          bar: 100
        }
    
        obj.foo.call(obj2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    image-20230911212217170

    4. new 绑定

    当函数用作构造函数(使用 new 关键字创建对象)时,this 绑定到新创建的对象。

        function fn ()
        {
          this.bar = 1
        }
    
        var obj = new fn()
        console.log(obj.bar);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 通过new关键字改变了this的执行,指向了obj

    当函数返回一个对象

        function fn ()
        {
          this.bar = 1
          return {
            bar: 10
          }
        }
    
        var obj = new fn()
        console.log(obj.bar);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 当函数返回一个对象时,通过new关键字将this指向改变指向返回的对象,不指向obj
      • image-20230911212816249

    当返回一些简单类型时候

        function fn ()
        {
          this.bar = 1
          return true
        }
    
        var obj = new fn()
        console.log(obj.bar);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • this还是指向obj

    返回null

        function fn ()
        {
          this.bar = 1
          return null
        }
    
        var obj = new fn()
        console.log(obj.bar);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 虽然null是object类型
    • 但是还是指向obj

    三:箭头函数

    JS中箭头函数与普通函数在this上有着重要的不同。

    箭头函数this的绑定是在箭头函数创建的时候就确定的好的,是静态this绑定,它没有自己的上下文,它会捕获最近的普通函数的this

    普通函数this值取决于,函数是如何被调用的,是根据调用方式动态确定的

    在全局上下文中

        var a = 1
        const fn = () =>
        {
          console.log(this.a);
        }
        fn()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20230911214426329

    • fn箭头函数会自动捕获最近的最近的普通函数上下文,通常是全局对象window

    在对象方法中

        var a = 10
        const obj = {
          a: 1,
          fn: () =>
          {
            console.log(this.a);
          }
        }
        obj.fn()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20230911214641724

    • fn箭头函数的this值不取决于被调用时动态绑定,而是在静态创建时候,与最近最近的普通函数上下文this值一致
    • fn箭头函数最近最近的普通函数上下文是window全局
    • 因此this指向window

    作为事件回调

      <button id="btn">点击button>
    
    • 1
    
        const btn = document.getElementById('btn')
        var a = 10
        const obj = {
          a: 1,
          fn: () =>
          {
            console.log(this.a);		// 10
          }
        }
        btn.addEventListener('click', obj.fn)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 点击按钮输出还是10
    • 箭头函数作为回调函数时,其 this 绑定通常与定义它的上下文相同。

    四:优先级

    1. 隐式绑定 VS 显示绑定

    function foo() {
        console.log( this.a );
    }
    
    var obj1 = {
        a: 2,
        foo: foo
    };
    
    var obj2 = {
        a: 3,
        foo: foo
    };
    
    obj1.foo(); // 2
    obj2.foo(); // 3
    
    obj1.foo.call( obj2 ); // 3
    obj2.foo.call( obj1 ); // 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 显示绑定优先级要高于隐式绑定

    2. new绑定 VS 显示绑定

    function Person(name) {
      this.name = name;
    }
    
    const alice = new Person("Alice");
    const person = { name: "Bob" };
    
    const boundGreet = greet.bind(person);
    const aliceWithBinding = new boundGreet(); // 使用 new 绑定,this 绑定到新对象 aliceWithBinding
    console.log(aliceWithBinding.name); // 输出: undefined,因为 new 绑定覆盖了显式绑定
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • new 绑定的优先级更高。当使用 new 关键字创建对象实例时,它会覆盖之前的显式绑定
  • 相关阅读:
    【数据结构】树形结构——树的定义和术语
    hackmyvm之gift
    Java14-线程、同步
    LabVIEW数据采集-数字I/O/计数器
    KT148A语音芯片SOP外挂功放芯片8002D的说明_V1
    网址静态码手机制作教程,附图文详解!
    cpp占位参数在重载运算符中的作用
    通过docker-compose部署elk日志系统,并使用springboot整合
    娄底可靠性检测实验室建设知识概述
    Preview(2021-2022年度第三届全国大学生算法设计与编程挑战赛(夏季赛)——正式赛——E)
  • 原文地址:https://blog.csdn.net/Czc1357618897/article/details/132818518