设为首页 收藏本站
查看: 1197|回复: 0

[经验分享] Javascript中this关键字详解

[复制链接]

尚未签到

发表于 2017-2-24 07:12:20 | 显示全部楼层 |阅读模式
  Quiz
  请看下面的代码,最后alert出来的是什么呢?



1 var name = "Bob";  
2 var nameObj ={  
3     name : "Tom",  
4     showName : function(){  
5         alert(this.name);  
6     },  
7     waitShowName : function(){  
8         setTimeout(this.showName, 1000);  
9     }  
10 };  
11
12 nameObj.waitShowName();
  要解决这个问题我们需要了解Javascript的this关键字的用法。
  this指向哪里?
  一般而言,在Javascript中,this指向函数执行时的当前对象。

  In JavaScript, as in most object-oriented programming languages, this is a special keyword that is used within methods to refer to the object on which a method is being invoked.
  ——jQuery Fundamentals (Chapter 2), by Rebecca Murphey

  值得注意,该关键字在Javascript中和执行环境,而非声明环境有关。

  The this keyword is relative to the execution context, not the declaration context.

  我们举个例子来说明这个问题:



var someone = {
name: "Bob",
showName: function(){
alert(this.name);
}
};
var other = {
name: "Tom",
showName: someone.showName
}
other.showName();  //Tom
  this关键字虽然是在someone.showName中声明的,但运行的时候是other.showName,所以this指向other.showName函数的当前对象,即other,故最后alert出来的是other.name。
  没有明确的当前对象时
  当没有明确的执行时的当前对象时,this指向全局对象window。

  By default, this refers to the global object.
  为什么说是全局对象(the global object),因为非浏览器情况下(例如:nodejs)中全局变量并非window对象,而就是叫“全局变量”(the global object)。不过由于我们这片文章主要讨论的是前端开发知识,所以nodejs就被我们忽略了。

  例如对于全局变量引用的函数上我们有:



var name = "Tom";
var Bob = {
name: "Bob",
show: function(){
alert(this.name);
}
}
var show = Bob.show;
show();  //Tom
  你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:



var name = "window";
var Bob = {
name: "Bob",
showName: function(){
alert(this.name);
}
};
var Tom = {
name: "Tom",
showName: function(){
var fun = Bob.showName;
fun();
}
};
Tom.showName();  //window
  setTimeout、setInterval和匿名函数
  文章开头的问题的答案是Bob。
  在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window,这条我们可以看成是上一条的一个特殊情况。
  所以在运行this.showName的时候,this指向了window,所以最后显示了window.name。

  浏览器中全局变量可以当成是window对象下的变量,例如全局变量a,可以用window.a来引用。

  我们将代码改成匿名函数可能更好理解一些:



var name = "Bob";  
var nameObj ={  
name : "Tom",  
showName : function(){  
alert(this.name);  
},  
waitShowName : function(){  
!function(__callback){
__callback();
}(this.showName);  
}  
};  
nameObj.waitShowName();  //Bob
  在调用nameObj.waitShowName时候,我们运行了一个匿名函数,将nameObj.showName作为回调函数传进这个匿名函数,然后匿名函数运行时,运行这个回调函数。由于匿名函数的当前对象是window,所以当在该匿名函数中运行回调函数时,回调函数的this指向了window,所以alert出来window.name。
  由此看来setTimeout可以看做是一个延迟执行的:



function(__callback){
__callback();
}
  setInterval也如此类比。
  但如果我们的确想得到的回答是Tom呢?通过一些技巧,我们能够得到想要的答案:



var name = "Bob";  
var nameObj ={  
name : "Tom",  
showName : function(){  
alert(this.name);  
},  
waitShowName : function(){
var that = this;
setTimeout(function(){
that.showName();
}, 1000);
}
};
nameObj.waitShowName();  //Tom
  在执行nameObj.waitShowName函数时,我们先对其this赋给变量that(这是为了避免setTimeout中的匿名函数运行时,匿名函数中的this指向window),然后延迟运行匿名函数,执行that.showName,即nameObj.showName,所以alert出正确结果Tom。
  eval
  对于eval函数,其执行时候似乎没有指定当前对象,但实际上其this并非指向window,因为该函数执行时的作用域是当前作用域,即等同于在该行将里面的代码填进去。下面的例子说明了这个问题:



var name = "window";
var Bob = {
name: "Bob",
showName: function(){
eval("alert(this.name)");
}
};
Bob.showName();    //Bob
  apply和call
  apply和call能够强制改变函数执行时的当前对象,让this指向其他对象。因为apply和call较为类似,所以我们以apply为例:



var name = "window";
var someone = {
name: "Bob",
showName: function(){
alert(this.name);
}
};
var other = {
name: "Tom"
};   
someone.showName.apply();    //window
someone.showName.apply(other);    //Tom
  apply用于改变函数执行时的当前对象,当无参数时,当前对象为window,有参数时当前对象为该参数。于是这个例子Bob成功偷走了Tom的名字。
  new关键字
  new关键字后的构造函数中的this指向用该构造函数构造出来的新对象:



function Person(__name){
this.name = __name;        //这个this指向用该构造函数构造的新对象,这个例子是Bob对象
}
Person.prototype.show = function(){
alert(this.name);
}
var Bob = new Person("Bob");
Bob.show();        //Bob
  思考题
  1.  请问下面代码会alert出什么,为什么?



var name = "Bob";  
var nameObj ={  
name : "Tom",  
showName : function(){  
alert(this.name);  
},  
waitShowName : function(){
var that = this;
setTimeout("that.showName();", 1000);
}
};
nameObj.waitShowName();
  2.  请问下面代码会alert出什么,为什么?



var fun = new Function("alert(this)");
fun();
  3.  下面代码分别在IE和其他浏览器上运行有什么差异,可以用什么方法解决这个差异问题?
  IE:



<button id = "box" name = "box">Click Me!</button>
<script>
var name = "window";
function showName(){
alert(this.name);
}
document.getElementById("box").attachEvent("onclick", showName);
</script>
  Others:



<button id = "box" name = "box">Click Me!</button>
<script>
var name = "window";
function showName(){
alert(this.name);
}
document.getElementById("box").addEventListener("click", showName, false);
</script>
  参考文献
  Javascript Closures . Richard Cornford  . March 2004
  Javascript的this用法 . 阮一峰 . 2010.4.30

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-346315-1-1.html 上篇帖子: 微软和开源社区---开发者的福音 下篇帖子: 你所必须掌握的三种异步编程方法callbacks,listeners,promise
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表