Javascript - elegant way to check object has required properties

后端 未结 3 524
醉话见心
醉话见心 2021-01-03 01:26

I\'m looking for an good / elegant way to validate that a javascript object has the required properties, so far this is what I have:

var fields = [\'name\',\         


        
相关标签:
3条回答
  • 2021-01-03 01:43

    If you want "elegant", what you're looking for is called a schema:

    var schema = {
      name: function (value) {
        return /^([A-Z][a-z\-]* )+[A-Z][a-z\-]*( \w+\.?)?$/.test(value);
      },
      age: function (value) {
        return !isNaN(value) && parseInt(value) == value && value >= 18;
      },
      phone: function (value) {
        return /^(\+?\d{1,2}-)?\d{3}-\d{3}-\d{4}$/.test(value);
      }
    };
    
    var info = {
      name: "John Doe",
      age: "",
      phone: "123-456-7890"
    };
    
    function validate(object, schema) {
      var errors = Object.keys(schema).filter(function (key) {
        return !schema[key](object[key]);
      }).map(function (key) {
        return new Error(key + " is invalid.");
      });
    
      if (errors.length > 0) {
        errors.forEach(function (error) {
          console.log(error.message);
        });
      } else {
        console.log("info is valid");
      }
    }
    
    validate(info, schema);

    To address @AndreFigueiredo's pedantry, you can also check if the object contains the property at all:

    var schema = {
      name: function (value) {
        return /^([A-Z][a-z\-]* )+[A-Z][a-z\-]*( \w+\.?)?$/.test(value);
      },
      age: function (value) {
        return !isNaN(value) && parseInt(value) == value && value >= 18;
      },
      phone: function (value) {
        return /^(\+?\d{1,2}-)?\d{3}-\d{3}-\d{4}$/.test(value);
      }
    };
    
    schema.name.required = true;
    schema.age.required = true;
    
    var info = {
      // name: "John Doe",
      age: "",
      phone: "123-456-7890"
    };
    
    function validate(object, schema) {
      var errors = Object.keys(schema).map(function (property) {
        var validator = schema[property];
        
        return [property, !validator.required || (property in object), validator(object[property])];
      }).filter(function (entry) {
        return !entry[1] || !entry[2];
      }).map(function (entry) {
        if (!entry[1]) return new Error(entry[0] + " is required.");
        else return new Error(entry[0] + " is invalid.");
      });
    
      if (errors.length > 0) {
        errors.forEach(function (error) {
          console.log(error.message);
        });
      } else {
        console.log("info is valid");
      }
    }
    
    validate(info, schema);


    Update

    Here's a modernized solution using features from ECMAScript 6 edition including destructuring, arrow functions, Object.entries(), template literals, and for...of:

    const schema = {
      name: value => /^([A-Z][a-z\-]* )+[A-Z][a-z\-]*( \w+\.?)?$/.test(value),
      age: value => parseInt(value) === Number(value) && value >= 18,
      phone: value => /^(\+?\d{1,2}-)?\d{3}-\d{3}-\d{4}$/.test(value)
    };
    
    let info = {
      name: 'John Doe',
      age: '',
      phone: '123-456-7890'
    };
    
    const validate = (object, schema) => Object
      .keys(schema)
      .filter(key => !schema[key](object[key]))
      .map(key => new Error(`${key} is invalid.`));
    
    const errors = validate(info, schema);
    
    if (errors.length > 0) {
      for (const { message } of errors) {
        console.log(message);
      }
    } else {
      console.log('info is valid');
    }

    And the version that performs required and validate checks separately:

    const schema = {
      name: value => /^([A-Z][a-z\-]* )+[A-Z][a-z\-]*( \w+\.?)?$/.test(value),
      age: value => parseInt(value) === Number(value) && value >= 18,
      phone: value => /^(\+?\d{1,2}-)?\d{3}-\d{3}-\d{4}$/.test(value)
    };
    
    schema.name.required = true;
    schema.age.required = true;
    
    let info = {
      // name: 'John Doe',
      age: '',
      phone: '123-456-7890'
    };
    
    const validate = (object, schema) => Object
      .entries(schema)
      .map(([key, validate]) => [
        key,
        !validate.required || (key in object),
        validate(object[key])
      ])
      .filter(([_, ...tests]) => !tests.every(Boolean))
      .map(([key, invalid]) => new Error(`${key} is ${invalid ? 'invalid' : 'required'}.`));
    
    const errors = validate(info, schema);
    
    if (errors.length > 0) {
      for (const { message } of errors) {
        console.log(message);
      }
    } else {
      console.log('info is valid');
    }

    0 讨论(0)
  • 2021-01-03 01:47

    I would do for a real check for empty strings, because 0 is falsy, but a value and not empty.

    function validateFields(object, keys) {
        keys.forEach(function (k) {
            if (k in object) {
                console.log(k + ": " + object[k]);
                if (object[k] === '') {
                    console.log(k + " exists but is empty");
                }
                return;
            }
            console.log(k + " doesn't exist in object");
        });
    }
    
    var fields = ['name', 'age', 'address', 'zeroString', 'zeroNumber'],
        info = { name: "John Doe", age: "", phone: "123-456-7890", zeroString: '0', zeroNumber: 0 };
    
    validateFields(info, fields);

    0 讨论(0)
  • 2021-01-03 01:49

    I think that you should be more concerned about what's the proper way of checking for it, rather than the most elegant. I'll drop a link to a very good post from Todd Moto regarding this: Please, take a look

    In short your code should look like this:

     var validateFields = function(o, required_fields) {
      required_fields.forEach(function(field){
        if(field in o){
          if((typeof o[field] != 'undefined')){
            console.log(field + ": " + o[field]);
          }else{
            console.log(field + " exists but is undefined");
          }
        }else{
          console.log(field + " doesn't exist in object");
        }
      });
    }
    

    Note: Take care when checking it has value, many expressions in javasscript are falsy (eg. 0, false, etc.) but are valid values.

    0 讨论(0)
提交回复
热议问题