位置: 编程技术 - 正文

精通JavaScript的this关键字(javascript 语言精粹(修订版))

编辑:rootadmin

推荐整理分享精通JavaScript的this关键字(javascript 语言精粹(修订版)),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:javascript教程推荐知乎,javascript高手,好的javascript教程,javascript精髓,好的javascript教程,javascript编程精解,javascript精髓,javascript精髓,内容如对您有帮助,希望把文章链接给更多的朋友!

JS中的this关键字让很多新老JS开发人员都感到困惑。这篇文章将对this关键字进行完整地阐述。读完本文以后,您的困惑将全部消除。您将学会如何在各种不同的情形正确运用this。

我们和在英语、法语这样的自然语言中使用名词一样地使用this。比如,“John飞快地跑着,因为他想追上火车”。请注意这句话中的代指John的代名词“他”。我们原本也可以这样表达,“John飞快地跑着,因为John想追上火车”。按照正常的语言习惯,我们并不按第二种方式表达。如果我们真按第二种方式说话,我们的家人和基友一定会把我们当成怪胎。说不定不止家人,甚至连我们的酒肉朋友和同事都会远离我们。类似地,在JS中,我们把this关键字当成一种快捷方式,或者说是引用(referent)。this关键字指向的是当前上下文(context,下文中将会对此作专门的解释)的主体(subject),或者当前正在被执行的代码块的主体。

考虑以下代码:

如果我们使用person.firstName和person.lastName,某些情况下代码会变得模棱两可。例如,全局变量中有一个跟person同名的变量名。这种情况下,如果我们想要读取person.firstName的值,系统将有可能从全局变量的person变量中读取firstName属性(property)。这样一来,我们调试代码的时候很难发现错误。所以this并不只起到美化代码的作用,同时也是为了保证程序的准确性。这种做法实际上和前面讲到的“他”的用法一样,使得我们的代码更加清晰。“他”所引用的正是句首的“John”。

正如代名词“他”被用来代指句中的先行词(先行词就是代名词所指示的名词),this关键字以同样的方式来引用当前方法(function,也可以称为函数)所绑定(bound)的对象。this不只引用对象,同时包含了对象的值。跟先行词一样,this也可以被理解成在上下文中用来引用当前对象(又叫作“先行词对象”)的快捷方式(或者来适度减少歧义的替代品)。我们迟些会专门讲解“上下文”。

this关键字基本理论

首先我们得知道,对象(Object)有属性集(properties),所有的方法(function)也有属性集。运行到某个方法的时候就有了一个this属性—一个存储了调用该方法(准确地说是使用了this关键字的方法)的对象的值的变量。

this关键字始终指向一个对象并持有这个对象的值,尽管它可以出现在全局范围(global scope)方法(函数)以外的地方,但它通常出现在方法体中。值得注意的是,如果我们使用严格模式(strict mode),并在全局方法(global functions)或者没有绑定到任何对象的匿名方法中使用this关键字时,this将会指向undefined。

this被用在方法体中,比如方法A,它将指向调用方法A的对象的值。并不是任何情况我们都能找到调用方法A的对象名,这时候就用this来访问调用方法A的对象所拥有的方法和属性。this确实只是一个用来引用先行词—调用方法的对象—的快捷方式。

我们来仔细体会下面这段使用this的代码。

再考虑下面这段使用了this的jQuery示例。

我想详细地说一下上面这个jQuery示例:$(this)的使用,这是this的jQuery版本,它用于匿名方法中,这个匿名方法在button的单击事件里执行。这里之所以说$(this)被绑定到button对象,是因为jQuery库把$(this)绑定到调用click方法的对象上。因此,尽管$(this)被定义在一个自身无法访问“自身”变量的匿名方法里,$(this)仍会指向button对象。

请注意,button是一个HTML页面的DOM元素,它同时是一个对象:在上面的例子中,因为我们把它包装在了jQuery的$()方法里,所以它是一个jQuery对象。

this关键字的核心

下面这条规则可以帮助你彻底搞懂this关键字:如果一个方法内部使用了this关键字,仅当对象调用该方法时this关键字才会被赋值。我们估且把使用了this关键字的方法称为“this方法”。

尽管看上去this引用了它在代码中所存在于的对向,事实上在方法被调用之前它并没有被赋值,而赋给它的值又严格地依赖于实际调用“this方法”的对象。this通常会被赋予调用对象的值,下面有一些特殊情况。

全局范围里的this

在全局域中,代码在浏览器里执行,所有变量和方法都属于window对象。因而当我们在全局域中使用this关键字的时候,它会被指向(并拥有)全局变量window对象。如前所述,严格模式除外。window对象是JS一个程序或一张网页的主容器。

因而:

对付this有绝招

