JS的this指向问题

一、全局环境下的 this

永远指向window

    <script>
      console.log(this); //window
    </script>

#二、函数中的this

2.1、作为普通函数被调用时

this指向调用该函数的对象

  • this指向全局对象window
  • 严格模式下 this是undefined
function fn() {
  console.log(this); //window
}
fn();
//相当于window.fn()


function fn() {
  "use strict";
  console.log(this); //undefined
}
fn();

2.2、作为对象的方法被调用

this指向调用该函数的对象

let obj = {
  age: 18,
  fn: function () {
    console.log(this === obj); //true
    console.log(this.age); //18
  },
};
obj.fn()

2.3、作为构造函数被调用时

构造函数里的this指向new创建的实例对象

构造函数的原理(new之后发生了什么)

官方解释:

  1. 创建一个空的简单JavaScript对象(即{});
  2. 为步骤1新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;
  3. 将步骤1新创建的对象作为this的上下文 ;
  4. 如果该函数没有返回对象,则返回this

咱们的总结:

1、自从用new调用函数后,JS引擎就会在内存中创建一个空对象{}const newObj = {};
2、将新对象newObj的__proto__属性链接至构造函数的原型对象 newObj.__proto__ = FunctionName.prototype
3、构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)this = newObj
4、执行构造函数内部代码;
5、如果该函数没有返回对象,则默认返回this。

2.4、定时器函数里面的this

//this指向window 实际上为window.setTimeout(),也是指向函数的调用者
setTimeout(function () {
  console.log("定时器的this" + this); //window
}, 1000);

定时器函数的调用,实际上是window.setTimeout(),因此定时器函数的this指向window

2. 5、立即执行函数里面的this

//6.立即执行函数  this指向window  相当于普通函数,只是不需要手动调用
(function () {
    console.log('立即执行函数的this' + this); //window
})();

2.6、绑定事件函数里面的this

this指向调用该函数的对象

//4.绑定事件函数
let btn = document.querySelector("button");
btn.onclick = function () {
  console.log("绑定事件的this" + this); // 指向btn 也是指向函数的调用者
};

绑定事件的函数,同样遵循谁调用,this指向谁的原则,在这里是btn绑定了点击事件,因此这里的this指向函数的调用者btn

2.7、箭头函数里面的this

  • 在js中有全局作用域,函数作用域,块级作用域
  • 箭头函数里面没有自己的this,箭头函数的this跟箭头函数所在作用域里面的this一致

2.7.1、箭头函数定义在函数中

<script>
    function fn() {
        return () => {
            console.log(this);
        }
	}
    let test = fn()
    test()//window
</script>

箭头函数定义在fn函数作用域内,则箭头函数的this与所在作用域的this指向一致,而普通函数的this指向全局window对象,则该箭头函数也指向window

2.7.2、箭头函数定义在对象中

<script>
    let obj = {
        name: 'cirrod',
        play: () => {
            console.log(this);
        }
    }
	console.log(obj.play()); //window全局对象
</script>

play箭头函数定义在对象中,而在js中只有全局作用域,函数作用域,块级作用域,没有对象作用域,所以相当于箭头函数定义在全局作用域中,箭头函数的this与所在作用域的this指向一致,所以this指向全局对象window

2.7.3、箭头函数定义在对象的方法中

<script>
let obj = {
    name: 'cirrod',
    fn: function() {
        return {
            play: () => {
                console.log(this);
            }
        }
	}
}
let obj1 = obj.fn();
console.log(obj1.play());//obj这个对象
</script>

箭头函数定义在fn函数的返回对象中,而对象没有作用域,则向上一层查找fn函数,相当于箭头函数定义在fn函数的作用域内,fn函数的this指向自己所属的对象obj,箭头函数的this与所在作用域的this指向一致,所以箭头函数的this指向为obj

2.7.4、箭头函数定义在定时器中

2.7.4.1、定时器在全局作用域中
<script>
    setTimeout(() => {
        console.log(this); // window
    }, 100)
</script>

箭头函数定义在定时器的参数上,定时器的参数没有作用域,向外一级是全局作用域,相当于箭头函数定义在全局作用域,箭头函数的this与所在作用域的this指向一致,所以箭头函数的this指向为window

2.7.4.2、定时器在函数作用域
<script>
    function Person(name) {
        this.name = name
        setTimeout(() => {
            console.log(this); // cirrod这个实例对象
        }, 100)
    }
    const cirrod = new Person('杨某某')
</script>

箭头函数定义在定时器的参数上,定时器的参数没有作用域,向外一级是构造函数的作用域,相当于箭头函数定义在构造函数的作用域,而构造函数的this指向实例对象,箭头函数的this与所在作用域的this指向一致,所以箭头函数的this指向为构造函数的实例对象cirrod

三、总结

image.png

四、如何更改this指向

call,apply和bind方法都可以用来更改this指向

区别

  • call、apply 在改变 this 指向的同时还会执行函数,一次性的。
    不同的是 call方法传递函数调用形参是以散列形式,而 apply 方法的形参是一个数组。在传参的情况下,call的性能要高于 apply,因为 apply 在执行时还要多一步解析数组。
  • bind 在改变 this 后是返回一个全新的绑定函数,即返回一个新的函数,不直接执行函数。并且此后 this 的指向无法再次通过 call、apply、bind 改变。

4.1、call

使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数

function.call(thisArg, arg1, arg2, ...)

[thisArg] 在 func 函数运行时使用的 this 值。请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装

[arg1, arg2, …] 参数列表

例子

let objCall = {
  name: "我是 Call",
};
function fn() {
  console.log("参数 => ", ...arguments);
  console.log("name => ", this.name);
}
fn.call(objCall, 1, 2, 3);
// 参数 =>  1 2 3
// name =>  我是Call

4.2、apply

调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数

func.apply(thisArg, [argsArray])
[thisArg] 必选的 同 call 一样
[argsArray] 可选的

例子

let objApply = {
  name: "我是 Apply",
};
function fn() {
  console.log("参数 => ", ...arguments);
  console.log("name => ", this.name);
}
fn.apply(objApply, [1, 2, 3]);
// 参数 =>  1 2 3
// name =>  我是 Apply

4.3、bind

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

function.bind(thisArg,arg1,arg2,arg3,....)

例子

let objBind = {
  name: "我是 Bind",
};
let objApply = {
  name: "我是 Apply",
};

function fn() {
  console.log("参数 => ", ...arguments);
  console.log("name => ", this.name);
}
let bfn = fn.bind(objBind, 1, 2, 3);
//需要自己主动执行
bfn();
// 参数 =>  1 2 3
// name =>  我是 Bind
  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值