zoukankan      html  css  js  c++  java
  • JavaScript中的this关键字

    下文翻译自:http://davidshariff.com/blog/javascript-this-keyword/#first-article

    “this”关键字是JavaScript中的一个常见特性,但它通常也是该语言中最混乱和容易误解的特性之一。“this”究竟意味着什么,它又是如何定义的呢?

    本文试图澄清困惑并以清晰的方式解析答案。

    “this”关键字对于已经使用过其他编程语言的人并不陌生,通常它指的是,通过构造函数实例化类时创建的新对象。例如,如果我有一个类Boat(),它有一个方法moveBoat(),当在moveBoat()方法中引用“this”时,我们实际上是访问新创建的Boat()对象。

    在JavaScript中,当使用“new”关键字调用它时,我们在Function构造函数中也有这个概念,但它不是唯一的规则,“this”通常可以引用不同的执行上下文中的不同对象。如果您不熟悉JavaScript的执行上下文,我建议您在此处阅读我关于该主题的其他帖子。说的差不多了,让我们来看一些JavaScript的示例:

    // global scope
    
    foo = 'abc';
    alert(foo); // abc
    
    this.foo = 'def';
    alert(foo); // def

    任何时候,在全局上下文(不在函数体内)中使用"this"关键字,this总是指向全局对象。现在,我们来看一下this在函数体内的表现:

    var boat = {
        size: 'normal',
        boatInfo: function() {
            alert(this === boat);
            alert(this.size);
        }
    };
    
    boat.boatInfo(); // true, 'normal'
    
    var bigBoat = {
        size: 'big'
    };
    
    bigBoat.boatInfo = boat.boatInfo;
    bigBoat.boatInfo(); // false, 'big'

    所以上面的"this"如何确定呢?起码可以看见一个boat对象,其中有一个size属性和一个boatInfo()函数。boatInfo()函数里面,弹出this对象是否是boat对象的结果,和this对象中的size属性。然后,我们用boat.boatInfo()的方式调用boatInfo()函数可以看见this对象是boat对象和boat中的size属性的值“normal”。

    接着我们创建另一个对象bigBoat,其中有一个值为big的size属性。然而,bigBoat对象中不存在boatInfo()方法,所以我们使用bigBoat.boatInfo = boat.boatInfo方式从boat对象中复制方法。现在,当我们调用bigBoat.boatInfo()时,发现this对象不在等于boat对象,this.size属性也变成了big。为什么会这样呢?boatInfo()内部的值是怎么改变的呢?

    首先你需要了解的是在任何函数内部,其this对象的值都不是静态不变的,它的值总是在每次调用函数时确定,但在函数实际执行函数体代码之前。函数内部this的值实际上是由调用该函数的父作用域提供的。而更重要的是,这样的函数语法实际上是如何编写。

    当一个函数被调用时,我们必须查看我们必须查看括号/括弧“()”的左侧。如果我们可以在括号的左侧看到一个引用,那么传递给函数调用的“this”值正是该属于该对象的值,否则“this”值便是全局对象。我们来看一些例子:

    function bar() {
        alert(this);
    }
    bar(); // global - 因为方法bar()被调用时属于global对象(被全局对象调用)
    var foo = {
        baz: function() {
            alert(this);
        }
    }
    foo.baz(); // foo -因为方法baz()被调用时属于foo对象(被foo对象调用)

    如果到目前为止的这些对你来说是清晰的,那么以上的代码明显起了作用。我们可以通过两种不同的方式编写调用语法,来更改同一个函数中“this”值,将问题进一步复杂化:

    var foo = {
        baz: function() {
            alert(this);
        }
    }
    foo.baz(); // foo - 因为baz()被调用时属于foo对象
    
    var anotherBaz = foo.baz;
    anotherBaz(); // global - 因为方法antherBaz()被调用时属于global对象,而不是foo对象

    这里,我们可以看见两次baz()内部的“this”的值是不同的,因为它用两种不同的语法调用。现在,让我们在深层嵌套的对象中看一下“this”的值:

    var anum = 0;
    
    var foo = {
        anum: 10,
        baz: {
            anum: 20,
            bar: function() {
                console.log(this.anum);
            }
        }
    }
    foo.baz.bar(); // 20 - 因为()的左边是bar,它被调用时属于baz对象
    
    var hello = foo.baz.bar;
    hello(); // 0 - 因为()的左边是hello,它被调用时属于global对象

    还有一个经常被问到的问题是如何在一个事件处理程序中确定“this”关键字?答案是事件处理程序内部的“this”始终引用它所触发的元素。我们来看一个例子:

    <div id="test">I am an element with id #test</div>
    function doAlert() { 
        alert(this.innerHTML); 
    } 
    
    doAlert(); // undefined 
    
    var myElem = document.getElementById('test'); 
    myElem.onclick = doAlert; 
    
    alert(myElem.onclick === doAlert); // true 
    myElem.onclick(); // I am an element

    在这里我们可以看到,当首次调用doAlert()时,它弹出undefined,因为doAlert()从属于全局对象。然后我们编写myElem.onclick = doAlert,它将函数doAlert()复制给myElem的onclick()事件。这基本上意味着每当触发onclick()时,doAlert()就是myElem的一个方法,这意味着可以确定“this”的值将是myElem对象。

    关于这个主题,我要添加的最后一点是,“this”的值也可以使用call()和apply()手动设置,覆盖我们今天在这里讨论的内容。同样有趣的是,当在函数构造函数中调用“this”时,“this”指的是构造函数内所有实例中新创建的对象。原因是函数构造函数使用“new”关键字调用,该关键字创建一个新对象,其中构造函数中的“this”始终引用刚刚创建的新对象。

    总结

    希望今天发布的博客已经解决了对“this”关键字的任何疑惑与误解,你可以随时了解“this”的正确价值。我们现在知道“this”的值永远不会是静态的,并且具有不同的值,具体取决于函数的调用方式。

  • 相关阅读:
    存储过程中Like没有数据?
    鼠标放上图片移动,字体移动
    Excel
    参数无效。区域性ID2155(0X086B)不是受支持的区域性
    JVM指令集及各指令的详细使用说明[转的]
    BTrace使用简介
    ST表
    树剖模板
    AjaxControlToolkit中的CalendarExtender被遮挡及日期格式本地化解决方法
    Using Beyond Compare with TFS
  • 原文地址:https://www.cnblogs.com/xiaokeai0110/p/10087113.html
Copyright © 2011-2022 走看看