JS 中几种处理’this’指向的方式
码农天地 -我喜欢在JS中更改函数执行上下文的指向,也称为 this 指向。
例如,咱们可以在类数组对象上使用数组方法:
const reduce = Array.prototype.reduce;function sumArgs() { return reduce.call(arguments, (sum, value) => { return sum += value; });}sumArgs(1, 2, 3); // => 6另一方面,this 很难把握。
咱们经常会发现自己用的 this 指向不正确。下面的教你如何简单地将 this 绑定到所需的值。
在开始之前,我需要一个辅助函数execute(func),它仅执行作为参数提供的函数。
function execute(func) { return func();}execute(function() { return 10 }); // => 10现在,继续理解围绕this错误的本质:方法分离。
1.方法分离问题
假设有一个类Person包含字段firstName和lastName。此外,它还有一个方法getFullName(),该方法返回此人的全名。如下所示:
function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.getFullName = function() { this === agent; // => true return `${this.firstName} ${this.lastName}`; }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'可以看到Person函数作为构造函数被调用:new Person('前端', '小智')。函数内部的 this 表示新创建的实例。
getfullname()返回此人的全名:'前端 小智'。正如预期的那样,getFullName()方法内的 this 等于agent。
如果辅助函数执行agent.getFullName方法会发生什么:
execute(agent.getFullName); // => 'undefined undefined'执行结果不正确:'undefined undefined',这是 this 指向不正确导致的问题。
现在在getFullName() 方法中,this的值是全局对象(浏览器环境中的 window )。this 等于 window,${window.firstName} ${window.lastName} 执行结果是 'undefined undefined'。
发生这种情况是因为在调用execute(agent.getFullName)时该方法与对象分离。基本上发生的只是常规函数调用(不是方法调用):
execute(agent.getFullName); // => 'undefined undefined'// 等价于:const getFullNameSeparated = agent.getFullName;execute(getFullNameSeparated); // => 'undefined undefined'这个就是所谓的方法从它的对象中分离出来,当方法被分离,然后执行时,this 与原始对象没有连接。
为了确保方法内部的this指向正确的对象,必须这样做
以属性访问器的形式执行方法:agent.getFullName()
或者静态地将this绑定到包含的对象(使用箭头函数、.bind()方法等)方法分离问题,以及由此导致this指向不正确,一般会在下面的几种情况中出现:
回调
// `methodHandler()`中的`this`是全局对象setTimeout(object.handlerMethod, 1000);在设置事件处理程序时
// React: `methodHandler()`中的`this`是全局对象<button onClick={object.handlerMethod}> Click me</button>接着介绍一些有用的方法,即如果方法与对象分离,如何使this指向所需的对象。
2. 关闭上下文
保持this指向类实例的最简单方法是使用一个额外的变量self:
function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; const self = this; this.getFullName = function() { self === agent; // => true return `${self.firstName} ${self.lastName}`; }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'execute(agent.getFullName); // => '前端 小智'getFullName()静态地关闭self变量,有效地对this进行手动绑定。
现在,当调用execute(agent.getFullName)时,一切工作正常,因为getFullName()方法内 this 总是指向正确的值。
3.使用箭头函数
有没有办法在没有附加变量的情况下静态绑定this?是的,这正是箭头函数的作用。
使用箭头函数重构Person:
function Person(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.getFullName = () => `${this.firstName} ${this.lastName}`;}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'execute(agent.getFullName); // => '前端 小智'箭头函数以词法方式绑定this。简单来说,它使用来自其定义的外部函数this的值。
建议在需要使用外部函数上下文的所有情况下都使用箭头函数。
4. 绑定上下文
现在让咱们更进一步,使用ES6中的类重构Person。
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } getFullName() { return `${this.firstName} ${this.lastName}`; }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'execute(agent.getFullName); // => 'undefined undefined'不幸的是,即使使用新的类语法,execute(agent.getFullName)仍然返回“undefined undefined”。
在类的情况下,使用附加的变量self或箭头函数来修复this的指向是行不通的。
但是有一个涉及bind()方法的技巧,它将方法的上下文绑定到构造函数中:
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.getFullName = this.getFullName.bind(this); } getFullName() { return `${this.firstName} ${this.lastName}`; }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'execute(agent.getFullName); // => '前端 小智'构造函数中的this.getFullName = this.getFullName.bind(this)将方法getFullName()绑定到类实例。
execute(agent.getFullName) 按预期工作,返回'前端 小智'。
5. 胖箭头方法
bind 方式有点太过冗长,咱们可以使用胖箭头的方式:
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } getFullName = () => { return `${this.firstName} ${this.lastName}`; }}const agent = new Person('前端', '小智');agent.getFullName(); // => '前端 小智'execute(agent.getFullName); // => '前端 小智'胖箭头方法getFullName =() =>{…}绑定到类实例,即使将方法与其对象分离。
这种方法是在类中绑定this的最有效和最简洁的方法。
6. 总结
与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this。
在类中,可以使用bind()方法手动绑定构造函数中的类方法。当然如果你不用使用 bind 这种冗长方式,也可以使用简洁方便的胖箭头表示方法。
更多JavaScript知识请关注PHP中文网JavaScript视频教程栏目
以上就是JS 中几种处理’this’指向的方式的详细内容,更多请关注php中文网其它相关文章!
微信分享相关标签:JS this本文转载于:CSDN,如有侵犯,请联系a@php.cn删除上一篇:如何检测一个函数是否是JavaScript原生函数下一篇:js中闭包的概念相关文章
相关视频
JS中this究竟指向什么?JavaScript中this绑定方式总结java中this关键字的四种用法是什么JS干货分享—-this指向问题JS 中几种处理’this’指向的方式JavaScript比较运算符JavaScript中的条件语句网友评论
文明上网理性发言,请遵守 新闻评论服务协议
我要评论立即提交专题推荐独孤九贱-php全栈开发教程全栈 100W+
主讲:Peter-Zhu 轻松幽默、简短易学,非常适合PHP学习入门
玉女心经-web前端开发教程入门 50W+
主讲:灭绝师太 由浅入深、明快简洁,非常适合前端学习入门
天龙八部-实战开发教程实战 80W+
主讲:西门大官人 思路清晰、严谨规范,适合有一定web编程基础学习
作者信息尚
认证0级讲师
最近文章增加redis命令的方法514SpringBoot整合Redis缓存的方法介绍684layui中动态设置checkbox选中状态的方法介绍990发布技术文章最新文章热门排行JS 如何获取扫码枪输入数据一起看看JavaScript如何获取页面上被选中的文字现代JavaScript使用技巧之ES6中的简写语法用JavaScript获取伪元素(Pseudo-Element)属性的方法详解如何用JavaScript避免代码的重复执行如何用js统计字符串中每个字符出现的次数?JavaScript判断"字典"为空的方法8个问题测试你的JavaScript基础RN布局的实例详解jQ选择器汇总JS是什么意思json格式是什么?json格式文件怎么打开?vue.js中created方法的使用详解echarts柱状图颜色设置:echarts柱状图如何设置不同颜色?(代码)js数组如何删除指定位置的元素?删除指定位置元素的2种方法怎样实现Vue项目中使用Vux推荐视频教程Javascript趣味课堂JavaScript基础入门及设计模式视频教程JavaScript核心编程视频教程JavaScript标准参考手册视频教程分类php视频教程html视频教程css视频教程JS视频教程jQuery视频教程mysql视频教程Linux视频教程Python视频教程article_status = 469925;网站首页 PHP视频PHP实战PHP代码PHP手册词条手记编程词典php中文网:公益在线php培训,帮助PHP学习者快速成长! 合肥彼岸互联信息技术有限公司
Copyright 2014-2020 https://www.php.cn/ All Rights Reserved | 皖B2-20150071-9 皖公网安备 34010402701654号 关于我们免责申明赞助与捐赠广告合作
座机号码:0551-64933227 安徽省合肥市政务新区置地广场D座2101
var _hmt = _hmt || [];(function(){var hm = document.createElement("script");hm.src="//hm.baidu.com/hm.js?8cc45d54c337ca616c34b1cf747da91c";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();(function(){var bp = document.createElement('script');var curProtocol = window.location.protocol.split(':')[0];if(curProtocol === 'https'){bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';}else{bp.src = 'http://push.zhanzhang.baidu.com/push.js';};var s = document.getElementsByTagName("script")[0];s.parentNode.insertBefore(bp, s);})();$('.content').viewer();