• this的指向问题


    一、非箭头函数

    关于 this 的指向,记住最核心的一句话: 哪个对象调用函数,函数里面的this指向哪个对象。

    (一)全局环境

    全局环境中(在任何函数体外部)this都指向全局对象

    //浏览器环境 Window对象即是全局对象
    console.log(this === window); // true
    //node环境 由于模块化node中this指向module.exports node的全局对象为global
    console.log(this === module.exports); // true
    

    (二)普通函数

    在函数内部,this的值取决于函数被调用的方式。此外,在严格模式和非严格模式之间也会有一些差别

    非严格模式

    ——非严格模式下,this指向window

    var name = "xiaoyu"
    function fn() {
        var name = "小鱼"
        console.log(this.name)
    }
    fn() //xiaoyu
    

    严格模式

    1. 严格模式下,this将保持进入执行环境时的值
    2. 没有被执行环境(execution context)定义,this保持为 undefined
     "use strict"
    var name = "xiaoyu"
    function fn() {
        var name = "小鱼"
        console.log(this)
        console.log(this.name)    
    }
    fn() //Cannot read property 'name' of undefined
    

    (三)对象方法

    ——对象方法 this指向该方法所属对象

    var name = "xiaoyu"
    var object = {
        name: "小鱼",
        sayHi() {
            console.log(this.name)
        }
    }
    object.sayHi()	//小鱼
    

    (四)构造函数

    ——构造函数的this 指向创建出来的实例对象

    ——new实例对象的过程改变this指向

    var name = "xiaoyu"
    function Person() {
        this.name = "小鱼"
        console.log(this); //Person {name: "小鱼"}
    }
    var person = new Person() 
    

    (五)绑定事件函数

    ——事件绑定的处理函数 this指向函数的调用者 (绑定该函数的元素)

    <button>点击</button>
    <script>
        var btn = document.querySelector('button')
        btn.onclick = function() {
            console.log('事件处理函数的this:' + this)
            //事件处理函数的this:[object HTMLButtonElement]
            console.log(this) //<button>点击</button>
        }
    </script>
    

    (六)定时器函数

    ——定时器函数 this指向window

    window.setTimeout(function(){
        console.log('定时器函数中this:' + this)
        //定时器函数中this:[object Window]
        console.log(this) //window
    }, 1000)
    

    (七)立即指向函数

    ——立即执行函数 this指向window

    (function() {
        console.log('立即执行函数中this' + this)
        //立即执行函数中this[object Window]
        console.log(this) //window
    })()
    

    (八)匿名函数

    ——匿名函数的执行环境是全局性的

    var name = 'xiaoyu'
    var person = {
        name :'小鱼',
        sayName:function () {
            return function () {
                console.log(this.name) 
            }
        }
    }
    person.sayName()()  //xiaoyu
    

    小结

    函数调用方式 函数内部this的指向
    普通函数调用 window
    对象方法调用 该方法所属的对象
    构造函数调用 创建的实例对象
    事件绑定方法 绑定事件的的对象
    定时器函数 window
    立即执行函数 window
    匿名函数 window

    二、箭头函数

    箭头函数出现的意义:让函数表达更简洁,增强可读性;解决匿名函数、setTimeout和setInterval的回调函数 this 指向的问题

    箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”

    var name = "xiaoyu"
    var object = {
        name: "小鱼",
        sayHi: () => { console.log(this.name) }
    }
    object.sayHi()	//xiaoyu this继承自父执行上下文
    

    三、 改变this的指向

    var name = "xiaoyu"
    var obj = {
        name: "小鱼",
        fn: function() {
            setTimeout( function() {
                console.log(this.name)
            }, 0)
        }
    }
    obj.fn() //xiaoyu
    

    (一)使用that保存this变量

    var name = "xiaoyu"
    var obj = {
        name: "小鱼",
        fn: function() {
            var that = this;
            setTimeout( function() {
                console.log(that.name)
            }, 0)
        }
    }
    obj.fn() //小鱼
    

    (二)使用 call apply bind

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用

    返回值:改变this指向的原函数拷贝

    var name = "xiaoyu"
    var obj = {
        name: "小鱼",
        fn: function() {
            setTimeout( function() {
                console.log(this.name)
            }.bind(obj), 0)
        }
    }
    obj.fn() //小鱼
    

    (三)new 实例

    使用new创建新对象的过程

    1. 创建一个空对象
    2. 将构造函数的作用域赋值给该对象 (将this绑定在刚创建的对象上)
    3. 执行构造函数的代码,为该对象添加属性
    4. 返回一个新的的对象
    var Person = function(name, age) {
        this.name = name;
        this.age = age;
    };
    Person.prototype.show = function() {
        console.log(this.name, this.age);
    };
    var p = new Person("xiaoyu", 18);
    console.log(p);
    

    (四)箭头函数

    var name = "xiaoyu"
    var obj = {
        name: "小鱼",
        fn: function() {
            setTimeout( () => console.log(this.name), 0)
        }
    }
    obj.fn() //小鱼
    

    四、面试题

    var baz = 0;
    let foo = {
        bar:function() {
            console.log(this,this.baz); 
            return this.baz;
        },
        baz:1
    };
    let foo2 = {
        baz:2
    };
    
    let a = foo.bar();  
    //作为对象的方法调用,this指向调用函数的对象,即foo
    let b = foo.bar.call(foo2); 
    //使用call方法将this绑定到第一个参数对象向,此时,this指向foo2
    let fn = foo.bar;
    let c = fn(); 
    //let fn创建的对象,此时,fn = function(){...},此时函数执行时,默认指向全局window对象
    let d;
    (function test(){
      d = arguments[0]()
    })(foo.bar);  
    // arguments.callee包括了一个函数的引用去创建一个arguments对象,它能让一个匿名函数很方便的指向本身,即此时this指向arguments类数组对象
    
    console.log(a,b,c,d)  //1 2 0 undefined
    

    参考文章

    https://juejin.im/post/59bfe84351882531b730bac2#heading-2

  • 相关阅读:
    vlookup函数的使用方法
    sql去重常用的基本方法
    Mybatis中的foreach
    readonly和disable的区别是什么?
    sql的删除语句
    项目升级步骤
    【Azure 事件中心】Azure Event Hub中的数据能不能存储大于7天呢?如果7天之后是不是会自动删除呢?
    【Azure 存储服务】存储在Azure Storage Table中的数据,如何按照条件进行删除呢?
    【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
    【Azure Developer】使用Python代码获取VM的IP地址 (Public IP + Private IP)【未解决问题标签】
  • 原文地址:https://www.cnblogs.com/zengbin13/p/12905217.html
Copyright © 2020-2023  润新知