一个表单验证引发的深思!!!

390 阅读6分钟

需求

实现一个表单验证,用于验证用户名,邮箱,密码等。

function checkName() {
    // 验证用户名
}
function checkEmail() {
    // 验证邮箱
}
function checkPassword() {
    // 验证密码
}
...

通过上面我们书写的函数实现了我们的需求。 但是我们写完之后,会不会考虑一个问题,这些函数都是变量,而且是全局变量!

函数的另外一种形式

var checkName = function () {
    // 验证用户名
}
var checkEmail = function () {
    // 验证邮箱
}
var checkPassword = function () {
    // 验证密码
}
...

两种写法其实是一致的,都是声明了三个全部变量,功能上没啥问题,但是在团队开发中,我们写代码的时候就需要三思后行了,不能只考虑自己,也要考虑不影响到其他人,如果别人也定义了同样的方法就会覆盖掉原有的功能。如果我们定义了很多方法,这种互相覆盖的问题是很不容易被发现的。

那么我们应该如何避免这种情况呢?

使用对象收编变量

对象都拥有属性和方法,而如果我们要访问他的属性或者方法时,可通过点语法遍历查询得到。因此我们的代码可以修改为:

var CheckObject = {
    checkName: function () {
        // 验证用户名
    },
    checkEmail: function () {
        // 验证邮箱
    },
    checkPassword: function () {
        // 验证密码
    }
    ...
}

此时我们将搜有的方法都放在CheckObject这个对象里面,我们只声明了一个变量,我们使用也非常简单,比如检测用户名CheckObject.checkName(),这样只是在我们之前使用函数式前面加了一个对象名称。

当然还有另外一种形式。

对象的另外一种形式

在javascript中,函数也是对象的一种,所以我们可以这样写:

var CheckObject = function () {};
CheckObject.checkName = function () {
    // 验证用户名
}
CheckObject.checkEmail = function () {
    // 验证邮箱
}
CheckObject.checkPassword = function () {
    // 验证密码
}
...

使用和前面的方式是一样的,但是这样写虽然满足了我们自己的需求,但当别人想用我们写的方法时就有些麻烦了,因为我们写的这个对象没办法进行复制,也就是通过new关键字创建的新的对象不会继承这些方法。

真假对象

如果我们想简单的进行复制一下,那么我们可以这么写:

var CheckObject = function () {
    return {
        checkName: function () {
            // 验证用户名
        },
        checkEmail: function () {
            // 验证邮箱
        },
        checkPassword: function () {
            // 验证密码
        }
        ...
    }
}

我们上面写的代码,看上去是复制了,当每次调用这个函数的时候,把我们之前写的这个对象返回出来,当别人每次调用的时候都返回了一个新的对象,这样执行过程中明面是CheckObject对象,可实际上是返回的新对象,这样每个人在使用的时候就互不影响了。比如我们想要验证邮箱:

var a = CheckObject();
a.checkEmail();

虽然上面我们通过创建新对象的需求,但是这并不是一个真正意义上类的创建方式,并且创建的对象a和CheckObject没有任何关系(返回出来的对象本身就和CheckObject对象无关),所以我们对代码再次进行需改:

var CheckObject = function () {
    this.checkName = function () {
        // 验证用户名
    }
    this.checkEmail = function () {
        // 验证邮箱
    }
    this.checkPassword = function () {
        // 验证密码
    }
}

上面我们实现的CheckObject就可以看作是一个类,我们可以通过new 关键字来创建

var a = new CheckObject()
a.checkName()

这样每个使用者在使用CheckObject时,通过对CheckObject进行实例,那么每个人都会有属于自己的方法,并且不相互影响。

更优化的方案

我们将所有的方法都放在了函数内部,通过this定义,所以每次通过new关键字创建对象的时候,新创建的对象都会对类的this上的属性进行复制。所以这些创建的方法都会都自己的一套方法,然而有时候这么做造成的消耗是很奢侈的,我们需要处理一下:

var CheckObject = function () {}
CheckObject.prototype.checkName = function () {
    // 验证用户名
}
CheckObject.prototype.checkEmail = function () {
    // 验证邮箱
}
CheckObject.prototype.checkPassword = function () {
    // 验证密码
}
...

这样创建对象实例的时候,创建出来的对象所拥有的方法就都是一个了,因为它们都依赖的prototype原型依次寻找,而找到的方法是同一个,它们都绑定在CheckObject对象的原型上。这种方式需要写很多遍prototype,我们也可以这么写:

var CheckObject = function () {}
CheckObject.prototype = {
    checkName: function () {
        // 验证用户名
    },
    checkEmail: function () {
        // 验证邮箱
    },
    checkPassword: function () {
        // 验证密码
    }
    ...
}

但是有一点需要记住,这两种方式不能混合使用,如果混用的话,后面的对象的原型为对象赋值新对象的时候,它会将之前对prototype对象赋值的方法覆盖掉!!

这里还有一点需要大家关注的是前者实例的constructor是ƒ (){}后者指向的是ƒ Object() { [native code] }

实现链式调用

我们上面写的代码在使用的时候:

var a = new CheckObject()
a.checkName()
a.checkEmail()
a.checkPassword()

我们需要写多遍a对象,如果我们在声明的每个方法末尾将当前的对象返回,那么我们就可以进行链式调用了!

var CheckObject = function () {}
CheckObject.prototype = {
    checkName: function () {
        // 验证用户名
        return this;
    },
    checkEmail: function () {
        // 验证邮箱
        return this;
    },
    checkPassword: function () {
        // 验证密码
        return this;
    }
    ...
}

这样我们在使用的时候就可以写成:

CheckObject.checkName().checkEmail().checkPassword()

Prototype

有兴趣的同学可以看一下这篇文章 原型与原型链

可能在上面的实现中,大家可能心里会有这种实现思路:

Function.prototype.checkName = functionn () {
    // 验证用户名
}
var f = new Function()
f.checkName()

这样做其实是不可取的,因为这样做污染了原声对象Function,别人创建的函数也会被污染,造成不必要的开销,其实我们可以这样做:

Function.prototype.addMethod = function (name, fn) {
    this[name] = fn
}

这样的话, 我们想添加业务逻辑的时候就可以这样做:

var methods = new Function()
methods.addMethod('checkName', function () {
    // 验证用户名
})
methods.addMethod('checkEmail', function () {
    // 验证邮箱
})
methods.checkName()
methods.checkEmail()

当然我们还可以实现链式添加方法:

Function.prototype.addMethod = function (name, fn) {
    this[name] = fn;
    return this;
}

var methods = new Function()
methods.addMethod('checkName', function () {
    //验证用户名
    return this;
}).addMethod('checkEmail', function () {
    // 验证邮箱
    return this;
})

// 调用
methods.checkName().checkEmail()

最后

JavaScript是一门灵活的语言,这因为这种灵活性,所以每个人都可能会写出不同风格的代码,这是JavaScript给予我们的财富,不过在团队开发中我们谨慎发挥,尽量保持团队开发代码风格的一致性,这也是团队代码易开发、可维护以及代码规范的必要条件!

文章同步更新在我的个人公众号与我的个人博客