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. vmware workstation 版本合集

    各版本序列号 10.x:1Z0G9-67285-FZG78-ZL3Q2-234JG 11.x:YG74R-86G1M-M8DLP-XEQNT-XAHW2 12.x:ZC3TK-63GE6-481JY- ...

  2. C++/Qt网络通讯模块设计与实现(四)

    在C++/Qt网络通讯模块设计与实现(三)中提到了一个概念,即接受者所依附的线程:关注我微信公众号的技术朋友留言对该概念还是不解,这节就单独讲述这个概念的理论与实际应用,这种应用无处不在,因为与Qt的 ...

  3. Cesium 后处理(Post Process)

    原文地址:https://blog.csdn.net/ls870061011/article/details/123910821 作者:GIS李胜 为实现三维模型的更炫.更酷.更美观,Cesium在1 ...

  4. 5分钟带你彻底搞懂async底层实现原理!

    ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖.研究 async 的原理,就必须先弄清楚 Genera ...

  5. Qt连接不上Linux服务器?

    目录 1. Qt连接代码 2. 问题分析(按照顺序排除) 2.1 服务器IP是否能被Ping通? 2.2 客户端中的服务器IP和Port是否填写正确? 2.3 Linux的代码处理是否正确? 2.4 ...

  6. 【ACM算法竞赛日常训练】DAY4题解与分析【树】【子序列】| 组合数学 | 动态规划

    DAY4共2题: 树(组合数学) 子序列(dp,数学) 作者:Eriktse 简介:19岁,211计算机在读,现役ACM银牌选手力争以通俗易懂的方式讲解算法!️欢迎关注我,一起交流C++/Python ...

  7. 最新版本 Stable Diffusion 开源 AI 绘画工具之汉化篇

    目录 汉化预览 下载汉化插件一 下载汉化插件二 下载汉化插件三 开启汉化 汉化预览 在上一篇文章中,我们安装好了 Stable Diffusion 开源 AI 绘画工具 但是整个页面都是英文版的,对于 ...

  8. ACM-学习记录-DP-1

    DPL_1_A: Coin Changing Problem 每次均有两种选择,即选择当前的,即为在当前状态+1,否则维持原来的T[j+d[i]] #include<iostream> # ...

  9. 代码Bug太多?给新人Code Review头都大了?快来试试SpotBugs

    如果你需要一个自动化的工具帮助你或者你的团队发现代码中的缺陷,在提升代码质量同时减少人工Code Review的成本,那这篇文章非常的适合你.本文围绕SpotBugs与Gradle集成,将相关配置和使 ...

  10. 计网学习笔记七 IP protocol basic

    在这一节讲了IP协议的基本内容:包括IPv4提供的操作.数据报在IPv4下是怎么样的结构.数据报是怎样切片发送的.IPv4的编址方式有什么--IPv6在下一节讲网络层协议簇时细讲. IPv4协议的具体 ...