在事件处理函数中的 this

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在事件处理函数中的 this相关的知识,希望对你有一定的参考价值。

参考技术A javascript 中, this 是一个很重要的关键字。此前写过一篇文章: JavaScript中 的 this 真没那么难理解 。本文内容主要是,针对事件处理函数中如何使用 this 的几种方法及区别。

我们将在本文讨论的问题是:在函数 doSomething() 中 this 指向的是什么?

在 JavaScript 中, this 总是指我们正在执行的函数的“owner”,或者更确切地说,是指函数作为其方法的对象。当我们在页面中定义我们函数 doSomething() 时,它的“owner”是页面,或者更确切地说,是 JavaScript 的 window 对象(或全局对象)。但是, onclick 属性归它所属的 html 元素所有。

这种“ownership”是 JavaScript 面向对象方法的结果。有关更多信息,请参阅 作为关联数组的对象 页面。

如果我们在没有任何准备的情况下执行 doSomething() ,则 this 关键字指向 window 对象,该函数会尝试更改 window 对象的 style.color 。由于 window 没有 style 对象,该函数会失败并产生 JavaScript 错误(TypeError)。

如果我们想充分利用 this ,我们必须注意使用它的函数是由正确的 HTML 元素“拥有”的。换句话说,我们必须将函数复制到我们的 onclick 属性。 传统的事件注册 会处理它。

该函数被完整地复制到 onclick 属性(现在变成了一个方法)。因此,如果执行事件处理程序, this 会指向 HTML 元素,并且它的 color 会发生变化。

当然是我们可以将函数复制到多个事件处理程序。每次 this 将指向正确的 HTML 元素:

因此,你可以最大程度地使用它。每次调用该函数时, this 指的是当前正在处理事件的 HTML 元素,即“拥有” doSomething() 副本的 HTML 元素。

但是,如果你使用 内联事件注册 :

你不要复制功能!相反,你指向它,差异至关重要。 onclick 属性不包含实际的函数,而只是一个函数调用:

所以这相当于,前往 doSomething() 并执行它。当我们到达 doSomething() 时, this 关键字再次指向全局 window 对象,并且该函数返回错误消息(TypeError)。

如果你想使用 this 来访问正在处理事件的 HTML 元素,你必须确保 this 关键字实际上已写入 onclick 属性。只有在这种情况下, this 才指向事件处理程序注册到的 HTML 元素。因此,如果你这样处理:

你将会得到:

如你所见, this 关键字存在于 onclick 方法中。因此 this 指向 HTML 元素。

但是,如果你这样处理:

你得到的是:

这仅仅是对函数 doSomething() 的引用。 onclick 方法中不存在 this 关键字,因此 this 不指向 HTML 元素。

以下情况 this 会写入 onclick 方法:

以下情况 this 指向 window 对象:

请注意 attachEvent() 的存在。 Microsoft 事件注册模型 的主要缺点是 attachEvent() 创建对函数的引用而不复制它。因此,有时无法知道当前是哪个 HTML 处理该事件。

使用内联事件注册时,你还可以将 this 发送到该函数,以便你仍然可以使用它:

React--事件处理

React中的事件处理

  React 中文官网中有提到:"你必须谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的" 。 "这并不是 React 的特殊行为;它是函数如何在 JavaScript 中运行的一部分"  。因此,如果忘记绑定,对应函数的 this 的值会是 undefined。当然,在没有用到函数的 this 的时候,绑定就不是必要的了。下面主要是从两个部分对 React 中的事件处理进行理解:第一部分是事件函数仅在在当前组件中进行事件处理,第二部分是将事件函数传递给其他组件进行事件处理。每部分分为用到 this 的事件函数,和没有用到 this 的事件函数。第一部分中例子使用没有传递参数,第二部分中使用参数。最后例中也同样展示了函数的几种绑定方式。

 

一、事件处理:事件函数仅在在当前组件中(例中没有传递参数,传递参数的情况与之类似)

1、没有用到事件处理程序中的 this 时

代码如下:

 

 1 var React = require(‘react‘);
 2 var ReactDOM = require(‘react-dom‘);
 3 class Index extends React.Component {
 4     constructor() {
 5         super(); //调用基类的所有的初始化方法
 6          7     };
 8 
 9     showName(){
10         alert(‘username: "Guang"‘);
11     }
12 
13     render() {
14         return (
15             <div>
16                         {/* 传递数据: 不传递参数或者有传递参数但是不涉及事件处理程序中的 this ,对事件处理程序的绑定:不是必须的 */}
17                         <input type="button" value="显示名称 没有绑定" onClick={this.showName}></input><br></br>
18                         <input type="button" value="显示名称 箭头函数绑定" onClick={()=>this.showName()}></input><br></br>
19                         <input type="button" value="显示名称 bind绑定" onClick={this.showName.bind(this)}></input>                        
20                         {/* 也可以在构造函数中通过: this.showName=this.showName.bind(this); 语句来绑定 */}                
21             </div>
22         );
23     }
24 }
25 ReactDOM.render(
26     <Index/>, document.getElementById(‘example‘));

 

运行结果:

 

技术分享图片

 

2、用到事件处理程序中的 this 时

代码如下:

 1 var React = require(‘react‘);
 2 var ReactDOM = require(‘react-dom‘);
 3 class Index extends React.Component {
 4     constructor() {
 5         super(); //调用基类的所有的初始化方法
 6         this.state = {
 7             username: "Guang",
 8             age: 20,
 9             newage1:"9 changeAge1",
10             newage2:"99 changeAge2",
11             newage3:"999 changeAge3"
12         };     
13     };
14 
15     changeAge1(){
16         this.setState({age:this.state.newage1});
17     };
18     changeAge2(){
19         this.setState({age:this.state.newage2});
20     };
21     changeAge3(){
22         this.setState({age:this.state.newage3});
23     };
24 
25     render() {
26         return (
27             <div>
28                 <p>age:{this.state.age}</p>
29                 {/* 传递数据: 不传递参数但是涉及到事件处理程序中的 this ,对事件处理程序的绑定:是必须的 */}
30                 <input type="button" value="更改 age, 没有绑定" onClick={this.changeAge1}></input><br></br>
31                 <input type="button" value="更改 age, 箭头函数绑定" onClick={()=>this.changeAge2()}></input><br></br>
32                 <input type="button" value="更改 age, bind绑定" onClick={this.changeAge3.bind(this)}></input>                        
33                 {/* 也可以在构造函数中通过: this.changeAge3=this.changeAge3.bind(this); 语句来绑定 */}                
34             </div>
35         );
36     }
37 }
38 ReactDOM.render(
39     <Index/>, document.getElementById(‘example‘));

运行结果: 可以看到,在需要用到事件处理程序中的 this 时,如果没有对事件处理程序进行绑定,会报错。而对事件处理程序进行绑定后正确运行

技术分享图片

  

 

 

二、事件处理:事件函数传递到其他组件中(例中有传递参数,没有传递参数的情况与之类似)

 

1、没有用到事件处理程序中的 this 时(当传递的参数只有事件对象无其他数据时)

父组件代码如下:

 1 var React = require(‘react‘);
 2 var ReactDOM = require(‘react-dom‘);
 3 import BodyChild from ‘./components/bodychild‘;
 4 class Index extends React.Component {
 5 
 6     // 该函数将获取的事件保持在 this.state.eventobject 中
 7     parentEventHandler(e){
 8         alert(e.target.value);
 9     }
10 
11     render() {
12         return (
13             <div>                    
14                     {/* 事件处理:事件函数传递给其他组件 */}
15                     {/* 传递的数据: 传递参数 只有事件对象 无其他数据 但是没有用到事件处理程序的 this */}
16                     <BodyChild 
17                         // 匿名函数赋值给子组件的 this.props.childAnonymous ,匿名函数后面的 bind(this) 是传入当前上下文,使得匿名函数内的 this 为当前上下文
18                         childAnonymous={function(e){this.parentEventHandler(e)}.bind(this)}
19                         // 箭头函数将函数 this 设置为当前上下文
20                         childArrow={(e)=>this.parentEventHandler(e)}
21                         // 使用 bind 将函数 this 设置为当前上下文
22                         childBind={this.parentEventHandler.bind(this)}
23                         // 也可以在构造函数中通过: this.childBind=this.parentEventHandler.bind(this) 语句来绑定                        
24                     />    
25             </div>
26         );
27     }
28 }
29 ReactDOM.render(
30     <Index/>, document.getElementById(‘example‘));

 

子组件代码如下:

 1 import React from ‘react‘;
 2 export default class BodyChild extends React.Component{
 3 
 4   render(){
 5     return(
 6       <div>                         
 7             {/* 匿名函数后面的 bind(this) 是传入当前上下文,使得匿名函数内的 this 为当前上下文 */}
 8             <input type="button" value="childAnonymous 匿名函数传参 无绑定" onClick={function(e){this.props.childAnonymous(e)}}></input><br></br>
 9             <input type="button" value="childAnonymous 匿名函数传参 匿名函数使用 bind 绑定" onClick={function(e){this.props.childAnonymous(e)}.bind(this)}></input><br></br>
10             
11             {/* 
12                 对于箭头函数绑定过程的个人理解
13                 使用箭头函数 this 被设置为当前箭头函数所在的上下文,其原理有点类似于下面的过程(并不是说过程就是这样的,只是原理与之类似,个人理解)                
14                 源代码:                  
15                 <input type="button" onClick={(parameters)=>FunctionName(parameters)}/></input>
16                 过程原理:
17                 function anonymous(parameters){
18                   // 通过某种方式,将函数绑定当前上下文,将 this 设置为当前上下文(比如: FunctionName.bind(当前上下文))
19                   // 通过某种方式,将参数 parameters 传递给 FunctionName(比如:FunctionName(parameters))
20                 }
21                 <input type="button" onClick=anonymous /></input>                            
22             */}           
23             <input type="button" value="childArrow 箭头函数传参 箭头函数绑定" onClick={(e)=>this.props.childArrow(e)}></input><br></br>            
24           
25             {/* 通过箭头函数的方式,事件对象必须显式的进行传递,但是通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。 */}
26             <input type="button" value="childBind 直接传参 bind 绑定" onClick={this.props.childBind.bind(this)}></input>
27         </div>
28     )
29   }
30 }

 

运行结果:可以看到,在没有用到 this 时候,由于需要通过 this 来获取当前组件中的函数,因此需要绑定函数

 

 

 

2、用到函数的 this 的情况(由于不需要用到 this 时,在不同组件间传递函数都需要绑定,因此,用到 this 的情况下必然要绑定)

 

以上是关于在事件处理函数中的 this的主要内容,如果未能解决你的问题,请参考以下文章

Javascript - 事件处理程序中的箭头函数?

在事件处理程序中使用 this

浏览器事件

EventEmitter事件处理器中的this问题

Vue 事件处理

从事件处理程序回调调用的函数中“this”的值?