this的指向问题

本文详细解析了JavaScript中的this指向问题,包括全局作用域、方法调用、构造函数、箭头函数、call/apply/bind的使用,以及定时器函数中的this行为。通过对各种场景的分析,帮助读者掌握this的关键概念,提升JavaScript编程技能。
摘要由CSDN通过智能技术生成

js 中的 this 指向十分重要,在我们的工作和面试中也会时常遇到,倒是对this,总是不太了解,今天我来带大家系统的了解和学习一下。

一、this的指向

this 总是(非严格模式下)指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境;

this的指向大体分为以下几种情况:

1、全局作用域和普通函数调用,此时 this 指向 window

当函数不作为对象的属性被调用,而是以普通函数的方式,this总是指向全局对象(在浏览器中,通常是Window对象)

//直接打印
console.log(this) //window

//function声明函数
function bar () {console.log(this)}
bar() //window

//function声明函数赋给变量
var bar = function () {console.log(this)}
bar() //window

//自执行函数
(function () {console.log(this)})(); //window

2、方法调用中谁调用 this 指向谁 

(1)、构造函数调用, 此时 this 指向 实例对象

当函数作为对象的方法被调用时,this指向该对象

 function Person(age, name) {
         this.age = age;
         this.name = name
         console.log(this)  // 此处 this 分别指向 Person 的实例对象 p1 p2
     }
    var p1 = new Person(18, 'zs')//Person {age: 18, name: 'zs'}
    var p2 = new Person(18, 'ww')//Person {age: 18, name: 'ww'}

(2)、对象方法调用, 此时 this 指向 该方法所属的对象

当对象内的方法调用时,this指向该对象

 var obj = {
       fn: function () {
         console.log(this); // obj
       }
     }
    obj.fn();//{fn: ƒ}

(3)、通过事件绑定的方法, 此时 this 指向 绑定事件的对象

当时事件绑定方法时,this指向绑定的方法

//事件监听
var btn = document.querySelector("button")
btn.addEventListener('click', function () {
  console.log(this) //btn
})

3、构造器调用

//不使用new指向window
function Person(name) {
  console.log(this) // window
  this.name = name;
}
Person('inwe')


//使用new
function Person(name) {
  this.name = name
  console.log(this) //people
  self = this
}
var people = new Person('iwen')
console.log(self === people) //true
//这里new改变了this指向,将this由window指向Person的实例对象people


//但是,如果显式的返回了一个object对象,那么此次运算结果最终会返回这个对象。
var MyClass = function () {
    this.name = 1;
    return {
        name: 2
    }
}
var myClass = new MyClass(); 
console.log('myClass:', myClass.name);//myClass: 2

4、箭头函数中指向外层作用域的 this

箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。

var obj = {
  foo() {
    console.log(this);
  },
  bar: () => {
    console.log(this);
  }
}

obj.foo() // {foo: ƒ, bar: ƒ}
obj.bar() // window

5、call或apply调用

跟普通的函数调用相比,用call和apply可以动态的改变函数的this

var obj1 = {
    name: 1,
    getName: function (num = '') {
        return this.name + num;
    }
};

var obj2 = {
    name: 2,
};
// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数
console.log(obj1.getName()); // 1
console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4

 6、补充

有一点需要注意的是定时器函数, 此时 this 指向 window

 setInterval(function () {
       console.log(this); // window
     }, 1000);

二、call、apply和bind

我们先来看看call和apply方法的例子

var obj1 = {
    name: 1,
    getName: function (num = '') {
        return this.name + num;
    }
};

var obj2 = {
    name: 2,
};
// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数
console.log(obj1.getName()); // 1
console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4

从中我们可以看出来,call和apply的作用都是改变this的指向,似乎没有什么差距,事实上也的确如此,他们的差距很小,也可以实现切换,但是他们之间还是有一些细小的差距的,接下来我们来看看他们之间的差距

call()和apply()的区别

  • apply接受两个参数
    • 第一个参数指定了函数体内this对象的指向
    • 第二个参数为一个带下标的参数集合(可以是数组或者类数组)
  • call接受的参数不固定
    • 第一个参数指定了函数体内this对象的指向
    • 第二个参数及以后为函数调用的参数

在所有(非箭头)函数中都可以通过arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,它本身就是一个类数组,我们apply在实际使用中更常见一些。

call是包装在apply上面的语法糖,如果我们明确的知道参数数量,并且希望展示它们,可以使用call。

当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会默认指向宿主对象,在浏览器中则是window。

var obj1 = {
    name: 1,
    getName: function (num = '',j= '') {
        return this.name + num+j;
    }
};

var obj2 = {
    name: 2,
};
// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数
console.log(obj1.getName()); // 1
console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4
console.log(obj1.getName.apply(obj2, [2,3]));// 2 + 2 + 3 = 7

bind()方法

bind()创建的是一个新的函数(称为绑定函数),与被调用函数有相同的函数体,当目标函数被调用时this的值绑定到 bind()的第一个参数上

var obj = {
    name: 1
};

var func = function(){
    console.log(this.name);
};
func.bind(obj)()//记住一定到调用,否则只是绑定


//bind也可以直接绑定在函数上
var obj = {
    name: 1
};

var func = function(){
    console.log(this.name);
}.bind(obj);

func(); //1

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌新小吉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值