javascript 资料型態/结构验证库 : Skeletons

栏目: JavaScript · 发布时间: 5年前

内容简介:当初专案需要将资料以JSON格式储存在本地端,万一资料结构出了问题或是不符合预其,后面程式都会出问题,因此想写一个简单直觉的纯JS资料验证方法,并开源到npm上。希望对大家有帮助。喜欢可以给个星:) 有任何讨论都欢迎。先来介绍一下Javascript有趣的资料型态,如有错误请帮忙提出修正~

当初专案需要将资料以JSON格式储存在本地端,万一资料结构出了问题或是不符合预其,后面程式都会出问题,因此想写一个简单直觉的纯JS资料验证方法,并开源到npm上。

希望对大家有帮助。喜欢可以给个星:) 有任何讨论都欢迎。

源码

Javascript 型态

先来介绍一下Javascript有趣的资料型态,如有错误请帮忙提出修正~

JS 共有七种资料型态

其中包含六种 Primitive types :

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Symbol

和 Object

特别的是 Function 广义来说也是属于物件。

我们可以用 typeof 来检查型态 (回传一个字串)

typeof 1 // 'number'
typeof "" // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof null // 'object'
typeof Symbol // 'symbol'
typeof function(){ } // 'function'
typeof {} // 'object'
复制代码

等等,你有没有发现什麽端倪?我们一个一个看。

Number

一般我们会直接定义变数:

let a = 1
复制代码

也可以用 function 定义

let a = Number(1)
typeof a // 'number'
复制代码

但如果加上 new ,则会创建一个Number 物件

let a = new Number(1)
typeof a // 'object'
复制代码

NaN 也是属于Number

typeof NaN // 'number'
复制代码

如果要判断变数 a 是可计算的数字且不是 NaN ,以下是行不通的

if(typeof a==='number' && a!==NaN) //... a !== NaN 永远是 true
复制代码

因为 NaN 很特别,它不会等于任何值

// 以下通通都是 false !
NaN == 0 
NaN == false
NaN == NaN
NaN === NaN
复制代码

你可能会想到用 boolean 来判断 true / false

if(typeof a==='number' && !a) // ...
复制代码

但是别忘了还有个 0 :

if(typeof a==='number' && !a && a !== 0) // ...
复制代码

当然最简单的是用 isNaN 这个方法区分

if(typeof a==='number' && !isNaN(a)) // ...
复制代码

Boolean, String

和 Number 很像,注意用new的话会一样是创建object。

let a = true  // boolean
a = Boolean(true) //boolean
a = new Boolean(true) //object
复制代码

Undefined

也是一种premitive type

undefinednull 是没有 funtion的 ,直接指定值就好

typeof undefined // 'undefined'
复制代码

值得一提的是,虽然以下都是否定值 (false)

Boolean(0)
Boolean(false)
Boolean('')
Boolean(undefined)
Boolean(null)
复制代码

但动态型别方面 0, false, '' 是一伙的, undefined, null 则是另外一个团体

0 == false  // true
0 == ''     // true
false == '' // true

undefined == null // true

undefined == false // false
undefined == 0 //false
null == '' //false
复制代码

Null

null也是一种type,但是。。。

typeof null // 'object'
复制代码

没错, typeof 打印出来的是 'object'

上网查了一下,有些人说是JS当初设计的错误。

我们要判断一个变数是物件的话可以这样:

if(typeof a === 'object' && a!==null) // ...
复制代码

Symbol

最后一个 premitive type symbol

创建一个 symbol:

let a = Symbol()
typeof a // 'symbol'
复制代码

注意不能用 new ,会丢出错误

let a = new Symbol()
> Uncaught TypeError: Symbol is not a constructor
复制代码

Object

除了上面六种 primitive type,其他都归类为物件

但特别的是 function ,使用 typeof 检查会回传 function 字串:

typeof function(){} // 'function'
复制代码

让我们能很好的区别 function 和其他一般的物件

Skeletons

接下来要介绍这个库了,有兴趣的话可以先看看 介绍

请先记好上面 Javascript 原生定义的资料型别,因为这个库的分类有些不一样

Skeletons 中可定义的类型除了原本的七种JS类型,额外分出 array 和 function

原因是这两个都是很常用的,将他们从物件特别区分出来。

使用方法

定义一个规则,使用 validate 来验证资料

const rule = new Skeletons(schema)
rule.validate(data)
复制代码

Schema

定义规则需要传入一个 schema ,也就是你设想的资料结构以及形态

schema 可以有四种

1. premitive type function

共有四种可以用 (undefined和null是没有function的,我们后面谈如何定义)

  • Number
  • Boolean
  • String
  • Symbol

分别定义四种形态,使用上不用呼叫,直接传入function

如下,定义一个型态为数字的schema

const schema = Number
复制代码

2. 使用 object literal

使用最值觉的 object literal 来定义一个物件 (注意,在Skeletons会排除array和function)的key

每个key都可指派另一个schema

如下定义了一个有 x, y 两个键的物件,且两个键的值都是数字型态

const schema = {
  x: Number,
  y: Number
}
复制代码

使用这种方式,让你能够轻易地定义结构较深的物件

const userSchema = {
  name: String,
  id: String,
  VIP: {
    code: Number,
    details: {
      type: String,
      level: Number,
      expired: Boolean
    }
  },
}
复制代码

3. array literal

使用array literal来定义有固定元素數量的array

const schema = [String, Number, Skeletons.Function()]
复制代码

4.呼叫Skeletons的静态方法

  • Skeletons.Number()
  • Skeletons.String()
  • Skeletons.Boolean()
  • Skeletons.Null()
  • Skeletons.Symbol()
  • Skeletons.Any()
  • Skeletons.Array()
  • Skeletons.Object()
  • Skeletons.Function()
  • Skeletons.MapObject()

共有十种方法,分别代表是五种premitive type (不含undefined)、Object, 从物件中分出来的 Array, Function,以及特殊的Any(任何非undefined的型态) 和 MapObject

每种方法都接受一个 options 物件当做参数,

且都可定义三个基本的property

  • options.required

    type: Boolean

    default: true

    Skeletons对于任何 undefined 值都会认定为验证失败:

    new Skeletons({
      a: Number
    }).validate({})
    // data.a got undefined, validation filed
    复制代码

    如果要允许该层资料可以为 undefined ,设 options.required 为 false

    new Skeletons({
      a: Skeletons.Number({
        required: false
      })
    })
    复制代码
  • options.default

    type: 任何

    default: undefined

    有时后资料的预设值(或者空值)的型态可能会和资料有值的时后不一样,比方说有人可能会用 null 来替代空的物件。

    new Skeletons(Skeletons.Object({
      default: null
    }))
    复制代码
  • options.validator

    type: Function

    传入一个function,回传 true / false 来验证资料

    validator(value, data)
    复制代码

    该函数可接收两个参数: value 代表该层资料的值, data 代表整个资料

    以下这个例子, value 等于 120 , data 等于整个 datasource

    const datasource = {
      a: 120,
      b: 240
    }
    
    new Skeletons({
      a: Skeletons.Number({
        validator: (val, data) => {
         // in this case, val = 120, data = datasource
         return val === data.b*2
        }
      }),
      b: Number
    })
    复制代码

更多详细的介绍可以参考 文件

验证

验证可分为

  • 使用 console 打印出错误资讯
  • 直接抛出错误

如何设定可参考 文件

每次验证后,可由 warnings 属性获得错误资讯

const rule = new Skeletons(Number)
rule.validate('1')
rule.warnings // 一串array 包含所有错误资讯
复制代码

关于错误资讯可参考 warnings

示例

接下来演示一些资料定义的范例

范例一 : 阵列

定义一个 schema 代表不是 NaNnumber

// ex: 1
const calcNum = Skeletons.Number({
  allowNaN: false
})
复制代码

定义一个 array ,每个元素是含有 x , y 属性,值为非 NaN 数字的物件

// ex: [{x: 1, y: 2}, {x: 3, y: 5}]
new Skeletons(
  Skeletons.Array({
    item: {
      x: calcNum,
      y: calcNum
    }
  })
)
复制代码

规定 array 一定要有元素

// ex: [{x: 1, y: 2}, {x: 3, y: 5}]
new Skeletons(
  Skeletons.Array({
    validator: ary=>ary.length>0,
    item: {
      x: calcNum,
      y: calcNum
    }
  })
)
复制代码

范例二 : 和其他资料比对

假设有一笔资料,当 age 大于 18, grownup 等于 true 代表已成年,反之则为 false

const ex = {
  age: 19,
  grownup: true
}
复制代码

我们可以用 validator 来进行检查

new Skeletons(
  {
    age: Number,
    grownup: Skeletons.Boolean({
      validator: (val, data) => val === data.age>=18
    })
  }
).validate(ex)
复制代码

范例三: 不限制物件的key

有时后物件作为一个类似map来除存对应的key,代表并没有固定的属性值和数量。这时可以使用 MapObject

例如 room 以房间的id当做key来mapping

const room = {
  idkfd: {
    name : 'have fun',
    members: 4,
    id: 'idkfd'
  },
  ckclo: {
    name : 'My room',
    members: 2,
    id: 'ckclo'
  }, 
  ppqkd: {
    name : 'User0001\'s room',
    members: 8,
    id: 'ppqkd'
  } 
}
复制代码

可这样定义

new Skeletons(
  Skeletons.MapObject({
    keyValidator: (k, data)=> k === data[k].id,
    item: {
      name: String,
      members: Number,
      id: String
    }
  })
)
复制代码

以上所述就是小编给大家介绍的《javascript 资料型態/结构验证库 : Skeletons》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

独角兽之路

独角兽之路

三节课产品社区 / 电子工业出版社 / 2016-7 / 79.00元

对2~3年以上经验的互联网人来说,最好的学习可能不是听课,而是分析各类真实的产品和运营案例。而《独角兽之路:20款快速爆发且极具潜力的互联网产品深度剖析(全彩)》正好提供了对滴滴出行、百度外卖、懂球帝、快手App等20款极具代表性的准独角兽产品的发展路径的深度分析。 通过阅读《独角兽之路:20款快速爆发且极具潜力的互联网产品深度剖析(全彩)》,你可以发现互联网产品发展的背后,或许存在着某些共......一起来看看 《独角兽之路》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具