当方法内使用了this关键字时,这几种情况最容易引起误解:方法被借用;把方法赋值给某个变量;方法被用作回调函数(callback),被作为参数传递;this所在的方法是个闭包(该方法是一个内部方法)。针对这几种情况,我们将逐一攻破。在此之前,我们先简单介绍一下“上下文”(context)。

JS当中的上下文跟这句话中的主语(subject)类似:“John是赢家,他还了钱”。这句话的主语是John。我们也可以说这句话的上下文是John,因为我们在这句话中关注的是John,即使这里有一个“他”字来代指John这个先行词。正如我们可以使用分号来切换句子的主语一样,通过使用不同的对象来对方法进行调用,当前的上下文对象同样可以被切换。

类似地,以下JS代码:

现在我们开始正式讨论应付this关键字的绝招,例子里包含了this所引发的错误以及解决方案。

1.当this被用作回调函数传入其它方法

当我们把一个使用了this关键字的方法当成参数作为回函数的时候,麻烦就来了。例如:

上面的代码中,我们把user.clickHandler当成回调函数传入$(“button”)对象的click事件,user.clickHandler中的this将不再指向user对象转。谁调用了这个包含this的方法this就会指向谁。真正调用user.clickHandler的对象是button对象—user.clickHandler会在button对象的单击方法里执行。

注意,尽管我们使用user.clickHandler来调用clickHander方法(我们也只能这么做,因为clickHandler是定义在user对象上的),clickHandler方法本身会被现在被this所指向的上下文对象所调用。所以this现在指向的是$(“button”)对象。

精通JavaScript的this关键字(javascript 语言精粹(修订版))

当上下文改变时—当我们在其它对象而非原对象上执行某个方法的时候,显然this关键字不再指向定义了this关键字的原对象。

解决方案:

由于我们真的很想让this.data指向user对象的data属性,我们可以使用Bind/ Apply/ Call等方法来强制改变this所指向的对象。本系列的其它篇目将专门对Bind/ Apply/ Call进行讲解,文中介绍了如何在不同的情况强制改变this的值的方法。与其在本文大篇幅讨论,我强烈建议大家直接去读另外的篇目(译者注:晚些时候放出这里所说的“其它篇目”)。

为了解决前面代码中的问题,我们可以使用bind方法。

针对下面这行代码:

$ ("button").click (user.clickHandler);我们可以用bind方法把clickHandler绑定的user对象上:

$("button").click (user.clickHandler.bind (user)); // P. Mickelson .闭包中的this

在内部方法中,或者说闭包中使用this,是另一个很容易被误解的例子。我们必须注意的是,内部方法不能直接通过使用this关键字来访问外部方法的this变量,因为this变量 只能被特定的方法本身使用。例如:

因为匿名方法中的this不能访问外部方法的this,所以在非严格模式下,this指向了全局的window对象

解决方案:

在进入forEach方法之前,额外使用一个变量来引用this。

正如下面的代码,很多JS开发人员喜欢使用变量that来设置this的值。但我个人不太喜欢用that这个名字,我喜欢使用让人一眼就能看懂this到底指向谁的那种名字,所以上面的代码中我使用了theUserObj = this。

3.方法被赋值给某个变量

this关键字有时候很调皮,如果我们把一个使用了this关键字的方法赋值给一个变量,我们来看会有什么有趣的事发生:

// data变量是一个全局变量var data = [{ name: "Samantha", age: },{ name: "Alexis", age: }];

var user = { // 而这里的data是user的一个属性 data: [{ name: "T. Woods", age: }, { name: "P. Mickelson", age: }], showData: function(event) { var randomNum = ((Math.random() * 2 | 0) + 1) - 1; // 随机生成1或0 //这句话会从数组data里随机显示人名和岁数 console.log(this.data[randomNum].name + " " + this.data[randomNum].age); }

}

// 把user.showData方法赋值给变量 showUserDatavar showUserData = user.showData;

//执行showUserData方法,结果将 来自全局的data数组而非user对象的data属性showUserData(); // Samantha (来自全局变量data)//解决方案:通过使用bind方法来显式设置this的值//把showData方法绑定到user对象上var showUserData = user.showData.bind(user);

//现在结果将来自user对象,因为this关键字已经被强制绑定到user对象上了showUserData(); // P. Mickelson

4.借用方法带来的问题

JS开发中,借用方法(borrowing methods)很常见。

我们来看下面的代码:

avg方法的this关键字指向的是gameController对象,如果使用appController调用该方法,this将会指向appController(但事实上这并不是我们期望的结果,因为我们只想借用方法的实现逻辑而非具体的数据来源)。

解决方案:

为了保证gameController只借用appController的avg方法的逻辑,我们使用apply方法:

gameController只借用了appController的avg方法,这时this将指向gameController,因为我们把gameController作为apply方法的第一个参数进行传递。apply方法的第一个参数将会显式设置this的取值。

结语

