【问题标题】:Javascript - elegant way to check object has required propertiesJavascript - 检查对象的优雅方法是否具有必需的属性
【发布时间】:2016-12-01 16:18:49
【问题描述】:

我正在寻找一种好的/优雅的方法来验证 javascript 对象是否具有所需的属性,到目前为止,这就是我所拥有的:

var fields = ['name','age','address'];
var info = {
  name: "John Doe",
  age: "",
  phone: "123-456-7890"
}


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

validateFields(info, fields);

有没有更高效/优雅的方式在纯 javascript 中执行此操作?

编辑:好的,我很高兴我问了,因为我完全错过了一堆可能的条件,比如零。

优雅的窗外,这是一个验证功能如何?还有其他需要我检查的情况吗?

var fields = ['name','age','address'];
var info = {
  name: "John Doe",
  age: 0,
  address: false,
  phone: "123-456-7890"
}


var validateFields = function(o, required_fields, null_valid, zero_valid, empty_valid) {
  var invalid_fields = [];
  required_fields.forEach(function(field){
    if(field in o){
      switch(o[field]){
        case '':
          console.log(field + " exists but is empty");
          if(!empty_valid){
            invalid_fields.push(o[field]);
          }
          break;
        case undefined:
          console.log(field + " exists but is undefined");
          invalid_fields.push(o[field]);
          break;
        case null:
          console.log(field + " exists but is null");
          if(!null_valid){
            invalid_fields.push(o[field]);
          }
          break;
        case 0:
          console.log(field + " exists and the value is 0");
          if(!zero_valid){
          }
          invalid_fields.push(o[field]);
          break;
        default:
          console.log(field + ": " + o[field]);
          break;
      }
    }else{
      console.log(field + " doesn't exist in object");
      invalid_fields.push(o[field]);
    }
  });

  return invalid_fields;
}


var invalid = validateFields(info, fields, true, true, false);
console.log(invalid);
if(invalid.length >0){
  console.log("ERROR: Missing fields");
}else{
  console.log("Fields are valid");
}

【问题讨论】:

  • 你的函数看起来更像是一个调试函数,它并没有真正告诉其他函数对象是否具有所需的属性。
  • 我将在完成后将控制台日志替换为返回,这只是为了快速查看结果。
  • 返回 forEach 除了跳到下一个迭代之外并没有什么作用。也许您正在考虑map,但它仍然没有告诉您它是否有效。
  • fields.every(field => field in info && info[field] != null);

标签: javascript validation


【解决方案1】:

我认为您应该更关心检查它的正确方法是什么,而不是最优雅的方法。 我会放一个链接,指向 Todd Moto 的一篇非常好的帖子:Please, take a look

简而言之,您的代码应如下所示:

 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");
    }
  });
}

注意:检查它是否有值时要小心,javasscript 中的许多表达式是假的(例如 0、false 等)但都是有效值。

【讨论】:

  • 这实际上取决于您要检查属性是否存在的位置。例如,如果他有一个字段toString,即使它没有直接在对象上,测试也会通过。
【解决方案2】:

如果你想要“优雅”,你要找的就是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);

要解决@AndreFigueiredo's pedantry,您还可以检查object 是否包含该属性:

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);

更新

这是一个使用 ECMAScript 6 版中的功能的现代化解决方案,包括 destructuringarrow functionsObject.entries()template literalsfor...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');
}

而执行requiredvalidate的版本分别检查:

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');
}

【讨论】:

  • 不错的解决方案,但需要属性!= 有效的属性值
  • @AndreFigueiredo 更好吗?
  • 我一直在互联网上寻找这个。就像 JOI 验证一样,这是我找到的唯一参考
【解决方案3】:

我会真正检查空字符串,因为0 是假的,但它是一个值而不是空的。

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);

【讨论】:

    【解决方案4】:

    您可以使用https://github.com/jquense/yup来解决您的问题。

    import * as yup from 'yup';
    
    let schema = yup.object().shape({
      name: yup.string().required(),
      age: yup.number().required().positive().integer(),
      address: yup.string().required(),
    });
    
    var info = {
      name: "John Doe",
      age: "",
      phone: "123-456-7890"
    }
    
    // check validity
    schema
      .isValid(info)
      .then(function (valid) {
        valid; // => false
      });
    

    这不仅仅是检查字段的存在,它还确保数据类型正确,例如该年龄是一个非负数。

    【讨论】:

      【解决方案5】:

      这是一个函数,它通过将对象的键与字符串数组进行比较来检查对象是否包含所有必需的键。由于它通过比较长度进行验证,因此顺序是否不同或对象是否包含其他信息都无关紧要。

      const hasRequiredKeys = (object, requiredKeys) => {
        return Object.keys(object).filter(key => requiredKeys.includes(key)).length === requiredKeys.length
      }
      

      【讨论】:

        猜你喜欢
        • 2014-07-11
        • 2011-03-28
        • 1970-01-01
        • 1970-01-01
        • 2014-05-08
        • 1970-01-01
        • 2018-03-07
        • 2011-07-04
        相关资源
        最近更新 更多