JavaScript中的类型检查

152 阅读6分钟

JavaScript的动态类型同时好坏。很好,因为您不必指出变量的类型。

typeof 运算符确定JavaScript中的6种类型:

typeof 10;        // => 'number'
typeof 'Hello';   // => 'string'
typeof false;     // => 'boolean'
typeof { a: 1 };  // => 'object'
typeof undefined; // => 'undefined'
typeof Symbol();  // => 'symbol'

同样,instanceof检查实例的构造函数:

class Cat { }
const myCat = new Cat();

myCat instanceof Cat; // => true

但一些行为typeof,并instanceof可能会造成混淆。事先知道边缘情况比较明智。

1. null类型

typeof myObject === 'object'会告诉您是否myObject是对象类型。让我们尝试一个示例:

const person = { name: 'batman' };

typeof person; // => 'object'

typeof person'object'因为person拥有一个普通的JavaScript对象。

持有对象的变量有时可能为空。在这种情况下,您将需要null价值。以下是一些用例:

  • 您可以null用来跳过指示配置对象
  • 您可以使用null稍后将保存对象的变量进行初始化。
  • 当函数由于某种原因无法构造对象时,它可以返回 null

例如,如果不存在任何正则表达式匹配,则str.match(regExp)method返回null

const message = 'Hello';
message.match(/Hi/); // => null

您可以typeof用来区分现有对象和null缺少的对象吗?

不幸的是,您不能:

let myObject = null;
typeof myObject; // => 'object'

myObject = { prop: 'Value' };
typeof myObject; // => 'object'

typeof与一个现有对象并与null求和'object'

“ typeof null的历史”详细描述了此错误。

一种检测变量是否具有对象但没有null值的好方法是:

function isObject(value) {
  return typeof value === 'object' && value !== null;}

isObject({});   // => true
isObject(null); // => false

除了检查value是一个对象:typeof value === 'object'你还明确地验证空:value !== null

2.数组的类型

如果尝试检测变量是否包含数组,则第一个诱惑是使用typeof运算符:

const colors = ['white', 'blue', 'red'];

typeof colors; // => 'object'

但是,数组的类型'object'也是。从技术上讲,数组是一个对象,但有点令人困惑。

检测数组的正确方法是显式使用Array.isArray()

const colors = ['white', 'blue', 'red'];
const hero = { name: 'Batman' };

Array.isArray(colors); // => true
Array.isArray(hero);   // => false

Array.isArray(colors)返回一个boolean true,指示它colors是一个数组。

3.undefined类型检查

undefined JavaScript中的int是一个特殊值,表示未初始化的变量。

undefined如果尝试访问未初始化的变量,不存在的对象属性,则可以获取值:

let city;
let hero = { name: 'Batman', villain: false };

city;     // => undefined
hero.age; // => undefined

访问未初始化的变量,city并且不存在的属性的hero.age计算结果为undefined

要检查某个属性是否存在并且undefined虚假,您可能会想object[propName]在某种条件下使用它:

function getProp(object, propName, def) {
  // Bad
  if (!object[propName]) {    return def;
  }
  return object[propName];
}

const hero = { name: 'Batman', villain: false };

getProp(hero, 'villain', true);  // => true
hero.villain;                    // => false

object[propName]计算结果为undefinedpropName不存在objectif (!object[propName]) { return def }防止丢失属性。

hero.villain财产存在并且是false。但是,该函数true在访问villanprop值时错误地返回:getProp(hero, 'villain', true)

undefined是一个虚假的值。以及false0''null

不要将falsy用作类型检查undefined。明确验证属性是否存在于对象中:

  • typeof object[propName] === 'undefined'
  • propName in object
  • object.hasOwnProperty(propName)

让我们改善getProp()功能:

function getProp(object, propName, def) {
  // Better
  if (!(propName in object)) {
    return def;
  }
  return object[propName];
}

const hero = { name: 'Batman', villain: false };

getProp(hero, 'villain', true);  // => false
hero.villain;                    // => false

if (!(propName in object)) { ... } 条件正确确定该属性是否存在。

逻辑运算符

我认为最好避免使用逻辑运算符||作为默认机制。看到它,我的阅读流程就会中断:

const hero = { name: 'Batman', villain: false };

const name = hero.name || 'Unknown';
name;      // => 'Batman'
hero.name; // => 'Batman'

// Bad
const villain = hero.villain || true;
villain;      // => true
hero.villain; // => false

hero``villain有价值的财产false。但是该表达式的hero.villain || true计算结果为true

||当属性存在并且具有伪造的值时,用作访问属性的默认机制的逻辑运算符将失败。

要在属性不存在时默认为默认值,更好的选择是新的空值合并运算符

const hero = { name: 'Batman', villan: false };

// Good
const villain = hero.villain ?? true;
villain;      // => false
hero.villain; // => false

或销毁工作:

const hero = { name: 'Batman', villain: false };

// Good
const { villain = true } = hero;
villain;      // => false
hero.villain; // => false

4. NaN的类型

整数,浮点数,特别NUMERICS喜欢InfinityNaN是类型的数量

typeof 10;       // => 'number'
typeof 1.5;      // => 'number'
typeof NaN;      // => 'number'
typeof Infinity; // => 'number'

NaN是无法创建数字时创建的特殊数值。NaN的是一个缩写,而不是数量

在以下情况下无法创建号码:

// A numeric value cannot be parsed
Number('oops'); // => NaN

// An invalid math operation
5 * undefined; // => NaN
Math.sqrt(-1); // => NaN

// NaN as an operand
NaN + 10; // => NaN

由于NaN,意味着对数字进行的操作失败,因此对数字有效性的检查需要额外的步骤。

让我们确保isValidNumber()函数也可以防止NaN

function isValidNumber(value) {
  // Good
  return typeof value === 'number' && !isNaN(value);}

isValidNumber(Number('Z99')); // => false
isValidNumber(5 * undefined); // => false
isValidNumber(undefined);     // => false

isValidNumber(Number('99'));  // => true
isValidNumber(5 + 10);        // => true

此外typeof value === 'number',进行验证也是明智!isNaN(value)NaN

5. instanceof和原型链

JavaScript中的每个对象都引用一个特殊的函数:对象的构造函数。

object instanceof Constructor 是检查对象的构造函数的运算符:

const object = {};
object instanceof Object; // => true

const array = [1, 2];
array instanceof Array; // => true

const promise = new Promise(resolve => resolve('OK'));
promise instanceof Promise; // => true

现在,让我们定义一个父类Pet及其子类Cat

class Pet {
  constructor(name) {
    this.name;
  }
}

class Cat extends Pet {
  sound = 'Meow';
}

const myCat = new Cat('Scratchy');

现在让我们尝试确定的实例myCat

myCat instanceof Cat;    // => true
myCat instanceof Pet;    // => true
myCat instanceof Object; // => true

instanceof经营者说,myCat是的一个实例CatPet甚至Object

instanceof操作员通过整个原型链搜索对象的构造函数。要准确检测创建对象的构造函数,请查看constructor实例的属性:

myCat.constructor === Cat;    // => true
myCat.constructor === Pet;    // => false
myCat.constructor === Object; // => false

myCat.constructor === Cat计算为true,恰好表示myCat实例的构造函数。

6.关键要点

运算符typeofinstanceof在JavaScript中执行类型检查。尽管它们通常易于使用,但请确保了解边缘情况。

有点意外,typeof null等于'object'。要确定变量是否包含非空对象,请null明确声明:

typeof myObject === 'object' && myObject !== null

检查变量是否包含数组的最佳方法是使用Array.isArray(variable)内置函数。

因为undefined是不存在的,所以您可能会想直接在条件句中使用它。但是这种做法容易出错。更好的选择是prop in object验证属性的存在,无效合并object.prop ?? def或销毁分配{ prop = def } = object以访问可能丢失的属性。

NaN是数字无效操作所创建的数字类型的特殊值。为确保变量具有“正确的”数字,明智的做法是使用更详细的验证:!isNaN(number) && typeof number === 'number'

最后,请记住,它instanceof通过原型链搜索实例的构造函数。

原文