• JavaScript高级 |彻底搞清this指向问题


    本文已收录于专栏
    ⭐️ 《JavaScript》⭐️

    this指向问题

    this 指向问题 一般情况下 this 的最终指向是那个调用它的对象。

    ①在全局作用域下或者普通函数中 this 指向全局对象window,包括定时器。

    因为在全局作用域下,变量和函数都是window的属性或者方法,所以也就是说他们的调用者就是 window。

    console.log(this)
    
    • 1
    function fun(){
    	console.log(this);
    }
    本质:
    window.function fun(){
    	console.log(this);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    setTimeout(function(){
    	console.log(this);
    },1000);
    
    本质:
    window.setTimeout(function(){
    	console.log(this);
    },1000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ②方法调用中:谁调用this就指向谁。

    调用对象o里面的方法

    this指向对象o

    var o = {
      sayHi:fuction(){
      console.log(this);
      //this 指向的是 o 这个对象
    }
    }
    o.sayHI();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    调用 btn 按钮对象

    this 指向的是 btn

    var bth = document.querySelector('button');
    
    //传统注册事件方法
    btn.onclick = function(){
      console.log(this);
    }
    
    //事件监听
    btn.addEventListener('click',function(){
      console.log(this);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ③构造函数中this指向构造函数中的实例。

    在构造函数里调用this

    指向的是 Fun的实例对象 fun

    function Fun(){
      console.log(this);
    }
    var fun = new Fun();
    
    • 1
    • 2
    • 3
    • 4

    this 绑定规则

    默认绑定

    独立函数调用都是指向 window

    “ 独立的函数调用 ” 我们可以理解成:函数没有被绑定到某个对象进行调用。

    1. 普通函数被独立调用

    window是它的绑定对象

    function foo(){
    	console.log("foo:",this);
    }
    foo();
    
    • 1
    • 2
    • 3
    • 4
    1. 函数定义在对象里,但是被单独调用

    在 ②这种情况中 虽然函数定义在了对象里面,但还是被单独调用,所以此时this 的绑定对象 仍是 window
    在 ①这种情况中 函数定义在了对象里面,而且是被对象调用的,所有此时this 的绑定对象是 object
    所以 this 的绑定对象,与函数的声明位置没有关系。

    var obj = {
      name:"why",
      bar:function(){
        console.log("bar:",this)
      }
    }
    ① obj.bar() 
    //此时 this 指向的是 objectvar baz = obj.bar
    baz();
    // 此时 this 指向的是 window
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 严格模式下,独立调用的函数中的this 指向都是undefined

    一般打包工具会自动将js文件设置成 严格模式,这样可以规避一些低级错误。

    "use stric"
    
    function foo(){
    	console.log("foo:",this);
    }
    foo();
    
    var obj = {
      name:"why",
      bar:function(){
        console.log("bar:",this)
      }
    }
     var baz = obj.bar
    baz();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结:

    • this 代替 window会比较危险,所以建议直接window来写。
    • 独立函数调用都是指向 window 的!
    function foo(){
    	console.log("foo:",window);
    }
    foo();
    
    • 1
    • 2
    • 3
    • 4

    隐式绑定

    通过某个对象进行调用,即调用位置是某个对象发起的函数调用。

    前提:必须在调用的对象内部有一个函数的引用,(比如一个属性)

    简单来说就是:将函数赋值给了对象的某个属性,然后通过调用对象的这个属性的方式调用函数就是隐式绑定

    function foo(){
    	console.log("foo函数:",this);
    }
    
    var obj = {
    	bar:foo
      //将上面声明的那个 foo()函数 赋值给这个 bar 属性
    }
    
    obj.bar();
    // 调用 obj  对象中的 bar 属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    显式绑定

    与隐式绑定不同,显式绑定是通过call()等方法调用自己指定好的this指向的函数。

    var obj = {
      name:"why";
    }
    
    function foo(){
      console.log("foo函数"this}
    // 执行函数,并且强制 this 指向 obj 对象
    foo.call(obj)
    
    // 可以将 this 指定为 任意对象
    foo.call("123")
    foo.call(“abc”)
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    实现显式绑定的两个方法

    function foo(name,age,height){
      console.log("foo函数被调用"this);
      console.log("打印参数",name,age,height);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    apply()

    语法:

    foo.applay("apply",["shenqi",18,1.55]);
    
    • 1
    • 第一个参数:this 所绑定的对象。例子中 this 绑定的对象为 ‘apply’这个字符串。
    • 第二个参数:额外的实参,需要以数组的形式传入
    • foo.applay(“apply”,[“shenqi”,18,1.55]);
    call()

    语法:

    foo.call("call","shenqi",18,1.55);
    
    • 1
    • 第一个参数:this 所绑定的对象。例子中 this 绑定的对象为 ‘call’这个字符串。
    • 参数列表:后续的参数以多参数的形式传递
    • foo.call(“call”,“shenqi”,18,1.55);

    总结:第一个函数是相同的,参数均为this所需要指定的对象,后面的参数,apply为数组,call为参数列表.

    bind()

    我们发现 如果我们想多次调用指定好this指向的函数时都需要调用 apply或者 call。

     foo.applay(); 
     foo.applay(); 
     foo.applay(); 
     foo.applay(); 
     foo.applay(); 
     foo.applay(); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    有没有什么方法可以一劳永逸呢?
    bind 便应运而生。
    bind本质是 根据调用函数与指定的obj对象生成了一个新的函数,使得指定的obj 对象总绑定在 新的函数上。
    独立函数的优先级低的,所以一定是 先执行bind方法绑定之后独立函数才会被执行

    var bar = foo.bind()
    bar()
    bar()
    bar()
    bar()
    bar()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    bind方法创建的新的绑定函数(EF)是一个怪异函数对象

    new绑定

    JavaScript 中的函数可以当做一个类的构造函数来使用,也就是new关键字。
    new 之后发生了什么?

    • 创建新的空对象F。
    • 将this指向这个空对象。
    • 指向函数体中的代码。
    • 没有显式返回非空对象时,默认返回这个对象。
    function foo(){
      this.name = "shenqi"
      console.log("foo函数",this// 此时this 就是指向 默认创建的 全新的空对象 
    }
    new foo()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    内置函数的绑定思考

    有时候,我们会调用一些JavaScript的内置函数,或者一些第三方库中的内置函数。

    • 这些内置函数会要求我们传入另一个函数
    • 我们自己并不会显式了调用这些函数,都是当事件被触发后JS内部或者第三方库内部帮我们执行;
    • 这些函数中的this又是如果绑定的呢?

    需要依靠
    image.png

    绑定优先级

    1. 默认绑定的优先级最低
    2. 显式绑定的优先级高于隐式绑定

    image.png
    this 指向:“abc”
    在这里插入图片描述

    this 指向 :“aaa”

    1. bind 的优先级高于 apply、call

    image.png
    this指向:“aaa”

    1. new绑定的优先级高于隐式绑定

    image.png
    this指向:一个空对象 和 false

    1. new绑定的优先级高于bind

    在这里插入图片描述
    this指向:一个空对象

    1. new和 call、apply是不允许一起使用的,没有可比性。

    总结:new>bind>call=apply>默认绑定。
    注意:new和 call、apply是不允许一起使用的,没有可比性。

    完结散花

    ok以上就是对 JS高级篇 |彻底搞清this指向问题 的全部讲解啦,很感谢你能看到这儿。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。

    参考文献

    coderwhy老师JS高级视频教程

  • 相关阅读:
    一、react简介
    贪心算法之装箱问题
    英语读书笔记-Book Lovers Day 10
    Nginx核心要领十五:离线安装Nginx
    2023Fall美高选校必看!敏思跃动独家发布美国私立寄宿高中选校分级表
    SQL Server 解析JSON复杂的多层级示例
    10K起步的软件测试岗到底需要学什么?零基础进阶自动化测试需要哪些技术...
    gstreamer registry文件
    集成swagger 简单版
    Oracle中ALTER TABLE的五种用法(三)
  • 原文地址:https://blog.csdn.net/m0_66139206/article/details/126807517