首页 专题 H5案例 前端导航 UI框架

再来摸摸Javascript中this的坑

作者:TG 日期: 2018-07-21 阅读: 509
this 是 Javascript语言 的一个保留关键字,它代表函数运行时自动生成的一个内部对象,只能在函数内部使用。首先要记住的是,函数中的this并不是在创建时确定下来的,而是在函数执行的时候才确定的。这个也是造成使用this时出现很多误解的原因。

本章内容:
  1. 谁调用,谁负责
  2. new的过程
  3. 怪异的return
  4. 被干掉的this
  5. 丢失的this

在开始今天的内容之前,先来看看下面的代码:

// 实例1  

var name = 'a';   


var obj = {   

  name: 'b',   

  getName: function() {   

    console.log(this.name);   

  }  

};  

obj.getName();   


var getName = obj.getName;  

getName();   


var obj2 = (function() {   

  return function() {   

    console.log(this.name);   

  }  

})();  

obj2();  


// 实例2 

function Test() {   

  console.log(this.name);  

}  

Test();   


var test = new Test();   


function Test2() {   

  this.name = 'c';  

}   

var test2 = new Test2();  

console.log(test2.name);  


// 实例3 

function Test3() {   

  this.name = 'd';    

  return {}; // 1 | 'd' | null | undefined   

}  

var test3 = new Test3();  

console.log(test3.name);   


function Test4() {   

  this.name = 'd';    

  return 1;  

}  

var test4 = new Test4();  

console.log(test4.name);  


// 实例4

function Test5() {   

  "use strict";   

  console.log(this.name);  

}  

console.log(Test5());   


function test6() {   

  console.log(this.name);  

}  


// 实例5

var btn = document.querySelector('.btn');  

btn.name = 'button';  

btn.onclick = test6;   


var btn2 = document.querySelector('.btn2');  

btn2.name = 'button';  

btn2.onclick = function() {   

  test6();  

}


保存着你的答案,接下来我们一一分析。

1. 谁调用,谁负责

来回顾一下实例1

var name = 'a';   


var obj = {   

  name: 'b',   

  getName: function() {   

    console.log(this.name);   

  }  

};  

obj.getName(); // b   


var getName = obj.getName;  

getName(); // a   


var obj2 = (function() {   

  return function() {   

    console.log(this.name);   

  }  

})();  

obj2(); // a

首先说说obj.getName(),它打印的是b,为什么呢?因为调用getName()的是obj这家伙,自然,它的this就指向了obj,所以this.name自然就是b。

而接下来的getName()为毛打印的是a呢?因为当前调用getName()的并不是obj了,而是全局变量window,所以打印结果是a

obj2中,我们采用了立即执行函数,它返回一个函数,而当我们调用时,调用它的也是全局变量window,所以其打印的结果也是a。

注: 匿名函数内的this是指向window的,更准确的说是指向调用者。

结论: 谁调用,谁负责

2. new的过程

function Test() {   

  console.log(this.name);  

}  

Test(); // a   


var test = new Test();  // undefined  


function Test2() {   

  this.name = 'c';  

}   


var test2 = new Test2();  

console.log(test2.name); // c

要搞清楚上面为什么打印c,就有必要了解new的过程

new Test2() 其实执行了三步动作:

var obj = {};   

obj.__proto__ = Test2.prototype;   

Test2.call(obj);  

首先,创建了一个空对象obj
接着,将这个空对象的[[Prototype]](__proto__)成员指向了Test2函数对象prototype成员对象
最后,将Test2函数对象的this指针替换成obj

当没有显式返回值或者返回为基本类型、null时,默认将 this 返回。可参考:3. 怪异的return

搞清楚new的过程,相信你对打印出c的原因已经明白了。

结论: 当使用new时,函数内部的this指向已经改变了,并不指向window。

3. 怪异的return

在上面的“new的过程”中,我们了解了new的函数内的this指向,但是,也有一些例外,比如下面:

function Test3() {   

  this.name = 'd';    

  return {};   

}  

var test3 = new Test3();  

console.log(test3.name); // undefined   


function Test4() {   

  this.name = 'd';    

  return 1;  

}  

var test4 = new Test4();  

console.log(test4.name); // d

可以再试试return 'd' | null | undefined中的一个或更多类型。


结论: 如果return的是一个对象(null除外),那么this指向的这个对象,否则this依旧指向实例对象。


4. 被干掉的this


function Test5() {   

  "use strict";   

  console.log(this.name);  

}  

console.log(Test5()); // Uncaught TypeError: Cannot read property 'name' of undefined

在严格模式下,函数内的this都指向了undefined。 


除了严格模式下,函数内的this被干掉了。在ES6中箭头函数的this同样被干掉了,但是它有点不一样,它可以盗用它最接近一层作用域内的 this


5. 丢失的this


function test6() {   

  console.log(this.name);  

}  

var btn = document.querySelector('.btn');  

btn.name = 'button';  

btn.onclick = test6; // button   


var btn2 = document.querySelector('.btn2');  

btn2.name = 'button';  

btn2.onclick = function() {   

  test6(); // a  

}

在JavaScript中,事件绑定的函数的this是指向绑定元素的,比如上面的onclick绑定的test6函数内的this是指向btn元素的。而btn2绑定事件为什么打印a呢?回顾一下上面第一节中提到的“谁调用,谁负责”。


此外,setTimeoutsetInterval等函数内this默认的指向是Window。


如有疑问,欢迎在下方的评论区留言!


备注:评论插件已经换成Disqus,需要翻墙 !



关注”全栈技术杂货铺“

全栈技术杂货铺