如何理解React中的this指向,React的用法是什么
Admin 2022-10-19 群英技术资讯 490 次浏览
众所周知,React 的设计是响应式的,使用者无需操纵 DOM,操纵数据,页面就会渲染更新。
数据一变就更新,是更新所有的 DOM 吗?当然不是,哪些变了就重新渲染哪些。那就要对数据变化前后的 DOM 进行比较。直接对比真实 DOM 吗?这样性能会很低,React 比较的是虚拟 DOM,虚拟 DOM 也是对象,只不过相较真实 DOM而言,少了很多属性,更“轻”。
如何写虚拟 DOM 呢?原生JS我们可以使用 document.createElement() 方法,创建节点。React 中也可以通过 React.createElement(component, props, children),但是呢这种写法遇见多层嵌套,就能让人眼花缭乱。于是 JSX “横空出世”,JSX 其实就是,React.createElement 的语法糖,但是我们用起来更加方便,可以直接写成 <p id="test">hello</p> 这种形式。
但是呢问题又又来了!JSX 语法是不被 webpack 识别的,webpack 默认只能处理 .js 后缀名的文件,所以需要借助 Babel 这个 JavaScript 编译器,而 babel 开启了严格模式 **
import React, { Component } from 'react' export default class index extends Component { // speak(){ // console.log(this)//输出undefined // } speak = () => console.log( this ) //输出该组件 render() { return ( <div> <button onClick={ this .speak}>按钮</button> </div> ) } } |
this 本质上就是指向它的调用者,this 是在函数运行时才绑定,JS 里边普通函数都是 window 调用的,所以指向 window,开启了严格模式之后是 undefined。
( function (){ console.log( this ) //window })() |
在 JSX 中传递的事件不是一个字符串(在原生 JS 的中监听事件,采用的是回调函数的形式,在Vue中给监听事件传递的是字符串变量),而是一个函数(如上面的:onClick={this.speak}),此时onClick即是中间变量,最终是由React调用该函数,而因为开启了严格模式的缘故,this 是undefined,所以处理函数中的this指向会丢失。
事实上我们需要的是 this 指向当前实例化对象,无疑会使代码编写方便很多。类式组件里边有两地方的this恰好指向当前实例化对象。
类式组件里面的构造器里面的this是指向实例对象的,这是 ES6 类的特性,
众所周知 Javascript 里面是没有像 C++,JAVA 里面的的类的概念,ES6 类的实现也是基于原型链来实现的,
在 ES6 以前实例化一个对象应该这样:
function Animal(name, age) { this .name = name this .age = age } Animal.prototype.say = function () { console.log( this .name) } const Dog = new Animal( 'dog' , 3) Dog.say() //会在控制台打印出dog |
其中的 new 运算符,先产生了一个空对象 {},然后生成一个 this 指针,将 this 指针指向这个空对象;运行构造函数时,就相当于{}.name=dog,{}.age=3一样的为这个对象动态添加属性。最后将这个生成好的对象付给 Dog,
当我们使用 ES6 的 class 来声明上面这个类的话,代码如下:
class Animal { constructor(name, age) { this .name = name this .age = age } say() { console.log( this .name) } } const Dog = new Animal( 'dog' , 3) Dog.say() //会在控制台打印出dog |
类实现和上面应该大差不差,所以this是指向实例对象的。
render 函数里面的 this,也是指向实例的。为啥呢?
首先 render 方法是在类式组件的原型上边的,React发现组件是使用类定义的时候,后边就会 new 出来该类的实例,注意这个实例是 React 帮你 new 出来的,随后实例调用 render 方法,将虚拟 DOM 转换为真实 DOM,所以 render 中的this 就是指向实例咯,毕竟是他调用的嘛!,类似的呢,render 是一个生命周期钩子,那其他的生命周期钩子里面的 this也是指向实例组件的。
解决 this 问题呢,要有两个知识储
(1)bind
call apply bind 都是定义在函数原型上边的,用来改变函数 this 指向,传入的第一个参数是 this,后面的参数就是fun1的参数
区别:
let aa = { fun1: function (a,b){ console.log( this ) console.log(a-b); } } let bb = { fun2: function (a,b){ console.log( this ) console.log(a+b); } } aa.fun1.call(bb,11,22); //bb-11 bb.fun2.apply(aa,[11,22]); //aa 33 aa.fun1.bind(bb,11,22)(); //bb -11 |
(2)箭头函数
箭头函数:箭头函数并不会创建自己的执行上下文,所以箭头函数中的this都是外层的this,会向外作用域中,一层层查找this,直到有 this 的定义
const A = { arrow:() =>{ console.log( this ) //window }, func: function (){ this .arrow() //window console.log( this ) //A setTimeout(() => { console.log( this ) //A }); } } A.arrow() A.func() |
解决方法俺会两,嘿嘿!
import React, { Component } from 'react' export default class index extends Component { constructor(){ super () this .speak = this .speak.bind( this ) /*解决类中的this问题:this.speak = this.speak.bind(this),构造器里面的this默认指向实例对象, 实例对象通过原型链在类的原型上找着fnc函数,通过bind函数将其this指向改为实例对象,并返回一个新的函数 再将这个新的函数给实例,并取名为fnc*/ } speak(){ console.log( this ) //输出当前实例对象 } render() { return ( <div> <button onClick={ this .speak}>按钮</button> </div> ) } } |
import React, { Component } from 'react' export default class index extends Component { speak = () =>{ console.log( this ) } render() { return ( <div> <button onClick={ this .speak}>按钮</button> </div> ) } } //需要传参的话,可以使用函数柯里化的思想 |
使用箭头函数来解决性能会比较低,因为箭头函数不是方法,它们是匿名函数表达式,所以将它们添加到类中的唯一方法是赋值给属性。前面介绍ES6的类的时候可以看出来,ES 类以完全不同的方式处理方法和属性
方法被添加到类的原型中,而不是每个实例定义一次。
类属性语法是为相同的属性分配给每一个实例的语法糖,实际上会在 constructor里面这样实现:
constructor(){ super () this .speak = () => {console.log( this )} } |
这意味着新实例被创建时,函数就会被重新定义,丢失了JS实例共享原型方法的优势。而方法一,只是在生成实例时多了一步 bind 操作,在效率与内存占用上都有极大的优势
关于“如何理解React中的this指向,React的用法是什么”的内容今天就到这,感谢各位的阅读,大家可以动手实际看看,对大家加深理解更有帮助哦。如果想了解更多相关内容的文章,关注我们,群英网络小编每天都会为大家更新不同的知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
前端编写测试用例时,在测试界面上的一些效果时,通常都希望能够模拟一些用户操作,而模拟用户操作最主要的方式就是用代码触发指定事件。通常一些元素上会自带一些触发事件的方法
vue用@表示src文件夹,引入时找文件路径更方便,下面这篇文章主要给大家介绍了关于vue配置根目录(用@代表src目录)的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
本文主要介绍了 vue全局引入scss,我们在写VUE的时候,会使用scss,也会做一些通用样式,方便使用,在写好的通用样式的时候,每次都要单文件导入,刚开始写的时候,感觉还好,后面工程量大了后,就显得麻烦,那么本文就全局导入scss样式,下面来看详细内容,需要的朋友可以参考一下
Axios+Spring Boot实现文件上传和下载 本文实例为大家分享了Axios+Spring Boot实现文件上传和下载的具体代码,供大家参考,具体内容如下 1.所用技术 前端:Vue + Axios 后端:Springboot + SpringMVC 2.单文件上传 后端代码 只需要使用MultipartFile类配合RequestBody注解即可 @PostMapping("your/path") public ResultData courseCoverUpload(@RequestBody MultipartFil ...
Vue Router是Vue.js (opens new window)官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌,这篇文章主要给大家介绍了关于vue3使用vue-router的相关资料,需要的朋友可以参考下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008