资讯专栏INFORMATION COLUMN

【译】javascript的this关键词理解

tainzhi / 1183人阅读

摘要:在中,当使用关键字调用函数构造函数时,函数构造函数中也有这个概念,但是它不是惟一的规则,而且常常可以引用来自不同执行上下文的不同对象。因此,我们使用调用函数,可以看到这是对象,并且的属性是正常的。

一直以来,javascript里边的this都是一个很难理解的东西,之前看的最多的就是阮一峰老师关于this的理解:

http://www.ruanyifeng.com/blo...

http://www.ruanyifeng.com/blo...

今天在留言区发现了一国外大神关于this的理解,借助翻译工具读了一下原文,相对来说是最好的关于理解this的文章,就翻译了一下,也算是记录一下。

JavaScript的一个常用特性是“this”关键字,但它也常常是该语言中最令人困惑和误解的特性之一。“this”到底是什么意思?它是如何决定的?

本文试图澄清这种困惑,并以一种清晰的方式解释这个问题的答案。

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

在JavaScript中,当使用“new”关键字调用函数构造函数时,函数构造函数中也有这个概念,但是它不是惟一的规则,而且“this”常常可以引用来自不同执行上下文的不同对象。如果您不熟悉JavaScript的执行上下文,我建议您阅读我关于这个主题的另一篇文章(本人注:文章找不到了)。谈得够多了,让我们来看一些JavaScript例子:

// 全局作用域

foo = "abc";
alert(foo); // abc

this.foo = "def";
alert(foo); // def

无论何时在全局上下文中使用关键字“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()中,如果该对象的值是实际的boat对象,它将发出警报,并警告该对象的size属性。因此,我们使用boat.boatInfo()调用函数,可以看到这是boat对象,并且boat的size属性是正常的。

然后我们创建另一个对象bigBoat,它的size属性为big。然而,bigBoat对象没有一个boatInfo()方法,因此我们使用bigBoat从boat复制该方法。boatInfo = boat.boatInfo。现在,当我们调用bigBoat.boatInfo()并输入函数时,我们看到它不等于boat, size属性现在是big。为什么会这样?这个值在boatInfo()中是如何变化的?

您必须意识到的第一件事是,任何函数中的这个值都不是静态的,它总是在每次调用函数时确定的,但是在函数实际执行之前,它是代码。函数内部的值实际上是由父作用域提供的,在父作用域中调用函数,更重要的是,函数语法是如何编写的。

每当调用一个函数时,我们必须查看方括号/圆括号“()”的左边。如果在括号的左边我们可以看到一个引用,那么传递给函数调用的“this”的值就是该对象所属的值,否则它就是全局对象。让我们来看一些例子:

function bar() {
    alert(this);
}
bar(); // global - 因为方法bar()在调用时属于全局对象

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

如果到目前为止一切都很清楚,那么上面的代码显然是有意义的。通过用两种不同的方式编写call / invoke语法,我们可以在同一个函数中更改“this”的值,从而使事情变得更加复杂:

var foo = {
    baz: function() {
        alert(this);
    }
}
foo.baz(); // foo - 因为baz在调用时属于foo对象

var anotherBaz = foo.baz;
anotherBaz(); // global - 因为方法anotherBaz()在调用时属于全局对象,而不是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,它在调用时属于全局对象

另一个经常被问到的问题是如何在事件处理程序中确定关键字“this”?答案是,事件处理程序中的“this”总是指向它所触发的元素。我们来看一个例子:

I am an element with id #test
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()时,它会发出未定义的警报,因为doAlert()属于全局对象。然后我们写myElem。onclick = doAlert,它将函数doAlert()复制到myElem的onclick()事件。这基本上意味着无论何时触发onclick(),它都是myElem的一个方法,这意味着“This”的值就是myElem对象。

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

总结

希望今天的博客文章已经澄清了对“this”这个关键字的任何误解,你可以一直知道“this”的正确值。我们现在知道,“this”的值从来不是静态的,它的值取决于函数是如何调用的。

原文:http://davidshariff.com/blog/...

欢迎关注小程序,感谢您的支持!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103818.html

相关文章

  • 理解JavaScript:new 关键

    摘要:原理是类的构造函数被调用,并且实例化了新的对象。尽管的语法非常相同,但使用在底层还是会引发不同行为没有构造函数首先,我们并不是必须要用一个类来生成对象。构造函数只不过是在调用时关键字放在其前面的普通方法而已。 由于存在海量的库和工具,以及各种各样简化你开发的玩意儿,很多程序员开始在不深入了解底层的情况下开发应用。JavaScript就是这种现象的代言人。JavaScript作为一种最复...

    陆斌 评论0 收藏0
  • JavaScript面试问题:事件委托和this

    摘要:主题来自于的典型面试问题列表。有多种方法来处理事件委托。这种方法的缺点是父容器的侦听器可能需要检查事件来选择正确的操作,而元素本身不会是一个监听器。 showImg(http://fw008950-flywheel.netdna-ssl.com/wp-content/uploads/2014/11/Get-Hired-Fast-How-to-Job-Search-Classifieds...

    浠ラ箍 评论0 收藏0
  • []带你理解 Async/await

    摘要:所以是在一秒后显示的。这个行为不会耗费资源,因为引擎可以同时处理其他任务执行其他脚本,处理事件等。每个回调首先被放入微任务队列然后在当前代码执行完成后被执行。,函数是异步的,但是会立即运行。否则,就返回结果,并赋值。 「async/await」是 promises 的另一种更便捷更流行的写法,同时它也更易于理解和使用。 Async functions 让我们以 async 这个关键字开...

    xiaochao 评论0 收藏0
  • this 是什么?JavaScript 对象内部工作原理

    摘要:关键字会实例化一个新的对象实例,并在执行构造函数时将指向该实例。原文链接译是什么对象的内部工作原理 原文链接:What is this? The Inner Workings of JavaScript Objects (需要梯子) 原文作者:Eric Elliott 译文永久链接:【译】什么是 this?JavaScript 对象的内部工作原理 译者:士心 翻译目的:函数动...

    Hwg 评论0 收藏0
  • [] 你想知道关于 JavaScript 作用域一切

    摘要:原文链接原文作者你想知道的关于作用域的一切译中有许多章节是关于的但是对于初学者来说甚至是一些有经验的开发者这些有关作用域的章节既不直接也不容易理解这篇文章的目的就是为了帮助那些想更深一步学习了解作用域的开发者尤其是当他们听到一些关于作用域的 原文链接: Everything you wanted to know about JavaScript scope原文作者: Todd Mott...

    Flands 评论0 收藏0

发表评论

0条评论

tainzhi

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<