ES6中javascript實(shí)現(xiàn)函數(shù)綁定及類的事件綁定功能詳解
本文實(shí)例講述了ES6中javascript實(shí)現(xiàn)函數(shù)綁定及類的事件綁定功能的方法。分享給大家供大家參考,具體如下:
函數(shù)綁定
箭頭函數(shù)可以綁定this對(duì)象,大大減少了顯式綁定this對(duì)象的寫法(call、apply、bind)。但是,箭頭函數(shù)并不適用于所有場合,所以 ES7 提出了 “ 函數(shù)綁定 ” ( function bind )運(yùn)算符,用來取代call、apply、bind調(diào)用。雖然該語法還是 ES7 的一個(gè)提案,但是 Babel 轉(zhuǎn)碼器已經(jīng)支持。
函數(shù)綁定運(yùn)算符是并排的兩個(gè)雙冒號(hào)( :: ),雙冒號(hào)左邊是一個(gè)對(duì)象,右邊是一個(gè)函數(shù)。該運(yùn)算符會(huì)自動(dòng)將左邊的對(duì)象,作為上下文環(huán)境(即 this 對(duì)象),綁定到右邊的函數(shù)上面。
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); }
如果雙冒號(hào)左邊為空,右邊是一個(gè)對(duì)象的方法,則等于將該方法綁定在該對(duì)象上面。
var method = obj::obj.foo; // 等同于 var method = ::obj.foo; let log = ::console.log; // 等同于 var log = console.log.bind(console);
由于雙冒號(hào)運(yùn)算符返回的還是原對(duì)象,因此可以采用鏈?zhǔn)綄懛ā?/p>
// 例一 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提供了類,給模塊化帶來了很大的幫助。在類里面綁定事件,一來是為了使得代碼結(jié)構(gòu)清晰,二來是為了可以使用類的變量和方法。但是,由于事件的回調(diào)函數(shù)并不是由類的實(shí)例對(duì)象觸發(fā),所以,事件回調(diào)函數(shù)里面并不能訪問類的this變量。另外,我們也不希望事件回調(diào)函數(shù)對(duì)外暴露,免得調(diào)用者直接調(diào)用。
簡單來說,我們就希望:
1. 事件回調(diào)函數(shù)要能訪問類的this變量
2. 事件回調(diào)函數(shù)不能直接調(diào)用
如何訪問類的this
方案一:將類的this保存成一個(gè)局部變量
this的指代是動(dòng)態(tài)改變的,但是局部變量的指代卻是明確的,并且,函數(shù)定義的局部變量在整個(gè)函數(shù)里面都可以用。所以,我們可以使用let that = this
保存類的this變量。
class A{ //綁定事件的方法 bindEvent(){ let that = this; this.button1.on('click',function(e){ this.addClass('on'); //this指代所點(diǎn)的元素 that.doSomething(); //that指向類的this }) } doSomething(){ //事件處理函數(shù) } //解綁事件 unBindEvent(){ this.button1.off(); } }
這種方法只在使用jquery時(shí)有用,因?yàn)閖query解綁事件不需要提供回調(diào)函數(shù),直接off就可以了。但是原生js需要提供回調(diào)函數(shù)也有它的道理,因?yàn)橥粋€(gè)元素的同一種事件可以綁定多個(gè)回調(diào)函數(shù),所以你需要指出釋放哪一個(gè)。
方案二:使用bind()改變this的指向
有類A,在A中要添加mousemove事件,根據(jù)需求寫出下面代碼:
class A{ //添加事件 addEvent(){ document.addEventListener( 'mousemove', onMouseMove, false ); } //添加事件 removeEvent(){ document.removeEventListener( 'mousemove', onMouseMove , false ); } } //事件回調(diào)函數(shù)中 function onMouseMove(event){ console.log(this); //#document }
但是,這樣獲取不到類的this。onMouseMove的this將會(huì)指向document。因?yàn)槭录翘砑拥絛ocument上的,所以自然是由document觸發(fā)事件并調(diào)用onMouseMove進(jìn)行處理,所以onMouseMove中的this指向document。
比較正確的做法是:使用bind()
函數(shù)改變onMouseMove中this的指向,同時(shí)將事件回調(diào)函數(shù)移到類外面:
class A{ //添加事件 addEvent(){ document.addEventListener( 'mousemove', onMouseMove.bind(this), false ); } //添加事件 removeEvent(){ document.removeEventListener( 'mousemove', onMouseMove.bind(this) , false ); } } //事件回調(diào)函數(shù)中 function onMouseMove(event){ console.log(this); }
但是這樣仍然存在問題,事件移除不掉了!因?yàn)?code>this.bind()每次調(diào)用都會(huì)返回一個(gè)新的函數(shù),所以:
document.addEventListener( 'mousemove', onMouseMove.bind(this), false );
和
document.removeEventListener( 'mousemove', onMouseMove.bind(this), false );
兩者的第二個(gè)參數(shù)并不相同。
正確的做法是: 將bind()
的結(jié)果保存到一個(gè)變量中:
class A{ constructor(){ this._onMouseMove = onMouseMove.bind(this); //看這里 } //添加事件 addEvent(){ document.addEventListener( 'mousemove', this._onMouseMove , false ); } //添加事件 removeEvent(){ document.removeEventListener( 'mousemove', this._onMouseMove , false ); } } //事件回調(diào)函數(shù)中 function onMouseMove(event){ console.log(this); }
如何定義私有的事件回調(diào)函數(shù)
在Java中,不想對(duì)外暴露的方法可以定義為私有方法,但是ES6并沒有提供私有方法,只能通過一些辦法模擬。但是,事件回調(diào)函數(shù)比較特別,因?yàn)槭录硕x,還要移除,這會(huì)帶來額外的麻煩。但還是有辦法的:
使用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 ); } } //事件回調(diào)函數(shù)中 function onMouseMove(event){ console.log(this); }
Symbol("_onMouseMove")
會(huì)產(chǎn)生一個(gè)唯一的值,這個(gè)值是在對(duì)象創(chuàng)建的時(shí)候才生成的,所以,調(diào)用者沒有辦法在寫代碼時(shí)知道這個(gè)值的,所以,就無法調(diào)用使用這個(gè)值命名的方法了,這樣就定義了一個(gè)私有方法。
更多相關(guān)內(nèi)容可查看本站專題:《ECMAScript6(ES6)入門教程》、《JavaScript數(shù)組操作技巧總結(jié)》、《JavaScript字符與字符串操作技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》及《javascript面向?qū)ο笕腴T教程》
希望本文所述對(duì)大家基于ECMAScript的程序設(shè)計(jì)有所幫助。
- 為radio類型的INPUT添加客戶端腳本(附加實(shí)現(xiàn)JS來禁用onClick事件思路代碼)
- 怎么通過onclick事件獲取js函數(shù)返回值(代碼少)
- javascript 動(dòng)態(tài)改變onclick事件觸發(fā)函數(shù)代碼
- 詳解js的事件處理函數(shù)和動(dòng)態(tài)創(chuàng)建html標(biāo)記方法
- JavaScript利用發(fā)布訂閱模式編寫事件監(jiān)聽函數(shù)
- JavaScript觸發(fā)onScroll事件的函數(shù)節(jié)流詳解
- 深入理解Node.js 事件循環(huán)和回調(diào)函數(shù)
- 實(shí)例講解javascript注冊(cè)事件處理函數(shù)
- js動(dòng)態(tài)添加input按鈕并給按鈕增加onclick的函數(shù)事件(帶參數(shù))完整實(shí)例
相關(guān)文章
js中實(shí)現(xiàn)字符串和數(shù)組的相互轉(zhuǎn)化詳解
這篇文章主要介紹了js中實(shí)現(xiàn)字符串和數(shù)組的相互轉(zhuǎn)化,感興趣的小伙伴們可以參考一下2016-01-01Javascript 數(shù)組添加一個(gè) indexOf 方法的實(shí)現(xiàn)代碼
Javascript 的字符串有個(gè) indexOf 的方法,能夠返回字符在指定的字符串中的位置,非常有用,本文介紹了如何給 Javascript 數(shù)組也添加一個(gè)類似的方法。2009-09-09利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)示例代碼
這篇文章主要給大家介紹了關(guān)于如何利用Promise自定義一個(gè)GET請(qǐng)求的函數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Promise具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03JS+CSS實(shí)現(xiàn)簡單的二級(jí)下拉導(dǎo)航菜單效果
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)簡單的二級(jí)下拉導(dǎo)航菜單效果,通過簡單的JavaScript頁面元素遍歷及樣式操作實(shí)現(xiàn)下拉菜單效果,非常簡單實(shí)用,需要的朋友可以參考下2015-09-09關(guān)于IE、Firefox、Opera頁面呈現(xiàn)異同 寫腳本很痛苦
關(guān)于IE、Firefox、Opera頁面呈現(xiàn)異同 寫腳本很痛苦,對(duì)于多瀏覽器的兼容性,需要注意。2009-08-08