今天来聊聊JavaScript中的this,刚开始我]this的理解不深! 然后会看看各种技术文章,有时茅塞顿开,好像懂了了,使用中用迷糊了!
this
跟别的语言有很大的不同,JavaScript中的this总是指向一个对象,具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,不是函数声明时的环境.
this的指向
不考虑with和eval.
- 作为对象的方法调用
- 作为普通函数调用
- 作为构造器调用
- Function.prototype.call 或Function.prototype.apply调用
情况一:作为对象方法的调用
当函数作为对象的方法调用,这时this指向这个对象。
var obj={
a:1,
getA:function(){
console.log(this===obj); //true
console.log(this.a); //1
}
}
obj.getA();
复制代码
情况二:普通函数调用
这是函数的最通常用法,属于全局性调用,此时函数总是指向全局对象,在浏览器里,就是window。
window.name="globalName";
var getName=function(){
return this.name;
}
console.log(getName()); //输出:globalName复制代码
有时候会有很多困扰比如在回调事件中有一个callBack方法,callBack被作为普通函数调用时,callBack内部的this是window,我们想要的其实是触发事件的元素,代码如下:
<html>
<body>
<div id="div1" > 我被点击了</div>
</body>
<script>
window.id='window';
document.getElementById("div1").onclick=function(){
console.log(this.id); // div1;
var callback=funciton(){
console.log(this.id); //输出:// window
}
callback();
}
<script>
</html>
复制代码
解决办法就是利用闭包,
window.id='window';
document.getElementById("div1").onclick=function(){
console.log(this.id); // div1;
var self=this;
var callback=funciton(){
console.log(self.id); //输出:div1
}
callback();
}复制代码
如果在es5的严格模式下(strict),this被规定不指向全局了,是undefined
function func(){
"use strict"
alert(this); //undefined
}复制代码
情况三 作为构造器调用
所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。
var MyClass=function(){
this.name="seven";
}
var obj=new MyClass();
console.log(obj.name); //输出:seven
复制代码
注意: 如果构造器返回了一个object类型的对象,那么new 操作符后返回的是这个对象,不是我们的this;
var MyClass=function(){
this.name="seven";
return {
name:'小狗',
}
}
var obj=new MyClass();
console.log(obj.name); //输出:'小狗'复制代码
情况四 apply,call调用
跟普通函数相比,使用call和apply可以动态的指定this指向
var obj1={
a:1,
getA:function(){
console.log(this===obj1);
console.log(this.a);
}
}
var obj2={
a:'小狗'
}
console.log(obj1.getA()); //输出: ture ,1
console.log(obj1.getA.call(obj2)); //输出:false 小狗复制代码
记得看过一个面试题 "不用call和apply方法模拟实现ES5的bind方法",可以帮助我对this很好的理解.
丢失的this
var obj={
a:1,
getA:function(){
return this.a;
}
}
console.log(obj.getA());//输出 1
var getB=obj.getA;
console.log(getB); //输出 undefined
复制代码
当调用obj.getA(),getA是作为obj的属性被调用的,根据 情况一作为对象方法的调用,此时的this 指向obj;
当var getB=obj.getA; 这个时候就相当于普通函数调用 好比 var getB=function(){};,所以this指向window
最后聊一聊箭头函数
ES6允许使用(=>
)定义函数
var f = v => v;
复制代码
上面的箭头函数等同于:
var f = function(v) {
return v;
};复制代码
使用注意点
箭头函数有几个使用注意点。
(1)函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new
命令,否则会抛出一个错误。
(3)不可以使用arguments
对象,该对象在函数体内不存在。
var handler = {
id: '123456',
getId:()=>{
return this.id
},
init: function(type) {
let callback=type => this.doSomething(type);
callback();
},
doSomething: function(type) {
console.log('Handling ' + type + ' for ' + this.id);
}
};
//注意这里与"情况一:作为对象方法的调用" 的区别点,有一些迷惑
handler.getId(); // 输出:undfined
getId()使用的是箭头函数,箭头函数里面是没有this的,所以里面的this来自外部代码块
handler这个代码块又不够成作用域(函数作用域和全局作用域),所以this指向window
handler.init(); //输出123456
init不是箭头函数,根据 "情况一:作为对象方法的调用" init的this指向handler,
init是函数形成作用域,在函数作用中定义箭头函数callback,callback是箭头函数没有this,
所以找到外部代码块的init作用域的this;
用普通函数表示如下:
var handler = {
id: '123456',
init: function(type) {
var self=this;
var callback=function(){
self.doSomething(type);
}
callback();
},
doSomething: function(type) {
console.log('Handling ' + type + ' for ' + this.id);
}
};
复制代码
上面代码的init
方法中,使用了箭头函数,这导致这个箭头函数里面的this
,总是指向handler
对象。否则,回调函数运行时,this.doSomething
这一行会报错,因为此时this
指向
this
指向的固定化,并不是因为箭头函数内部有绑定this
的机制,实际原因是箭头函数根本没有自己的this
,导致内部的this
就是外层代码块的this
。正是因为它没有this
,所以也就不能用作构造函数。
这就是我对this的理解,希望读完这个,大家都能理解!
今天就写到这里
参考:http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html