this的指向及改变this指向的方法

心语:我还是很喜欢你,像从一场温暖至极的梦中醒来,只留叹息;我还是很喜欢你,像大海退潮后的礁岩,无处遁形。

在 JavaScript 编程中,this 关键字总是让初学者感到迷惑,而且this也是在面试过程中常会被问起的一个热词,那么接下来,就让我们一起探讨这个问题。

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,函数的调用方式决定了 this 的指向不同。
JavaScript 的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境

上面可能说的比较你难以理解,我举个例子吧,比如在日常生活中,别人让你帮他去那个超市买个东西,那么那个超市,就会很含糊,因为你不知道那个超市到底指的是那个超市,在不同的场景下,超市会不一样,这就相当于this,它也会根据不同的场景下指向不同。
接下来,让我们看看都有哪些常见的场景呢?

  • 普通函数调用, this 指向 window
var name="幕筱佳";
  function foo() {
       console.log(this);   // window
       console.log(this.name);   // 幕筱佳,因为this指向window,而name会挂载在window下,作为window的一个属性
     }
foo();  //  window.fn(),此处默认省略window
  • 对象方法调用, 此时 this 指向 该方法所属的对象
var obj = {
	   name:"幕筱佳",
       eat: function () {
         console.log(this); // obj
       }
     }
  obj.eat();
  • 通过事件绑定的方法, 此时 this 指向绑定该事件的对象
<body>
    <button id="btn">点我一下</button>
<script>
    var btn = document.getElementById("btn");
    btn.onclick = function() {
        console.log(this); // btn
    }
</script>
</body>
  • 定时器函数, this 指向 window
setInterval(function () {
       console.log(this); // window
     }, 1000);
  • 构造函数调用,此时 this 指向该实例对象
function Person(age, name) {
         this.age = age;
         this.name = name
         console.log(this)  // 此处 thisPerson的实例对象p1
     }
    var p1 = new Person(18, '幕筱佳')
  • 箭头函数中,this的指向取决于上层函数的this的指向,因为箭头函数是没有自己的this的
var obj = {
    name: '幕筱佳',
    sayName: function(){
        return () => {
            console.log('name:', this.name);
        }
    }
}
obj.sayName()()          // 幕筱佳

对于上面这种情况,箭头函数会向上找寻上层的this来作为自己的this指向,那么将会指向
sayName函数,而sayName函数的this指向的是obj这个对象,则此时,this就会指向obj对象。

总结:
1.以上常见的场景都是在非严格模式下适用,而在严格模式中的默认的this不再是window,而是undefined
2.在非箭头函数中,this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的

那么我们如果想改变this的指向,到底该怎么办呢?接下来让我们看看改变this指向常用的几种方法

1. call()

var Person = {
        name:"幕筱佳",
        age:18
    }
function foo(name,age){
     console.log(this.age,this.name);    //this指向window
    }  
    foo.call(Person,"幕筱佳丶",20);  //通过call将this指向Person对象

2. apply()

var Person = {
        name:"幕筱佳",
        age:18
    }
function foo(name,age){
     console.log(this.age,this.name);    //this指向window
    }  
    foo.call(Person,["幕筱佳丶",20]);  //通过call将this指向Person对象

如果我们仔细观察的话,可能会发现其实call()跟apply()这两种方法其实很相似,不同之处在于提供参数的方式,call() 使用对象罗列的方式,apply()使用参数数组,而不是参数列表

3. bind()

bind()创建的是一个新的函数(称为绑定函数),参数第一个this,第二个是传递的参数,但是此函数调用,不会马上执行,而不像call()跟apply()去主动调用改变this的指向。

var person = {
	name:"幕筱佳",
	age:18
}
function getInfo() {
	return ()=>{
		return `${this.name}今年${age}岁了`
	}
}.bind(person)    
var info=getInfo()   //幕筱佳今年18岁了

4.new关键字改变this指向

//构造函数版this
function Foo(){
    this.name= "追梦子";
}
var user = new Foo();
console.log(user.name); //追梦子

使用new关键字实例化一个对象时,此时构造函数中的this会指向该实例对象。相当于Foo会被复制一份,此时this将会指向新的实例对象user

最后,我顺便说一下当new一个构造函数时,都发生了什么,这也是一个高频面试题。

1.创建了一个空的对象
2.new会让this指向这个新对象
3.构造函数调完后,给这个新对象加属性和方法
4.new会返回这个新对象

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值