Home  >  Article  >  Web Front-end  >  Detailed explanation of function binding and class event binding functions in JavaScript in ES6

Detailed explanation of function binding and class event binding functions in JavaScript in ES6

小云云
小云云Original
2017-12-23 10:29:441887browse

This article mainly introduces the JavaScript implementation of function binding and class event binding in ES6, and analyzes the principles, implementation methods, related operating techniques and precautions of function binding and class event binding in ES6 in the form of examples. Friends in need can refer to it, I hope it can help everyone.

Function Binding

Arrow functions can bind this object, which greatly reduces the number of ways to explicitly bind this object (call, apply, bind). However, arrow functions are not suitable for all situations, so ES7 proposes the "function bind" operator to replace call, apply, and bind calls. Although this syntax is still an ES7 proposal, the Babel transcoder already supports it.

The function binding operator is two double colons ( :: ) side by side. The left side of the double colon is an object and the right side is a function. This operator will automatically bind the object on the left as the context (i.e. this object) to the function on the right.

foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
return obj::hasOwnProperty(key);
}

If the left side of the double colon is empty and the right side is a method of an object, it is equivalent to binding the method to the object.

var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;
let log = ::console.log;
// 等同于
var log = console.log.bind(console);

Since the double colon operator still returns the original object, chain writing can be used.

// 例一
import { map, takeWhile, forEach } from "iterlib";
getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));
// 例二
let { find, html } = jake;
document.querySelectorAll("p.myClass")
::find("p")
::html("hahaha");

Event binding in classes

Overview

ES6 provides classes, which brings great help to modularization. Binding events in a class is, firstly, to make the code structure clear, and secondly, so that the variables and methods of the class can be used. However, since the event callback function is not triggered by the instance object of the class, the this variable of the class cannot be accessed in the event callback function. In addition, we do not want the event callback function to be exposed to the outside world so that the caller cannot call it directly.

To put it simply, we hope:

1. The event callback function must be able to access the this variable of the class
2. The event callback function cannot be called directly

How Access the this of the class

Option 1: Save the this of the class as a local variable

The reference of this changes dynamically, but the reference of the local variable is clear, and, Local variables defined by a function are available throughout the function. So, we can use let that = this to save the this variable of the class.

class A{
  //绑定事件的方法
  bindEvent(){
   let that = this;
   this.button1.on('click',function(e){
      this.addClass('on'); //this指代所点的元素
      that.doSomething(); //that指向类的this
   })
  }
  doSomething(){
   //事件处理函数
  }
  //解绑事件
  unBindEvent(){
   this.button1.off();
  }
}

This method is only useful when using jquery, because the jquery unbinding event does not need to provide a callback function, just off directly. But there is a reason why native js needs to provide callback functions, because the same event of the same element can be bound to multiple callback functions, so you need to indicate which one to release.

Option 2: Use bind() to change the point of this

There is class A. In A, you need to add the mousemove event. Write the following code according to the requirements:

class A{
  //添加事件
  addEvent(){
    document.addEventListener( 'mousemove', onMouseMove, false );
  }
  //添加事件
  removeEvent(){
    document.removeEventListener( 'mousemove', onMouseMove , false );
  }
}
//事件回调函数中
function onMouseMove(event){
  console.log(this);  //#document
}

But , so you cannot get this of the class. onMouseMove's this will point to document. Because the event is added to the document, the event is naturally triggered by the document and onMouseMove is called for processing, so this in onMouseMove points to the document.

The more correct approach is to use the bind() function to change the pointer of this in onMouseMove, and at the same time move the event callback function outside the class:

class A{
  //添加事件
  addEvent(){
    document.addEventListener( 'mousemove', onMouseMove.bind(this), false );
  }
  //添加事件
  removeEvent(){
    document.removeEventListener( 'mousemove', onMouseMove.bind(this) , false );
  }
}
//事件回调函数中
function onMouseMove(event){
  console.log(this);
}

But this still has problems, the event is removed No more falling! Because this.bind() returns a new function every time it is called, the second parameter of

document.addEventListener( 'mousemove', onMouseMove.bind(this), false );

and

document.removeEventListener( 'mousemove', onMouseMove.bind(this), false );

is not the same.

The correct approach is: Save the result of bind() in a variable:

class A{
  constructor(){
    this._onMouseMove = onMouseMove.bind(this);  //看这里
  }
  //添加事件
  addEvent(){
    document.addEventListener( 'mousemove', this._onMouseMove , false );
  }
  //添加事件
  removeEvent(){
    document.removeEventListener( 'mousemove', this._onMouseMove , false );
  }
}
//事件回调函数中
function onMouseMove(event){
  console.log(this);
}

How to define a private event callback function

In Java, you don’t want to expose it to the outside world The method can be defined as a private method, but ES6 does not provide private methods and can only be simulated through some methods. However, the event callback function is special because the event must be removed in addition to being defined, which will cause additional trouble. But there is still a way:

Use Symbol variables to define

const _onMouseMove = Symbol("_onMouseMove");
class A{
  constructor(){
    this[_onMouseMove] = onMouseMove.bind(this);
  }
  //添加事件
  addEvent(){
    document.addEventListener( 'mousemove', this[_onMouseMove] , false );
  }
  //添加事件
  removeEvent(){
    document.removeEventListener( 'mousemove', this[_onMouseMove] , false );
  }
}
//事件回调函数中
function onMouseMove(event){
  console.log(this);
}

Symbol("_onMouseMove") will produce a unique value, which is generated when the object is created, so , the caller has no way to know this value when writing code, so it cannot call the method named with this value, thus defining a private method.

Related recommendations:

Examples to explain the usage of JavaScript function binding

Detailed explanation of how to use function binding code for JavaScript interaction

JavaScript function binding

The above is the detailed content of Detailed explanation of function binding and class event binding functions in JavaScript in ES6. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn