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. IDEA配置JDK版本的地方, 适用于Compilation failed: internal java compiler error

    错误原因: 1. 编译版本不匹配 2.当前项目jdk版本不支持 解决方法 查看项目的jdk 查看工程的jdk 查看java编译器版本 讲这些改成自己需要的版本, 一般就可以解决编译版本出现的错误

  2. 使用msf生成shellcode并用Go免杀?

    msf生成的裸马现在已经不行了,加壳也只能加冷门壳了,VMP,Shielden,upx不是失效就是效果很差,所以当下,得用shellcode来免杀了 msfvenom -a x86 --platfor ...

  3. python入门教程之四基本语法

    1Python 标识符 在 Python 里,标识符由字母.数字.下划线组成. 在 Python 中,所有标识符可以包括英文.数字以及下划线(_),但不能以数字开头. Python 中的标识符是区分大 ...

  4. [Web Server]Tomcat调优之工作原理、线程池/连接池

    1 Tomcat 概述 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛. 1.0 Tomcat 容器与原理 1.0.1 Tomcat组件构成 注意,如图所示,阴影部 ...

  5. JS引擎(2):Java平台上JavaScript引擎—Rhino/Nashorn概述

    可以后端开发的 javascript引擎有 Chrome V8 基于C++ java的Rhino引擎(JDK6被植入),Java8 被替换为Nashorn Rhino和Nashorn都是用Java实现 ...

  6. CommunityToolkit.Mvvm8.1 viewmodel源生成器写法(3)

    本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...

  7. Springboot集成MyBatis进行开发

    引入相关的依赖 <dependency> <groupId>junit</groupId> <artifactId>junit</artifact ...

  8. C# 从0到实战 基本类型

    C#语言的基本类型 与大多数编程语言一样,C#也有自己的基本类型,也称为内置类型.下面的表格就简单阐述了这些类型. C# 类型关键字 .NET 类型 bool System.Boolean byte ...

  9. Flowable启动报错problem during schema upgrade&&couldn‘t upgrade db schema:

    1.错误信息 problem during schema upgrade, statement alter table ACT_RU_VARIABLE add column SCOPE_ID_ var ...

  10. vue上传文件(原生方法)

    前言: 组件库的文件上传不适合项目,这里我们利用input标签实现文件上传 首先input type=file  标签是这个亚子的,而且样式不能改,我们利用css的方法,将一个定位到这个下面来,然后i ...