js 中的this 指向 一直是前端开发人员的一个痛点难点,项目中有很多bug往往是因为this指向不明确(this指向在函数定义时无法确定,只有在函数被调用时,才确定该this的指向为最终调用它的对象)而错误引起的,接下来就根据两个简单案例来深刻认识哈

【注】本案例使用vue 搭建的项目进行测试

一、创建 replaceContextInClass.js

先创建一个vue项目,在components下新增一个util目录在里面新建一个class


class ReplaceContextInClass {
constructor(name) {
this.name = name
window.golableGetName = this.getName
window.golableGetName2 = this.getName
window.golableGetName2 = window.golableGetName2.call(this)
}
getName() {
return this.name
}
} export default ReplaceContextInClass

二、再建个understanderContextInES5.js

再新增一个understanderContextInES5.js


window.pName = 'George'
var objDeclare = {
pName: 'Jeffery',
fun: function () {
var pName = 'Mars'
/**
* 此处没有使用this关键字,所以就近原则此处的pName就是 Mars
*/
console.log(pName) // Mars
/**
* 在understandThisScope.vue使用understandCEs5.fun()调用的fun方法
* 所以this为objDeclare他的pName值当然为 Jeffery了
*/
console.log(this.pName) // Jeffery function innerFun() {
var pName = 'Spark'
/**
* 此处没有使用this关键字,所以就近原则此处的pName就是 Spark
*/
console.log(pName) // Spark
/**
* 下面的innerFun()调用时由于没有使用任何对象,所以默认使用顶层对象window调用,
* 即可以理解为window.innerFun();故这里的this自然指向了window,
* 于是他的值;自然是最上面定义的George了
*/
console.log(this.pName) // George
}
innerFun()
}
}
module.exports = objDeclare

三、最后加个 understandThisScope.vue

然后在components目录下新增understandThisScope.vue


<template>
<div class="page-container">
<img src="../assets/logo.png">
<div>
<button @click="replaceThis">点击改变this</button>
</div>
</div>
</template> <script type="text/ecmascript-6">
import ReplaceContextInClass from './util/replaceContextInClass'
const understandCEs5 = require('./util/understanderContextInES5')
export default {
name: "testClassCall",
methods: {
replaceThis() {
let re = new ReplaceContextInClass('Evan')
/**
* 定义一个新对象
* 用于替换this指向
*/
let duplicateObj = {
name: 'Frank'
}
let res = re.getName.call(duplicateObj)
/**
* 使用call將class的this指向為duplicateObj所以值為 Frank
*/
console.log(res) // Frank
let gRes = window.golableGetName()
/**
* 該window調用時自身并沒有name,所以為空
*/
console.log(gRes) // ' '
let duplicateObj2 = {
name: 'Eric'
}
let gRes2 = window.golableGetName.call(duplicateObj2)
/**
* 使用call將class的this指向為duplicateObj2所以值為 Eric
*/
console.log(gRes2) // Eric
let gRes3 = window.golableGetName2
/**
* 其中使用call將對象this指向了類自己,所以該值為 Evan
*/
console.log(gRes3) // Evan
console.log('<-----------------------------------华丽分隔线-------------------------------------------->')
// eslint-disable-next-line
understandCEs5.fun() // 调用obj的fun方法
}
}
}
</script> <style scoped>
.page-container {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

四、修改main.js

我们修改哈main.js


// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './components/understandThisScope'
import router from './router' Vue.config.productionTip = false /* eslint-disable no-new */
/* no-unused-vars:0 */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})

最后完整的项目目录是果汁的

现在来运行起来验证哈,结果是酱紫的

最后看运行结果如图;这里就不做过多解释了,因为代码中有详细的解释

五、call和 bind的区别

这里还有一个值得注意的是在replaceContextInClass.js的构造中,我们使用了call来将绑定到window上的方法的this更改为当前类,但是会有一个问题,该call在类实例初始化时就会完成方法的调用(获取到getName()的返回值);这样如果后期该name发生改变那么取值就会不同步;

修改下replaceContextInClass.js


class ReplaceContextInClass {
constructor(name) {
this.name = name
window.golableGetName = this.getName
window.golableGetName2 = this.getName
window.golableGetName2 = window.golableGetName2.call(this)
window.golableGetName3 = this.getName
window.golableGetName3 = window.golableGetName3.bind(this)
}
getName() {
return this.name
}
changeName() {
this.name = 'Loren'
}
} export default ReplaceContextInClass

再修改下understandThisScope.vue


<template>
<div class="page-container">
<img src="../assets/logo.png">
<div>
<button @click="replaceThis">点击改变this</button>
</div>
</div>
</template> <script type="text/ecmascript-6">
import ReplaceContextInClass from './util/replaceContextInClass'
const understandCEs5 = require('./util/understanderContextInES5')
export default {
name: "testClassCall",
methods: {
replaceThis() {
let re = new ReplaceContextInClass('Evan')
re.changeName() // 调用change修改name的值
let gRes3 = window.golableGetName2
let gRes4 = window.golableGetName3()
/**
* 而的他使用call將對象this指向了類自己
* 并且在定义定义时就会调用getName()方法获取到name
* 将其保存到golableGetName2中,所以到再次
* re.changeName()修改name时它将不再发生改变
*/
console.log(gRes3) // Evan
/**
* 这个只是使用bind修改this指向
* 但并未立即调用 getName()
* 所以在 re.changeName()修改name
* 这里会获取到最新的Loren
*/
console.log(gRes4) // Loren
}
}
}
</script> <style scoped>
.page-container {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

最后运行

会发现call与bind修改的方法获取的值大不一样

探索JS中this的最终指向的更多相关文章

  1. 理解JS中的this的指向

    原文地址:https://www.cnblogs.com/pssp/p/5216085.html#1 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到 ...

  2. js中的this的指向问题

    this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象 this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调 ...

  3. 从Ecma规范深入理解js中的this的指向

    this是面向对象编程中的一个概念,它一般指向当前方法调用所在的对象,这一点在java.c++这类比较严格的面向对象编程语言里是非常明确的.但是在javascript中,this的定义要灵活许多,如果 ...

  4. js中函数this的指向

    this 在面试中,js指向也常常被问到,在开发过程中也是一个需要注意的问题,严格模式下的this指向undefined,这里就不讨论. 普通函数 记住一句话哪个对象调用函数,该函数的this就指向该 ...

  5. js 中onclick 事件 点击后指向自己的对象,查找或者添加属性 用关键字this 传入参数 (可以改变原标签css)

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. 浅谈js中的this关键字

    ---恢复内容开始--- this是JavaScript中的关键字之一,在编写程序的时候经常会用到,正确的理解和使用关键字this尤为重要.接下来,笔者就从作用域的角度粗谈下自己对this关键字的理解 ...

  7. JS中的继承实现方式

    第一种:通过prototype来实现 prototype.html <!DOCTYPE html><html lang="en"><head> ...

  8. React:JS中的this和箭头函数

    JS中的this和纯面向对象(java,c++)中的this有点不大一样,其原因就是作用域不同,导致JS中的this的指向不明确,在java中的this指当前对象的this或当前类的this,在JS中 ...

  9. 彻底理解js中this的指向,不必硬背。

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  10. 了解学习JS中this的指向

    [转] 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问 ...

随机推荐

  1. 【公式编辑测试】生成函数常用性质及其他(普通生成函数指数生成函数Dirichlet生成函数)

    目录 定义 普通生成函数OGF 指数生成函数 EGF Dirichlet生成函数 Notation OGF OGF property some OGF instances EGF EGF proper ...

  2. 【读书笔记】排列研究-模式避免-基础Pattern Avoidance

    目录 模式避免的定义 避免Pattern q 的n-排列计数\(S_n(q)\) q长度是2 q长度是3 对一些模式q,做\(S_n(q)\)的阶估计 Backelin, West, and Xin给 ...

  3. 【绘制分形图案】多重收缩打印机(MRCM)举例

    note 2020-08-05搬运 下面的内容来自我的CSDN博客 多重收缩打印机(MRCM)是生成分形图案的一种方法.主要思想还是多次迭代.   每次都是将上一次的输出拿来做线性仿射变换后重新组合在 ...

  4. Mybatis分页插件PageHelper的配置及使用方法

    尊重人家的知识成果 推荐 该作者总结的不错! --->> --->> @author 扎心了老铁 Mybatis分页插件PageHelper的配置及使用方法

  5. pack.json中的^ ~的区别

    在版本说明前面还有个符号:'^'(插入符号)和'~'(波浪符号),他们之间的区别:例如: '~'(波浪符号):他会更新到当前minor version(也就是中间的那位数字)中最新的版本.放到我们的例 ...

  6. Linux 端口及防火墙常用命令

    Linux 端口及防火墙操作 查看端口操作 一. netstat命令 -t (tcp) 仅显示tcp相关选项 -u (udp)仅显示udp相关选项 -n 拒绝显示别名,能显示数字的全部转化为数字 -l ...

  7. 如何用java校验SQL语句的合法性?(提供五种解决方案)

    方案一:使用JDBC API中提供的Statement接口的execute()方法 要在Java中校验SQL语句的合法性,可以使用JDBC API中提供的Statement接口的execute()方法 ...

  8. Python3.8环境安装PyHook3

    Python3.8环境安装PyHook3 1. 安装python对应版本的pyhook3网  址:https://pypi.org/project/PyHook3/#files如果没有对应版本,请下载 ...

  9. [Java]Maven构建时报错: "Error:java: 读取E:\XX\XXX..jar时出错; error in opening zip file"

    删除本地仓库中对应的jar包,pom.xml再reimport

  10. 【Note】矩阵加速

    感谢 \(\text{tidongCrazy}\) 倾情授课. 目录 基本形式 基础习题 P1962 斐波那契数列(例题) P4838 P哥破解密码(矩阵加速) 稍微up P1397 [NOI2013 ...