这是一个因为对 JavaScript 函数上下文明白不够深切而碰到的坑。
背景
在表单考证中,应用高阶函数,笼统一个能够返回特定考证逻辑的考证函数:
// 正则婚配
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
为上下文。
再来看上面的代码的末了一句:
const isValid = (value, type) => getMatch(value)(getParser(type));
经由过程 getMatch(value)
获得一个 match
要领,然则与预期差别,此时获得的 match
要领的上下文并非 value
,因而会实行失利。
解决办法
知道了缘由,很明显解决办法就是为要运用的 match
要领绑定上下文。在 Javascript 中,有许多种要领能够完成:
/// 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
的时刻就不会有什么上下文了。