您的位置:首页 > Web前端 > JavaScript

javascript中让你捉摸不定的this

2016-03-31 17:03 621 查看
this到底指向谁,估计很多人在使用javascript的过程中都遇到过,这个关键字如果没搞懂,在一些高级功能中都会困难重重,搜了下相关文章,介绍的都挺多的,也有很深入的,比如汤姆大叔的《深入理解javascript系列》文章。看到很多文章中提到一句话:"this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁实际上this的最终指向的是那个调用它的对象"。

《javascript设计模式与实践》中是这样说的:javascript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境

除去不常用的with和eval,实际应用中,this的指向大致分为下面4种情况:

1、作为对象的方法调用。

2、作为普通函数调用。

3、构造器函数调用。

4、call和apply调用。

情况1:作为对象的方法调用

当函数作为对象的方法调用时,this指向该对象。这是最常见的,比如:

var obj={
a:1,
fun:function(){
console.log(this.a);//输出:1
}
};
obj.fun();


情况2:作为普通函数调用

当函数不作为对象的属性调用时,即作为普通函数调用,this总是指向全局对象。

var a=1;
function fun(){
var a=2;
console.log(this.a);//输出:1
 console.log(a);//输出:2
}
fun();


再看一种情况:

var name="张三";
var obj={
name:"李四",
getName:function(){
console.log(this.name);
}
}
obj.getName();//输出:李四
var getName=obj.getName;
getName();//输出:张三


 直接调用obj.getName(),这里的this是作为对象的方法调用,所以它指向obj,this.name就是李四;

obj.getName赋值给getName后,getName就变成了普通函数,所以指向的是全局的window.name,结果是张三;

举个在实际开发过程中遇到的会让人困惑的例子:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button id="btn">点我</button>
<script type="text/javascript">
var id="window";
document.getElementById("btn").onclick=function(){
alert(this.id);//输出:btn
var callback=function(){
alert(this.id);//输出:window
}
callback();
}
</script>
</body>
</html>


  点击按钮的时候this指向的是按钮,但是callback是作为普通函数调用的,里面的this指向的是全局对象window,所以结果是window。

此时我们可以临时用一个变量保存对当前对象的引用:

var id="window";
document.getElementById("btn").onclick=function(){
var self=this;
var callback=function(){
alert(self.id);//输出:btn
}
callback();
}


情况3:构造器中调用

function myClass(){
this.name="张三";
}
var child=new myClass();
console.log(child.name);//输出:张三


大部分的javascript函数都可以当做构造函数来使用,构造器函数外表跟普通函数一模一样,区别在于调用的方式。当使用new运算符调用函数时,该函数总会返回一个对象,就是我们常说的实例对象。通常情况下,通过new运算符后,构造器函数中的this就指向的实例对象。

注意:如果构造器函数显式的返回了一个object类型的休息,那么运算结果最终会返回这个对象,而不是上面所期望的。例如:

function myClass(){
this.name="张三";
return {
name:"李四"
}
}
var child=new myClass();
console.log(child.name);//输出:"李四"
console.log(child);//输出:[object Object] {name: "李四"}


  

 这个例子与上面的例子差别就在于构造器函数最后返回了一个对象。如果构造器函数不显式的返回任何数据,或者返回一个非对象类型的数据,就不会出现这种情况,例如:

function myClass(){
this.name="张三";
return "李四"
}
var child=new myClass();
console.log(child.name);//输出:张三
console.log(child);//输出:[object Object] {name: "张三"}


情况4:call和apply

call和apply能够动态的修改传入函数的this:

var obj1={
name:"张三",
getName:function(){
console.log(this.name);
}
};
var obj2={
name:"李四"
};
obj1.getName();//输出:"张三"
obj1.getName.call(obj2);//输出:"李四"
obj1.getName.apply(obj2);//输出:"李四"


  

call和apply的作用这里就不详细说了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: