问:Symbol,究竟有什么作用
答:面试时有用,作为js的其中一种基本类型
真正的使用场景其实在网上一搜,也有很多答案,无非是
1.模拟私有属性
2.防止对象属性值命名冲突
3.xxx
一般来说,写业务很少会利用到这特性,而很多第三方工具(框架类库)都有用到,例如React的$$typeof属性用到Symbol,作用是防止xss(因为数据库无法存储Symbol),所以说React是天然防xss的
场景
终于有一天,在开发一个第三方工具(组件)时,想到Symbol可以帮我解决一个难题,场景是这样
1.这组件是依赖antd4.x的Form
2.它能通过数组格式配置生成表单控件,可以配置联动效果
// 数据模型
const config = [
{
label: '姓名',
name: 'name',
depChange: values => {
if (values.sex === 1) {
return '男姓名';
}
},
placeholder: '性别选择男看看效果',
},
{
label: '性别',
name: 'sex',
type: 'select',
options: [
{ label: '男', value: 1 },
{ label: '女', value: 2 },
],
}
];
简单描述下,depChange作用就是当表单值变化时执行,性别(sex)值为女(1)时,姓名的值自动变成“男姓名”, 实现思路是利用Fom的onValuesChange,将config配置的所有depChange依次执行(onValuesChanges的changedValues作参数),并装在一个deps对象里,最后setFieldsValue(deps)达到值更新效果
然而
当性别选择男时,姓名自动变成“男姓名”,然后在姓名打上任意字符,会发现,值清空了,为什么呢,列举一下步骤:
1.选择性别“男”,姓名自动填充为“男姓名” (正常)
2.姓名上输入1,姓名自动变成“空” (异常,理想是变成“男姓名1”)
why?
因为第二部的changedValues为
{name: "男姓名1"}
再看看姓名的depChanges配置
depChange: values => {
if (values.sex === 1) {
return '男姓名';
}
}
执行后会返回undefined!这是函数默认的返回结果!这可是一个棘手的问题,我可不想将姓名重置的,只是函数会默认返回undefined
解决
将函数默认返回值改成Symbol
for (let k in dependence) {
const actionStr = dependence[k].action.toString();
// 函数劫持,拿return Symbol兜底
const i = actionStr.lastIndexOf('}');
const code =
actionStr.slice(0, i) + `return Symbol()` + actionStr.slice(i);
const newFunc = new Function(`return ${code}`)();
let v = newFunc(changedValues);
// 返回Symbol的不收集
if (typeof v !== 'symbol') {
deps[k] = v;
}
}
将函数劫持重写最后返回"return Symbol()",这样就避免了默认值是undefined,后面会判断当返回值是非symbol类型l时才执行联动函数,避免清空的情况
为什么
Q:为什么用Symbol,而不用其他数据类型
A:因为你不能将Symbol输入到实际的控件值中,暂时没看到有控件支持,业务逻辑上也走不通