一、全局环境下的 this(与函数无关--直接访问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指向调用该函数的对象
当函数作为对象方法被调用时this指向该对象
let obj = {
age: 18,
fn: function () {
console.log(this === obj); //true
console.log(this.age); //18
},
};
obj.fn()
2.3、作为构造函数被调用时
- 构造函数里的this指向 new创建的实例对象
构造函数的原理(new之后发生了什么)
官方解释:
- 创建一个空的简单
JavaScript
对象(即{});- 为步骤1新创建的对象添加属性
__proto__
,将该属性链接至构造函数的原型对象 ;- 将步骤1新创建的对象作为
this
的上下文 ;- 如果该函数没有返回对象,则返回
this
。
咱们的总结:
1、自从用
new
调用函数后,JS引擎就会在内存中创建一个空对象{}
,const newObj = {};
2、将新对象newObj的__proto__
属性链接至构造函数的原型对象newObj.__proto__ = FunctionName.prototype
3、构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)this = newObj
4、执行构造函数内部代码;
5、如果该函数没有返回对象,则默认返回this。
构造函数中的this指向,指向构造出来的实例对象
eg
![](https://img.haomeiwen.com/i27493437/ba725dc1ccc463b6.png)
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
三、总结
![](https://img.haomeiwen.com/i27493437/16a0eace84eeb6f7.png)
四、如何更改this指向
call,apply和bind方法都可以用来更改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
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装
[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
网友评论