zoukankan      html  css  js  c++  java
  • 常规函数和箭头函数的this绑定问题

    核心要点

    function(){} 和 () => {} 的最大区别在于前者会在运行时绑定this对象,后者不会

    由于function(){}在运行时在内部自动绑定this对象,则不会访问外部作用域this
    由于() => {}不能自动绑定this对象,则只能访问外部作用域this

    如果要使用动态绑定的this,则使用function(){}
    如果要使用外部作用域的this,则使用() => {}

    估计ES6就是因为function(){}总是自动绑定this造成嵌套function时需要let self = this,然后需要在内层function使用self.xxx调用外层this,才新添加了一个不会自动绑定this的函数:箭头函数 () => {}

    function(){}的this绑定规则

    function(){}在运行时(被调用的时候)会基于绑定规则动态进行this绑定

    有两点强调:

    • this是在运行时绑定的,不是定义时
    • 要看this的指向,关键在于看函数调用的位置和方式

    根据函数调用位置和方式不同,有四种绑定策略

    1.默认绑定
    如果直接调用函数,则将this绑定到全局对象,在Node中是global,在浏览器中是window

    function foo () {
        console.log(this)
    }
    
    // 运行时绑定
    foo()
    

    2.隐式绑定
    如果有上下文对象调用函数,则将this绑定到上下文对象

    const obj = {
        foo: function () {
            console.log(this)
        }
    }
    
    // 运行时绑定
    obj.foo()
    

    3.显式绑定
    通过调用函数的call,apply,bind方法进行绑定

    function foo () {
        console.log(this);
    }
    const obj = { a: 1 }
    
    // 运行时绑定
    foo.call(obj)
    foo.apply(obj)
    foo.bind(obj)()
    

    4.new绑定
    new的过程也叫函数的“构造调用”,经历了以下几个步骤:
    1. 创建一个空对象obj
    2. 将对象obj的Prototype关联到构造函数的Prototype
    3. 将对象绑定到构造函数的this
    4. 如果构造函数没有返回对象,则返回对象obj

    function Foo () {
        console.log(this);
    }
    
    // 运行时绑定
    foo = new Foo()
    

    常见场景归纳

    1.对象方法定义:使用function(){} 以获得this绑定
    2.回调函数场景:使用() => {} 以访问外部作用域this

    const dog = {
        name: "旺仔",
        eat: function (callback) {
            // 这里的this采用隐式绑定策略
            // 因为调用方式是this.eat() (run和sleep方法中)
            setTimeout(() => {
                console.log(`${this.name}吃饱了`)
                callback()
            }, 3000);
        },
        run: function () {
            // 这里的this无法进行绑定,只能从外层作用域获得,在这里指向最外层(模块级别)this
            // 在node中模块级别this指向module.exports
            // node是模块化的,模块本身存在独立作用域,要和浏览器的全局概念区分
            this.eat(() => {
                console.log(`${this.name}开始跑步`);
            })
        },
        sleep: function () {
            // 这里的this采用默认绑定策略
            // 因为调用方式是callback() (eat方法中)
            this.eat(function () {
                console.log(`${this.name}准备睡觉`);
            })
        }
    }
    
    dog.run()
    // 旺仔吃饱了
    // 旺仔开始跑步
    dog.sleep()
    // 旺仔吃饱了
    // undefined准备睡觉
    

    3.事件监听场景:使用function(){} 以获得this绑定

    // 事件监听器调用仍然是上下文调用,socket.handle()
    socket.on('data', function handle () {
        console.log(this)
    })
    
  • 相关阅读:
    2010.10.10 第九课 函数(二)(递归)(汉诺塔)
    2020.10.8第八课函数(一)(4种函数)
    2020.9.29 第七课 字符串函数与字符数组
    2020.9.26第六节课数组
    2020.9.22 第四课 运算符表达式和语句
    2020.9.19 第三课 字符串格式化输出与输入
    2020.9.17 第二课 C语言中数据类型 2,8,10进制转换 计算机内存数值存储方式(补码转换)
    2020.9.15 第一课,概念
    spring架构解析--入门(一)
    JAVA对象实例化方式总结
  • 原文地址:https://www.cnblogs.com/Peter2014/p/12168456.html
Copyright © 2011-2022 走看看