JavaScript中的this

来源:互联网 发布:js离开当前页面事件 编辑:程序博客网 时间:2024/05/18 01:44

请看下面的代码,最后alert出来的是什么呢?

 var name = "Bob";   var nameObj ={        name : "Tom",        showName : function(){            alert(this.name);        },        waitShowName : function(){            setTimeout(this.showName, 1000);        }   };   nameObj.waitShowName(); //Bob

要解决这个问题我们需要了解Javascript的this关键字的用法。

1、this指向哪里?

  一般而言,在Javascript中,this指向函数执行时的当前对象。值得注意,该关键字在Javascript中和执行环境,而非声明环境有关。

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

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。

 

2、没有明确的当前对象时

  当没有明确的执行时的当前对象时,this指向全局对象window。为什么说是全局对象(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

3、setTimeout、setInterval和匿名函数

  在浏览器中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。

4、eval

  对于eval函数,其执行时候似乎没有指定当前对象,但实际上其this并非指向window,因为该函数执行时的作用域是当前作用域,即等同于在该行将里面的代码填进去。下面的例子说明了这个问题:

var name = "window";var Bob = {    name: "Bob",    showName: function(){        eval("alert(this.name)");    }};Bob.showName();    //Bob

5、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();    //windowsomeone.showName.apply(other);    //Tom

  apply用于改变函数执行时的当前对象,当无参数时,当前对象为window,有参数时当前对象为该参数。于是这个例子Bob成功偷走了Tom的名字。

6、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


 

0 0
原创粉丝点击