当前位置:首页 > 日记 > 正文

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

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

本文实例讲述了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中清空数组的三种方式

JavaScript中清空数组的三种方式

数组,三种,清空,方式,电脑软件,方式1,splicevar ary = [1,2,3,4]; ary.splice(0,ary.length); console.log(ary); // 输出 [],空数组,即被清空了 方式2,length赋值为0 这种方式很有意思,其它语言如Java,其数组的length是只读的,不能被赋值。如int[…

Vue.js自定义指令的用法与实例解析

Vue.js自定义指令的用法与实例解析

自定义指令,实例,电脑软件,Vue,js,市面上大多数关于Vue.js自定义指令的文章都在讲语法,很少讲实际的应用场景和用例,以致于即便明白了怎么写,也不知道怎么用。本文不讲语法,就讲自定义指令的用法。自定义指令是用来操作DOM的。尽管Vue推崇数据…

jQuery制作全屏宽度固定高度轮播图

jQuery制作全屏宽度固定高度轮播图

全屏,轮播图,宽度,实例,高度,前端新手自己写的,练习一下基本功,也是留下的第一次记录html部分div class="cm-banner"> <div class="cm-banner-list"> <ul id="cm_banner_list"> <!--图片宽度和高度在css中定为1920x300--> …

excel 公式转为文本的方法

excel 公式转为文本的方法

方法,文本,公式,电脑软件,excel,  Excel中的公式是较为常用的功能,具体该如何把公式转为文本呢?下面是小编带来的关于excel 公式转为文本的方法,希望阅读过后对你有所启发!excel 公式转为文本的方法:  公式转文本步骤1:选中J2单元格开始的J…

ps怎么制作透明背景的logo图标?

ps怎么制作透明背景的logo图标?

图标,透明背景,电脑软件,ps,logo,ps中想要制作一个透明背景的lo,但导入的图却有白色背景,该怎么办呢?下面我们就来看看详细的处理方法。软件名称:Adobe Photoshop 8.0 中文完整绿色破解版软件大小:150.1MB更新时间:2015-11-041、首先我打开一张个…

JavaScript之排序函数_动力节点Jav

JavaScript之排序函数_动力节点Jav

排序,节点,函数,学院,动力,排序算法排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个对象呢?直接比较数学上的大小是没有意义的,因此,比较的…

Ai怎么复制呢?AI复制方法介绍

Ai怎么复制呢?AI复制方法介绍

方法,电脑软件,Ai,AI,在绘制图形的过程中,我们经常可能会遇到要使用相同的图形或者元素,重新绘制,有时候也不一定一模一样,这时候最好的办法就是复制一个。那么,怎么复制呢?下面就为大家详细介绍一下,来看看吧!步骤:1、为了方便讲解,我们先任意新建一…

微信小程序 滚动到某个位置添加cla

微信小程序 滚动到某个位置添加cla

位置,效果,代码,程序,电脑软件,微信小程序滚动到某个位置添加class效果<scroll-view scroll-y="true" style="height:100vh;" bindscrolltoupper="upper" bindscrolltolower="lower" bindscroll="scroll" scroll-top="{{scrollY…

Visual Studio寻找C#程序必要的运

Visual Studio寻找C#程序必要的运

库文件,运行,程序,电脑软件,Visual,  在工程打包中,有时候很头痛的就是运行所需要的库文件不能够全面的包含进来,特别是有时候调用了一系列外部扩展。对于这些问题,我们可以借用Visual Studio的打包功能帮助我们寻找软件运行必须的库文件。…

js 获取json数组里面数组的长度实

js 获取json数组里面数组的长度实

数组,长度,实例,电脑软件,js,作为一个前端页面开发者第一次处理json数据,遇到了‘js 获取json数组里面数组的长度'?竟然不知道 json没有.length属性(真是要嘲讽下自己),少壮不努力老大徒伤悲啊!以前都是去寻求男朋友帮助,但是最近尝试自己去解决…

js 递归和定时器的实例解析

js 递归和定时器的实例解析

递归,实例,电脑软件,js,递归:是一个函数通过调用自身的情况下构成的;首先上个例子:Function factorial(num){ if(num<=1){ return 1; }else{ return num*factorial(num-1); }}这是一个经典的递归阶乘函数,但是在js中这么调用可能会出现一些错误…

基于Vue实例生命周期 | 全面解析

基于Vue实例生命周期 | 全面解析

生命周期,实例,电脑软件,Vue,前面的话Vue实例在创建时有一系列的初始化步骤,例如建立数据观察,编译模板,创建数据绑定等。在此过程中,我们可以通过一些定义好的生命周期钩子函数来运行业务逻辑。本文将详细介绍Vue实例的生命周期图示下图是Vue…