很多小伙伴会被this的指向问题弄得焦头烂额,或者这次记住了,下次别人一问,又答不上来,那么这次就让我们彻底捋清楚
首先,要清楚一点,
this的指向在函数声明的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁
- this永远指向的是最后调用它的对象,这里强调最后
- window是浏览器中js中的全局对象,globalwindow是nodejs的全局对象,我们创建的变量实际上是给全局对象添加属性
- 非严格模式下,例如user()其实等价于
window.user()
,所以默认指向是window,而严格模式下,this不会有默认指向,因而是undefined - 箭头函数 没有自己的this,只会从自己的作用域链的上一层继承this
下面我们通过代码进一步了解(非严格模式下)
function User(){
var name = 'henry';
console.log(this)//打印出了window,因为user()其实就是window.user()
console.log(this.name)//undefined
}
User()
var user = {
name:"henry",
getName:function(){
console.log(this.name); //henry,因为调用函数getName的是user
}
}
user.getName();
var user = {
age:26,
names:{
chinese:'楠',
english:'henry'
getEnglishName:function(){
console.log(this.english); //henry,因为调用的对象是names
console.log(this.age)//undefined
}
}
}
user.names.getEnglishName();
var user = {
age:26,
names:{
chinese:'楠',
english:'henry'
getEnglishName:function(){
console.log(this); //window,因为最后调用的对象是window
console.log(this.english)//undefined
}
}
}
var getEnglishName = user.names.getEnglishName;//创建的变量实际上是给全局对象(window)添加属性
getEnglishName();//等价于window.getEnglishName()
上面的三个例子说明:this指向最后调用函数的那个对象
下面我们继续看
构造函数版this:
function User(name){
this.name = name;
}
const user = new User('henry')
console.log(user.name) //henry
new关键字就是创建一个对象实例,并将this指向这个实例对象
但还有种情况比较特殊,当this碰到return时
function User1()
{
this.index = 1;
return {};
}
function User2()
{
this.index = 2;
return function(){};
}
function User3()
{
this.index = 3;
return [];
}
var user1 = new User1();
console.log(user1.index); //undefined
var user2 = new User2();
console.log(user2.index); //undefined
var user3 = new User3();
console.log(user3.index); //undefined
function User1()
{
this.index = 1;
return 'user1';
}
function User2()
{
this.index = 2;
return undefined;
}
function User3()
{
this.index = 3;
return null;
}
function User4()
{
this.index = 4;
return true;
}
function User5()
{
this.index = 5;
return 1000;
}
var user1 = new User1();
console.log(user1.index); //1
var user2 = new User2();
console.log(user2.index); //2
var user3 = new User3();
console.log(user3.index); //3
var user4 = new User4();
console.log(user4.index); //4
var user5 = new User5();
console.log(user5.index); //5
由上面的例子可以看出,如果返回值是一个引用类型时,那么this指向的就是那个返回的对象,如果返回值不是一个引用类型时,那么this还是指向函数的实例
* 改变this指向的三种方法
说了那么多,那this指向是否有办法改变,当然有,分别是call
,apply
,以及 bind
先看一个例子
function Person(sex, height){
console.log(sex + "," + height);//boy,180
console.log(this);//window对象
}
Person("boy",180)
然后我们分别用 call
,apply
来改变this指向
1.call() 方法
var user = {
name:"henry",
age:26
}
function Person(sex, height){
console.log(sex + "," + height);//boy,180
console.log(this);//user对象
console.log(this.name);//henry
console.log(this.age);//26
}
Person.call(user,"boy",180);
2.apply() 方法
var user = {
name:"henry",
age:26
}
function Person(sex, height){
console.log(sex + "," + height);//boy,180
console.log(this);//user对象
console.log(this.name);//henry
console.log(this.age);//26
}
Person.apply(user,["boy",180]);
接着我们来看看bind改变this指向的例子
var App = document.getElementById("app");
App.onclick = function(){
this.id='app'
setTimeout(function(){
console.log(this);//window,相当于window.setTimeout
console.log(this.id)//undefined
},1000)
}
那么怎么把this改成指向div呢?
var App = document.getElementById("app");
App.onclick = function(){
this.id='app'
setTimeout(function(){
console.log(this);//this指向了App
console.log(this.id)//app
}.bind(this),1000)
}
这里需要注意,箭头函数没有this,不能当构造函数new,当然也无法用apply,call,bind等方法改变this指向,具体可以看 MDN
以上就是我对this的总结,看完这个之后如果对new感兴趣的话,可以接着看下一篇 了解一下new的过程发生了什么,以便更进一步了解上面new过程的this指向