心语:我还是很喜欢你,像从一场温暖至极的梦中醒来,只留叹息;我还是很喜欢你,像大海退潮后的礁岩,无处遁形。
在 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会返回这个新对象