前端的小玩意(16)——利用setter和getter实现数据校验

利用setter和getter实现数据校验

写前端和后端的时候,往往要进行数据校验。

例如:

后端在处理数据之前,需要校验前端传过来的数据和后端要求的数据是否相符,以及是否存在超限问题(大于最大值或者小于最小值,或者字符串长度过长过短)。

在常规做法中,我们需要写多个函数,然后一个一个的校验过去,十分麻烦。

如果某个属性要在多个地方验证,并且验证条件是统一的,那么有两种写法:

  1. 比较笨是把一个写好的复制到另外一个地方,但若需求变更,那么修改的时候就很麻烦了;
  2. 比较聪明的是通过原型链来继承这个验证函数,不过这样也很麻烦。当验证函数比较多的时候,整理起来也比较麻烦,而且不容易观察到有哪些地方引用了。

第二种方法已经算是比较聪明的了,但还有一个缺点,那么就是需要专门调用,不够智能。

如果我们能在赋值的时候自动校验一下是否符合要求,不符合要求就不赋值,那么就很方便了。

对于这种要求,在es5的setter和getter特性出来后,是可以实现的。

在setter的时候,校验一下数据类型是否符合,如果符合则赋值,不符合则直接返回即可。如果有必要,还可以记录一下,甚至控制台打印报错信息。

这里给一个示例代码:

class Foo {
    constructor(val) {
        this._errorList = []
        // 遍历作为构造函数传的参数的每个属性,然后赋值之
        for (let i in val) {
            this[i] = val[i]
        }
    }

    get age() {
        return this._age ? this._age : null
    }

    set age(val) {
        // 赋值前进行数据验证
        if (val >= 20 && val <= 100) {
            this._age = val
        } else {
            this.errorList.push('age')
        }
    }

    // 直接查看值可以得知赋值过程中是否有错
    get isDataError() {
        if (this.errorList.length === 0) {
            return false
        } else {
            return true
        }
    }

    // 获取错误列表
    get errorList() {
        return this._errorList
    }

    // 赋值的时候,只是将错误添加到错误列表里(简化示例,不考虑重置)
    set errorList(val) {
        this._errorList.push(val)
    }

    // 获取当前赋值的数据
    getData() {
        return {
            age: this.age
        }
    }
}

let p1 = new Foo({age: 1})
if (p1.isDataError) {
    console.log(p1.errorList)
} else {
    console.log(p1.getData())
}
// ["age"]

let p2 = new Foo({age: 30})
if (p2.isDataError) {
    console.log(p2.errorList)
} else {
    console.log(p2.getData())
}
// {age: 30}

let p3 = new Foo()
if (p3.isDataError) {
    console.log(p3.errorList)
} else {
    console.log(p3.getData())
}
// {age: null}

以上代码包括:

  1. 赋值检测;
  2. 取值(返回有效值或默认值);
  3. 错误检查(isDataError);
  4. 正确则返回结果(getData());
  5. 错误则返回错误列表(errorList());

基本可以应对一般性的需求了。

另外提一下关于代码复用时的思路:

  1. 对于需要复用的属性,可以写一个基类,然后其他需要他的继承该基类就行;
  2. 基类的校验函数如果亢余,并不是问题,因为通常不会被调用;
  3. 如果像上面Foo类的构造函数这样批量赋值,那么错误校验的逻辑不应该放在setter里,而是应该放在getter里(取值时校验报错),返回错误后应该清空之前的错误列表;
  4. 对于不同的类,拿取数据的时候,应该用一个专门的函数(如getData())负责拿数据,这样稳妥一点。而对于基类,应该只负责数据校验,而不负责取数据;
  5. 如果校验的类比较多的情况下,应该用专门的js文件存放这些类,然后导出他们;
  6. 如果再更多一点的话,应该用一个专门的文件夹,然后不同的js存放不同页面/逻辑/功能模块的校验类,视需求引入;
  7. 总而言之,是抽出校验逻辑,解耦他,方便维护和开发;

最后附一个关于setter和getter用法和优点的总结:

引自《 API design for C++ 》

  1. 有效性验证(可以在setter里检查设置的值是否在许可区间里)
  2. 惰性求值(比如一个成员计算过于耗时,而这个类的用户(这里的用户指其他程序员)不一定需要时,可以在getter方法调用的时候再计算)
  3. 缓存额外的操作(比如用户调用setter方法时,可以把这个值更新到配置文件里)
  4. 通知(其它模块可能需要在某个值发生变化的时候做一些操作,那么就可以在setter里实现)
  5. 调试(可以方便的打印设置日志,从而追踪错误)
  6. 同步(如果多线程访问需要加锁的话,setter里加锁不是很容易么)
  7. 更精细的权限访问(比如private变量只有getter没有setter,那客户对该变量就是只读了,而类的内部代码可以读写)
  8. 维护不变式关系(比如一个类内部要维持连个变量a和b有a = b * 2的关系,那么在a和b的setter里计算就能维持这样的关系)

以上引用内容复制自:

作者:浅墨
链接:https://www.zhihu.com/question/21401198/answer/37192335
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

对于js来说,有用的有:

  1. 常见情况下:1(超限则赋值无效)、5(很好用的说)、8(比如改了当前值后,顺便改了和他联动的另外一个值)
  2. 不常见情况有:2(类似的效果可以参考Vue的计算属性、4(比如关键属性被修改,log一发)、7(比如只允许读或只允许写)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值