zoukankan      html  css  js  c++  java
  • Javascript中this关键字详解

    原文出处:http://www.cnblogs.com/justany/archive/2012/11/01/the_keyword_this_in_javascript.html

    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>
    复制代码
  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/purplefox2008/p/5376437.html
Copyright © 2011-2022 走看看