探索JS中this的最终指向
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的最终指向的更多相关文章
- 理解JS中的this的指向
原文地址:https://www.cnblogs.com/pssp/p/5216085.html#1 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到 ...
- js中的this的指向问题
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象 this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调 ...
- 从Ecma规范深入理解js中的this的指向
this是面向对象编程中的一个概念,它一般指向当前方法调用所在的对象,这一点在java.c++这类比较严格的面向对象编程语言里是非常明确的.但是在javascript中,this的定义要灵活许多,如果 ...
- js中函数this的指向
this 在面试中,js指向也常常被问到,在开发过程中也是一个需要注意的问题,严格模式下的this指向undefined,这里就不讨论. 普通函数 记住一句话哪个对象调用函数,该函数的this就指向该 ...
- js 中onclick 事件 点击后指向自己的对象,查找或者添加属性 用关键字this 传入参数 (可以改变原标签css)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 浅谈js中的this关键字
---恢复内容开始--- this是JavaScript中的关键字之一,在编写程序的时候经常会用到,正确的理解和使用关键字this尤为重要.接下来,笔者就从作用域的角度粗谈下自己对this关键字的理解 ...
- JS中的继承实现方式
第一种:通过prototype来实现 prototype.html <!DOCTYPE html><html lang="en"><head> ...
- React:JS中的this和箭头函数
JS中的this和纯面向对象(java,c++)中的this有点不大一样,其原因就是作用域不同,导致JS中的this的指向不明确,在java中的this指当前对象的this或当前类的this,在JS中 ...
- 彻底理解js中this的指向,不必硬背。
首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...
- 了解学习JS中this的指向
[转] 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问 ...
随机推荐
- CosineWarmup理论与代码实战
摘要:CosineWarmup是一种非常实用的训练策略,本次教程将带领大家实现该训练策略.教程将从理论和代码实战两个方面进行. 本文分享自华为云社区<CosineWarmup理论介绍与代码实战& ...
- java选择结构-switch
java选择结构-switch java的另一个多选择结构switch-case case中的value为常数值. 不加break,会一直执行到最后,包括default(case穿透) switch( ...
- KMP算法的研究
前脚学后脚忘,是时候给自己通俗易懂的总结一下了 KMP是什么 在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个字符串S内查找一个词W的出现位置.一个词在不 ...
- 案例(一) Z-Indexing Geometry
使用官方github包,部分解释来源于Viewer - Cesium Documentation Cesium.Ion.defaultAccessToken = " ...
- 手写Mybatis代码实现会出现的问题
实现自定义框架过程中遇到的问题及解决方案: 1.执行 Resources.class.getClassLoader().getResourceAsStream(path) 方法无法获得去字节输入流 解 ...
- day96:flask:flask-migrate&flask-session&蓝图Blueprint&蓝图的运行机制&基于flask仿照django进行项目架构
目录 1.flask-migrate 2.flask-session 3.蓝图:Blueprint 4.蓝图的运行机制 5.基于flask仿照django进行项目架构 1.准备工作 2.加载配置文件 ...
- day20:正则表达式
单个字符的匹配 findall(正则表达式,字符串) 把符合正则表达式的字符串存在列表中返回 预定义字符集(8) \d 匹配数字 \D 匹配非数字 \w 匹配数字字母下划线 \W 匹配非数字或字母或下 ...
- PHP安全有帮助的一些函数
安全是编程非常重要的一个方面.在任何一种编程语言中,都提供了许多的函数或者模块来确保程序的安全性.在现代网站应用中,经常要获取来自世界各地用户的输入,但是,我们都知道"永远不能相信那些用户输 ...
- memcache 安装及操作
memcache安装文件下载 http://pan.baidu.com/s/1hqRdW1Y 一 安装篇 1. 下载memcache的windows稳定版,解压放某个盘下面,比如在c:/memcach ...
- 为什么 APISIX Ingress 是比 Emissary-ingress 更好的选择?
本文从可扩展性和服务发现集成等多个维度对比了 APISIX Ingress 与 Emissary-ingress 的性能. 作者:容鑫,API7.ai 云原生技术工程师,Apache APISIX C ...