首頁  >  文章  >  web前端  >  詳解ES6中javascript實作函數綁定及類別的事件綁定功能

詳解ES6中javascript實作函數綁定及類別的事件綁定功能

小云云
小云云原創
2017-12-23 10:29:441887瀏覽

本文主要介紹了ES6中javascript實現函數綁定及類別的事件綁定功能,結合實例形式分析了ES6中函數綁定及類的事件綁定原理、實現方法、相關操作技巧與注意事項,需要的朋友可以參考下,希望能幫助大家。

函數綁定

箭頭函數可以綁定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("p.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")會產生一個唯一的值,這個值是在物件創建的時候才產生的,所以,呼叫者沒有辦法在寫程式碼時知道這個值的,所以,就無法呼叫使用這個值命名的方法了,這樣就定義了一個私有方法。

相關推薦:

實例講解JavaScript函數綁定用法

javascript互動如何使用函數綁定程式碼詳解

JavaScript函數綁定

以上是詳解ES6中javascript實作函數綁定及類別的事件綁定功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn