设为首页 加入收藏

TOP

理解并掌握 JavaScript 中 this 的用法(一)
2015-08-31 21:23:34 来源: 作者: 【 】 浏览:56
Tags:理解 掌握 JavaScript this 用法

按:本文原文来自 java script.isSexy 这个网站。这篇文章和文中提到的另一篇文章解决了我一直以来对 thisapply, call, bind 这三个方法的困惑。我看过很多国内相关的技术文章,没有一篇能让我彻底理解这些概念的。因此我决定把它译过来,不要让更多的初学者像我一样在这个问题上纠结太长时间。



预备知识:java script 基础知识
阅读时间:约 40 分钟


在 java script 中,this 这个关键字常常困扰着初学者甚至一些进阶的开发者。这篇文章旨在完完全全阐明 this。当你读完本文之后,你就再也不会为 this 所困惑了。你将会理解 this 的各种使用场景,包括那些最难懂的情形。


我们使用 this 的方式和在英语或法语中使用代词的方式十分类似。我们会这样写「李华正在飞快地跑着,因为正在赶火车。」注意这里代词「他」的用法。我们也可以这样写:「李华正在飞快地跑着,因为李华正在赶火车。」我们通常不会把「李华」这个名字像这样重复使用,因为这样显得很神经。类似地,在 java script 中,我们使用 this 作为一种指代。它指代一个对象(object),也就是那个上下文中的主语,或者说运行时的主体。考虑下面这个例子:


如果我们使用 person.firstNameperson.lastName 这种写法的话,我们的代码就会变得有歧义。假设有一个全局变量(我们或许有意为之,或许根本没有意识到)的名字也叫 person ,那么 person.firstName 将会尝试读取那个全局变量 person 中的 firstName 属性,这将可能导致极难调试的错误。所以我们使用 this 关键字,不仅仅是因为这看起来十分优雅,还因为这样使用更加准确。使用 this 消除了我们代码中的歧义,就像在上文中使用「他」让我们的话显得更加清晰一样。它让我们明白我们想要指代的李华就是句子刚开头提到的那个李华。


就像代词「他」用来指代之前提到的人一样,this 这个关键字也是用来指代那个被当前函数(就是使用了 this 的函数)绑定的对象。this 这个关键字不仅仅是指代那个对象,并且包含了那个对象的值。这很类似代词,this 可以被视作是指代「上下文」中对象(也称为「祖先对象」)的一种便捷的方式(同时也是一种没有歧义的替换)。我们将在后面学习更多关于「上下文」 的概念。


首先,我们已经知道在 java script 中,函数和对象一样都有属性。而当一个函数执行的时候,它就获得了 this 这个属性。而 this 其实就是一个具有调用当前函数的对象的值的变量。


this 这个变量 永远 指向 一个 对象,并且拥有这个对象的值。虽然 this 可以在全局作用域中出现,但它通常还是会在函数体内或对象的方法内。有一点要注意的是,当我们使用严格模式(strict mode)的时候,this 在全局函数中和匿名函数中的值是未定义的(undefined),不指向任何一个对象。


this 在一个函数体内出现的时候(设为函数 A ),它包含了调用函数 A 的那个对象的值。我们需要使用 this 来读取调用函数 A 的那个对象的方法或是属性。而这在我们不知道那个对象的名字,甚至有时候那个对象没有名字的情况下就变得尤为重要。实际上,this 真的仅仅就是对「祖先对象」,或者说调用这个函数的那个对象,的一个便捷的指代而已。


我们用一个例子来展示 java script 中 this 的一些基本用法,也来回顾一下上文的内容:


再来看看 jQuery 中 this 用法的例子:


我来解释一下上面的这个 jQuery 示例:$(this) 是 jQuery 中与 java script 中 this 类同的语法,它被用在一个匿名函数中,而这个匿名函数在一个按钮的 click() 方法中被执行。$(this) 之所以具有这个按钮对象的值是因为 jQuery 库把 $(this) 和那个调用了 click 方法的对象手动 绑定 (bind)在一起了。 因此,即使 $(this) 是在一个匿名函数中被定义,并且自身不能读取外部函数中的 this 变量,它仍然能够具有那个 jQuery 按钮对象 ($("button")) 的值。


注意,按钮(button)是一个 HTML 页面上的 DOM 元素,同时也是一个对象;在上面这个例子中的按钮是一个 jQuery 对象,因为我们把它包装在 jQuery 的 $() 函数中了。


如果你理解了 java script this 的以下这个原则的话,那你对 this 这个关键字就会有一个清晰的认识了:只有一个对象调用了包含 this 的函数的时候,this 才会被赋值。我们不妨把包含 this 的函数称作 this 函数


在一个对象方法中定义的 this 看起来好像指向了这个对象本身,但仍然只有在某个对象调用了这个 this 函数 的时候它才被赋值。并且被赋的那个值 只依赖于 调用了 this 函数 的那个对象。虽然在大多数情况下, this 都是那个调用了 this 函数 的那个对象,但也有一些情况不是这样的。我将会在后文中讲到这一点。


在全局作用域中,当代码在浏览器中执行的时候,所有的全局变量和函数都被定义在 window 对象上。因此,当我们在全局函数中使用 this 的时候,它会指向全局 window 对象并且拥有它的值(除非在严格模式下),此时的 this 就成了整个 java script 应用程序或者说整个网页的主容器。


所以:


this 关键字在以下场景中常常被误解:当我们借用一个使用了 this 的方法的时候;当我们把一个只用了 this 的方法赋给一个变量的时候;当一个使用了 this 的方法被当作回调函数传入的时候;当 this 在闭包中使用的时候。我们能过举例来详细地解释在上面的每一种情形中如何使 this 拥有合适的值。


在下面这些情景中,this 关键字可能会变得十分难以理解。我们在示例中同时给出了解决有关 this 使用错误的方案。


当我们把含有 this 的方法当做回调函数的时候代码往往变得十分难以理解。比如:


在上面的代码中,按钮 ($("button")) 是一个对象,我们把 user.clickHandler 传入它的 click() 方法作为一个回调函数,这时候我们就明白 user.clickHandler 方法里面的 this 已经不再指向 user 这个对象了。因为 this 是定义在 user.clickHandler 方法里的,所以它现在指向那个调用了 user.clickHandler 的对象。而那个对象就是 button 对象。也就是说,user.clickHandler 将会在 button 对象的 click 方法中被执行。


注意在调用 clickHandler() 时,我们虽然写成了 user.clickHander 的形式(事实上我们必须这么写,因为 clickHandler 是在 user 对象中被定义的),但 clickHandler 还会在 button 对象的上下文中被执行,this 也因而指向了 button 对象。


讲到这里,我们应该发现当上下文发生变化的时候,换句话说就是当我们在别的对象中调用了本对象内定义的方法的时候,this 关键字就不再指向定义 this 时的那个对象了,而是指向了调用了那个 this 所在方法的对象。


解决 this 方法被当作回调函数传递时指向错误的方法:


因为我们确实想要让 this.data 指向 user 对象的 data 属性,我们可以使用 bind(), apply(), call() 这三个方法来显式地设置 this 的值。


我还写了另一篇文章,java scrip

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Java访问权限控制 下一篇Java 中关于System property 之 f..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: