ES6中javascript实现函数绑定及类的事件绑定功能详解


Posted in Javascript onNovember 08, 2017

本文实例讲述了ES6中javascript实现函数绑定及类的事件绑定功能的方法。分享给大家供大家参考,具体如下:

函数绑定

箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以 ES7 提出了 “ 函数绑定 ” ( function bind )运算符,用来取代call、apply、bind调用。虽然该语法还是 ES7 的一个提案,但是 Babel 转码器已经支持。

函数绑定运算符是并排的两个双冒号( :: ),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即 this 对象),绑定到右边的函数上面。

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);
}

如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。

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

由于双冒号运算符返回的还是原对象,因此可以采用链式写法。

// 例一
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("div.myClass")
::find("p")
::html("hahaha");

类中事件绑定

概述

ES6提供了类,给模块化带来了很大的帮助。在类里面绑定事件,一来是为了使得代码结构清晰,二来是为了可以使用类的变量和方法。但是,由于事件的回调函数并不是由类的实例对象触发,所以,事件回调函数里面并不能访问类的this变量。另外,我们也不希望事件回调函数对外暴露,免得调用者直接调用。

简单来说,我们就希望:

1. 事件回调函数要能访问类的this变量
2. 事件回调函数不能直接调用

如何访问类的this

方案一:将类的this保存成一个局部变量

this的指代是动态改变的,但是局部变量的指代却是明确的,并且,函数定义的局部变量在整个函数里面都可以用。所以,我们可以使用let that = this保存类的this变量。

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();
  }
}

这种方法只在使用jquery时有用,因为jquery解绑事件不需要提供回调函数,直接off就可以了。但是原生js需要提供回调函数也有它的道理,因为同一个元素的同一种事件可以绑定多个回调函数,所以你需要指出释放哪一个。

方案二:使用bind()改变this的指向

有类A,在A中要添加mousemove事件,根据需求写出下面代码:

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

但是,这样获取不到类的this。onMouseMove的this将会指向document。因为事件是添加到document上的,所以自然是由document触发事件并调用onMouseMove进行处理,所以onMouseMove中的this指向document。

比较正确的做法是:使用bind()函数改变onMouseMove中this的指向,同时将事件回调函数移到类外面

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

但是这样仍然存在问题,事件移除不掉了!因为this.bind()每次调用都会返回一个新的函数,所以:

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

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

两者的第二个参数并不相同。

正确的做法是:bind()的结果保存到一个变量中:

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);
}

如何定义私有的事件回调函数

在Java中,不想对外暴露的方法可以定义为私有方法,但是ES6并没有提供私有方法,只能通过一些办法模拟。但是,事件回调函数比较特别,因为事件除了定义,还要移除,这会带来额外的麻烦。但还是有办法的:

使用Symbol变量来定义

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")会产生一个唯一的值,这个值是在对象创建的时候才生成的,所以,调用者没有办法在写代码时知道这个值的,所以,就无法调用使用这个值命名的方法了,这样就定义了一个私有方法。

更多相关内容可查看本站专题:《ECMAScript6(ES6)入门教程》、《JavaScript数组操作技巧总结》、《JavaScript字符与字符串操作技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript错误与调试技巧总结》及《javascript面向对象入门教程》

希望本文所述对大家基于ECMAScript的程序设计有所帮助。

Javascript 相关文章推荐
js实现的网站首页随机公告随机公告
Mar 14 Javascript
js电信网通双线自动选择技巧
Nov 18 Javascript
解析js中获得父窗口链接getParent方法以及各种打开窗口的方法
Jun 19 Javascript
JavaScript根据数据生成百分比图和柱状图的实例代码
Jul 14 Javascript
编写高效jQuery代码的4个原则和5个技巧
Apr 24 Javascript
JS实现距离上次刷新已过多少秒示例
May 23 Javascript
js select实现省市区联动选择
Apr 17 Javascript
在JS中a标签加入单击事件屏蔽href跳转页面
Dec 16 Javascript
详解使用vue-router进行页面切换时滚动条位置与滚动监听事件
Mar 08 Javascript
简单谈谈React中的路由系统
Jul 25 Javascript
js中如何完美的解析数据
Mar 18 Javascript
vuex管理状态仓库使用详解
Jul 29 Javascript
手把手教你使用vue-cli脚手架(图文解析)
Nov 08 #Javascript
vue中实现滚动加载更多的示例
Nov 08 #Javascript
详解使用webpack打包编写一个vue-toast插件
Nov 08 #Javascript
结合mint-ui移动端下拉加载实践方法总结
Nov 08 #Javascript
详解如何使用webpack在vue项目中写jsx语法
Nov 08 #Javascript
thinkjs 文件上传功能实例代码
Nov 08 #Javascript
基于jQuery的$.getScript方法去加载javaScript文档解析
Nov 08 #jQuery
You might like
探讨:使用XMLSerialize 序列化与反序列化
2013/06/08 PHP
php简单获取文件扩展名的方法
2015/03/24 PHP
PHP优化之批量操作MySQL实例分析
2020/04/23 PHP
javascript 强制刷新页面的实现代码
2009/12/13 Javascript
jQuery中与toggleClass等价的程序段 以及未来学习的方向
2010/03/18 Javascript
jQuery中:only-child选择器用法实例
2015/01/03 Javascript
js实现checkbox全选、不选与反选的方法
2015/02/09 Javascript
Javascript中的匿名函数与封装介绍
2015/03/15 Javascript
js实现圆盘记速表
2015/08/03 Javascript
jQuery中的Deferred和promise 的区别
2016/04/03 Javascript
javascript运算符——位运算符全面介绍
2016/07/14 Javascript
js判断空对象的实例(超简单)
2016/07/26 Javascript
浅谈js中调用函数时加不加括号的问题
2016/07/28 Javascript
在微信、支付宝、百度钱包实现点击返回按钮关闭当前页面和窗口的方法
2016/08/05 Javascript
浅谈SpringMVC中post checkbox 多选框value的值(隐藏域方式)
2018/01/08 Javascript
JS实现访问DOM对象指定节点的方法示例
2018/04/04 Javascript
关于TypeScript模块导入的那些事
2018/06/12 Javascript
在layui中layer弹出层点击事件无效的解决方法
2019/09/05 Javascript
angular组件间通讯的实现方法示例
2020/05/07 Javascript
vue 中使用print.js导出pdf操作
2020/11/13 Javascript
[02:54]DOTA2英雄基础教程 暗影牧师戴泽
2013/12/05 DOTA
Python 代码性能优化技巧分享
2012/08/07 Python
Python操作RabbitMQ服务器实现消息队列的路由功能
2016/06/29 Python
基于python中staticmethod和classmethod的区别(详解)
2017/10/24 Python
python使用matplotlib画饼状图
2018/09/25 Python
python爬虫 2019中国好声音评论爬取过程解析
2019/08/26 Python
利用Bootstrap实现漂亮简洁的CSS3价格表实例源码
2017/03/02 HTML / CSS
Linux文件系统类型
2012/02/15 面试题
大学毕业生通用自荐信范文
2013/10/31 职场文书
毕业生自我鉴定范文
2013/11/08 职场文书
大学运动会通讯稿
2014/01/28 职场文书
优乐美广告词
2014/03/14 职场文书
婚礼秀策划方案
2014/05/19 职场文书
CSS3实现的文字弹出特效
2021/04/16 HTML / CSS
Python办公自动化之教你用Python批量识别发票并录入到Excel表格中
2021/06/26 Python
Redis基本数据类型List常用操作命令
2022/06/01 Redis