【坑】JavaScript 對象方法執行的上下文

這是一個因爲對 JavaScript 函數上下文理解不夠深刻而遇到的坑。html

背景

在表單驗證中,利用高階函數,抽象一個能夠返回特定驗證邏輯的驗證函數:app

// 正則匹配
const getParser = (type) => {
  switch (type) {
    case 'chname':
      return /^([\u4e00-\u9fa5]+|([a-zA-Z]+\s?)+)$/g;
    case 'email':
      return /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
    case 'phone':
      return /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/;
    case 'password':
      return /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9!@#$%^&*()]{8,16}$/;
    default:
      return () => false;
  }
};
 
const getMatch = (value) => `${value}`.match;
const isValid = (value, type) => getMatch(value)(getParser(type));

isValid('12345678901', 'phone');

問題

執行 getMatch(value)(getParser(type)) 的時候,沒法完成驗證,程序陷入中止,沒法往下執行。函數

緣由

在執行形如 var a = obj.func 的代碼的時候,咱們覺得獲得的變量 a 的上下文是 obj,而後執行 a() 的時候,就會跟執行 obj.func() 同樣;然而實際上,獲得的 a 只是一個單純的函數,並不會自動綁定 obj 爲上下文。code

再來看上面的代碼的最後一句:htm

const isValid = (value, type) => getMatch(value)(getParser(type));

經過 getMatch(value) 獲得一個 match 方法,可是與預期不一樣,此時獲得的 match 方法的上下文並非 value,於是會執行失敗。對象

解決辦法

知道了緣由,很明顯解決辦法就是爲要使用的 match 方法綁定上下文。在 Javascript 中,有不少種方法能夠實現:ip

/// bind
const getMatch = (value) => `${value}`.match.bind(value);
const isValid = (value, type) => getMatch(value)(getParser(type));

/// call
const getMatch = (value) => `${value}`.match;
const isValid = (value, type) => getMatch(value).call(value, getParser(type));

/// apply
const getMatch = (value) => `${value}`.match;
const isValid = (value, type) => getMatch(value).apply(value, [getParser(type)]);

結論

JavaScript 的面向對象特性,比想象中還要弱一些。根本沒有什麼 「類方法」 ,全部形如 obj.func1() 的點操做方法執行,只不過是將 obj 做爲上下文去執行 func1 函數罷了。須要特別注意的是,只有在點操做以後立刻執行,纔會有上下文,給人形成是 「調用了對象 obj 裏面的 func1 方法」 的假象;若是如上文描述那樣進行了賦值操做 func2 = obj.func1,則在執行 func2 的時候就不會有什麼上下文了。get

參考文章

Javascript 中的上下文,個人認識的三個階段
Javascript中的Bind,Call和Applyit

相關文章
相關標籤/搜索