希望您在文中有所收获。现在你可以使用文中介绍的绝招(bind方法,apply方法,call方法,以及把this赋值给 一个变量)来对付跟this相关的任何问题。

正如已经了解到的,this在上下文改变、被作为回调函数使用、被不同的对象调用、或者方法被借用的情况下,this将一直指向调用当前方法的对象。

JS三级可折叠菜单实现方法 本文实例讲述了JS三级可折叠菜单实现方法。分享给大家供大家参考,具体如下:.ASPX代码:%@PageLanguage="C#"AutoEventWireup="true"CodeFile="NavigateMenu.aspx.cs"Inherit

JavaScript+CSS实现的可折叠二级菜单实例 本文实例讲述了JavaScript+CSS实现的可折叠二级菜单。分享给大家供大家参考,具体如下:.aspx文件:%@PageLanguage="C#"AutoEventWireup="true"CodeFile="NavigateMenu.aspx.c

JavaScript实现斗地主游戏的思路 本文知识给大家分享一下使用js写斗地主的思路,代码写的不好,还请见谅。这里说说斗地主主要包含的功能:洗牌,发牌,玩家出牌、电脑出牌,出牌

标签: javascript 语言精粹(修订版)

本文链接地址:https://www.jiuchutong.com/biancheng/378998.html 转载请保留说明!

上一篇:javascript计时器编写过程与实现方法(js中计时器怎么写)

下一篇:JavaScript+CSS实现的可折叠二级菜单实例(javascript 操作css)

  • 利润表中其他业务利润是什么
  • 党费会计核算科目说明
  • 农产品为什么价格低
  • 债权重组会计分录大全
  • 固定资产的确认条件是什么
  • 工会应付下级经费
  • 宣传费税前扣除标准
  • 出现销项负数
  • 工地工资是人走账清吗
  • 金税三期个人所得税怎么下载
  • 大病医疗保险为什么贵
  • 没签合同怎么交社保
  • 贸易公司给客户开发票
  • 如何计算房地产容积率与土地面积
  • 股东借款可以转为认缴出资
  • 分公司固定资产转入总公司的分录怎么做?
  • 初级考试备考计划
  • 设备改造时各项支出的会计处理?
  • 企业打款认证计入什么科目
  • 发票需要写真名吗
  • 科技服务业是怎么分类的
  • 合伙企业收到分红需要交所得税吗
  • windows10预览版
  • 公司代缴社保公司吃亏吗
  • 融资租赁货车
  • 几个项目可以合到一起招标吗
  • 应收账款转让的风险
  • 上季度成本多结转了怎么调
  • 资产负债表的编制依据是会计恒等式
  • 投资性房地产后续计量从成本模式转为公允价值模式属于
  • 支付临时工的工资怎么做账
  • 销售折扣属于什么项目
  • 企业工资薪金和职工福利费等支出税前扣除问题的公告
  • 企业为员工缴纳社保标准及流程
  • multipartfile 多文件上传
  • matlab绘图总结
  • 完美解决在ThinkPHP控制器中命名空间的问题
  • 【K210】K210学习笔记七——使用K210拍摄照片并在MaixHub上进行训练
  • mysqldump 导出数据
  • 什么发票才能做账务处理
  • 企业自建办公楼需要开发资质吗
  • 股东分红方式如何约定
  • 增值税发票价税合计不能超过多少
  • 技术人员工资计入什么科目
  • 废料处理没开票销项税
  • 从农民手中购买粮食税率
  • 现代服务业如何提高服务的效率和质量
  • 税额抵减的账务处理
  • 可以先注销银行信用卡吗
  • 哪些发票可以报账
  • 会计审计属于什么类别
  • 管理会计在企业中的地位如何?为什么
  • 电脑开机密码忘记了怎么打开
  • Windows时间同步时出错该怎么解决?
  • linux使用cp
  • smsss.exe - smsss是什么进程
  • splash.exe - splash是什么进程 有什么作用
  • sccenter.exe - sccenter是什么进程 有什么用
  • win81和win10
  • win10自带邮箱无法使用126
  • 微信小程序wx.request实现后台数据交互功能分析
  • ExtJS扩展 垂直tabLayout实现代码
  • perl删除文件夹
  • Unity同时接入ShareSdk和微派支付sdk(二)
  • unity编译速度吃什么硬件?
  • javascript用处
  • jquery弹出div遮罩层
  • js设置图片边框
  • javascript有哪些常用的属性和方法
  • express后端
  • 我国是多久取消税收的
  • 一般纳税人业务招待费可以抵扣吗
  • 2006年发生哪一些大案
  • 成都税务局网站首页
  • 遵从和尊重
  • 买车可以抵扣企业所得税多少
  • 开票信息哪里查询
  • 山西省地方税务总局官网
  • 辽宁朝阳丧葬费标准2022
  • 依法行政的观念
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设