Javascript中this关键字详解

简介: 原文地址 Quiz请看下面的代码,最后alert出来的是什么呢?var name = "Bob"; var nameObj ={ name : "Tom", showName : function(){ alert(this.name); }, waitShowName : function()

原文地址
Quiz

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

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

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月前
|
JavaScript 前端开发
javascript中的this
javascript中的this
|
3月前
|
JavaScript 前端开发
错综复杂的this:理清你的JavaScript代码中的指向问题
错综复杂的this:理清你的JavaScript代码中的指向问题
|
1月前
|
JavaScript
JS中改变this指向的六种方法
JS中改变this指向的六种方法
|
3天前
|
JavaScript 前端开发
js开发:请解释this关键字在JavaScript中的用法。
【4月更文挑战第23天】JavaScript的this关键字根据执行环境指向不同对象:全局中指向全局对象(如window),普通函数中默认指向全局对象,作为方法调用时指向调用对象;构造函数中指向新实例,箭头函数继承所在上下文的this。可通过call、apply、bind方法显式改变this指向。
7 1
|
1月前
|
JavaScript 前端开发 开发者
js开发:请解释什么是ES6的let和const关键字,以及它们与var关键字的区别。
ES6引入`let`和`const`替代`var`声明变量。`let`有块级作用域,存在暂时性死区,不进行变量提升,可重新赋值。`const`用于常量,值不可变但引用类型内容可变,同样有块级作用域和暂时性死区。与`var`主要区别在于作用域、变量提升和可变性。这些改进提高了代码的可预测性和安全性。
24 2
|
1月前
|
JavaScript
JS中call()、apply()、bind()改变this指向的原理
JS中call()、apply()、bind()改变this指向的原理
|
1月前
|
JavaScript 前端开发 算法
JavaScript 关键字 debugger 的作用和使用场景介绍
JavaScript 关键字 debugger 的作用和使用场景介绍
35 0
|
1月前
|
JavaScript 前端开发 编译器
编程笔记 html5&css&js 077 Javascript 关键字
编程笔记 html5&css&js 077 Javascript 关键字
|
2月前
|
JavaScript 前端开发
JavaScript中this的指向问题
JavaScript中this的指向问题
|
3月前
|
前端开发 JavaScript
揭开`this`的神秘面纱:探索 JavaScript 中的上下文密钥(下)
揭开`this`的神秘面纱:探索 JavaScript 中的上下文密钥(下)