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 相关文章推荐
Jquery进度条插件 Progress Bar小问题解决
Jul 12 Javascript
E3 tree 1.6在Firefox下显示问题的修复方法
Jan 30 Javascript
javascript实现确定和取消提示框效果
Jul 10 Javascript
javascript仿百度输入框提示自动下拉补全
Jan 07 Javascript
AngularJS入门教程之AngularJS模型
Apr 18 Javascript
JS封装的选项卡TAB切换效果示例
Sep 20 Javascript
微信JSAPI Ticket接口签名详解
Jun 28 Javascript
javaScript和jQuery自动加载简单代码实现方法
Nov 24 jQuery
JS实现留言板功能[楼层效果展示]
Dec 27 Javascript
关于JavaScript中高阶函数的魅力详解
Sep 07 Javascript
详解Node.js使用token进行认证的简单示例
May 25 Javascript
关于element的表单组件整理笔记
Feb 05 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
5.PHP的其他功能
2006/10/09 PHP
PHP XML数据解析代码
2010/05/26 PHP
深入解析php中的foreach问题
2013/06/30 PHP
PHP中redis的用法深入解析
2014/02/20 PHP
php获取QQ头像并显示的方法
2014/12/23 PHP
php中get_defined_constants函数用法实例分析
2015/05/12 PHP
JS 控件事件小结
2012/10/31 Javascript
表单元素的submit()方法和onsubmit事件应用概述
2013/02/01 Javascript
jQuery中对节点进行操作的相关介绍
2013/04/16 Javascript
jquery获取select选中值的方法分析
2015/12/22 Javascript
基于RequireJS和JQuery的模块化编程日常问题解析
2016/04/14 Javascript
Web纯前端“旭日图”实现元素周期表
2017/03/10 Javascript
微信小程序 es6-promise.js封装请求与处理异步进程
2017/06/12 Javascript
Vue slot用法(小结)
2018/10/22 Javascript
Vue打包部署到Nginx时,css样式不生效的解决方式
2020/08/03 Javascript
基于Vue.js+Nuxt开发自定义弹出层组件
2020/10/09 Javascript
[01:08:48]LGD vs OG 2018国际邀请赛淘汰赛BO3 第三场 8.25
2018/08/29 DOTA
python线程池的实现实例
2013/11/18 Python
利用 python 对目录下的文件进行过滤删除
2017/12/27 Python
使用PyQt4 设置TextEdit背景的方法
2019/06/14 Python
Pandas的read_csv函数参数分析详解
2019/07/02 Python
pycharm 安装JPype的教程
2019/08/08 Python
PyInstaller的安装和使用的详细步骤
2020/06/02 Python
容易被忽略的Python内置类型
2020/09/03 Python
解决H5的a标签的download属性下载service上的文件出现跨域问题
2019/07/16 HTML / CSS
DJI大疆德国官方商城:大疆无人机
2018/09/01 全球购物
俄罗斯在线手表和珠宝商店:AllTime
2019/09/28 全球购物
英国领先的男装设计师服装独立零售商:Repertoire Fashion
2020/10/19 全球购物
圣彼得堡鲜花配送:Semicvetic
2020/09/15 全球购物
ajax是什么及其工作原理
2012/02/08 面试题
四年大学生活的自我评价范文
2014/02/07 职场文书
旅游安全协议书
2014/04/21 职场文书
客运企业隐患排查工作方案
2014/06/06 职场文书
2014和解协议书范文
2014/09/15 职场文书
《我要的是葫芦》教学反思
2016/02/18 职场文书
Python人工智能之混合高斯模型运动目标检测详解分析
2021/11/07 Python