个人记录前端面试题-数据类型的判断

130 阅读5分钟

typeOf

typeof是一个JavaScript操作符,用于返回一个值的数据类型。它的语法格式为:typeof value,其中value可以是任意JavaScript值。typeof操作符返回的结果是一个字符串,表示value的数据类型。

  • 基本数据类型:除了 null 都可以显示正确的类型
  • 复杂数据类型(Object):除了函数都会显示 object
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof "str"); // string
console.log(typeof []); // object     []数组的数据类型在 typeof 中被解释为 object
console.log(typeof function () {}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object     null 的数据类型被 typeof 解释为 object

instanceof

instanceof是一个JavaScript操作符,用于检测一个对象是否是某个构造函数的实例。它的语法格式为:object instanceof constructor,其中object是要检测的对象,constructor是要检测的构造函数。如果object是constructor的实例,那么instanceof操作符返回true,否则返回false。

在使用instanceof操作符时,需要注意以下几点:

  • constructor必须是一个构造函数(例如Object、Array、Function等),不能是其他类型的值(例如字符串、数字、布尔值等)。
  • object必须是一个对象,不能是其他类型的值。
  • 如果object的原型链上存在constructor.prototype,那么object就被认为是constructor的实例。因此,即使constructor的原型链上有其他构造函数的prototype,只要object的原型链上存在constructor.prototype,那么object就被认为是constructor的实例。例如,[] instanceof Object返回true,因为数组的原型链上存在Object.prototype。
  • 如果constructor不是一个函数,那么会抛出一个TypeError异常。

示例代码:


console.log((2).constructor === Number); // true
console.log(true.constructor === Boolean); // true
console.log("str".constructor === String); // true
console.log([].constructor === Array); // true
console.log(function () {}.constructor === Function); // true
console.log({}.constructor === Object); // true

function Fn() {}

Fn.prototype = [];

const f = new Fn();

console.log(f.constructor === Fn); // false
console.log(f.constructor === Array); // true

typeOf和instanceof的区别

  1. typeof可以用来判断基础数据类型,其中除了null,其它基础数据类型都可以判断出来

console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof "str"); // string
console.log(typeof undefined); // undefined
console.log(typeof null); // object     null 的数据类型被 typeof 解释为 object

  1. typeof在判断对象的时候除了函数可以正确判断以外,其它数据类型都是无法正确的判断的,返回结果都是object

console.log(typeof function () {}); // function
console.log(typeof []); // object     []数组的数据类型在 typeof 中被解释为 object
console.log(typeof {}); // object

  1. instanceof是通过原型链的方式来判断数据类型的
const data = {name: 'Alice'};
function func(){}
console.log(func instanceof Function); // true
console.log(data instanceof Object); // true
//如果要正确判断是否是数组则要使用
Array.isArray([])

  1. instanceof判断不了基本的数据类型,因为基础数据类型本质上不是对象,它们没有原型链,也没有类似构造函数,所以无法判断它们的类型
const str = "hello";
console.log(str instanceof String); // 抛出 TypeError 错误

  1. instanceof检测对象的一些示例

// 使用instanceof检测对象的类型
class Person {             // 定义一个Person类
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const person1 = new Person("Alice", 18); // 使用Person类创建一个对象
const person2 = { name: "Bob", age: 20 }; // 创建一个普通的对象

console.log(person1 instanceof Person); // 输出true,因为person1是Person类的实例
console.log(person1 instanceof Object); // 输出true,因为person1是Object类的实例
console.log(person2 instanceof Person); // 输出false,因为person2不是Person类的实例
console.log(person2 instanceof Object); // 输出true,因为person2是Object类的实例
// 使用typeof检测变量是否被定义
let x;                     // 定义一个未赋值的变量x
console.log(typeof x);     // 输出“undefined”,因为x未赋值

if (typeof y === "undefined") {  // 如果变量y未被定义
  console.log("y is not defined"); // 输出“y is not defined”
}
// 使用instanceof检测函数是否是某个类的实例
class Animal {              // 定义一个Animal类
  constructor(name) {
    this.name = name;
  }
  say() {
    console.log(`I am a ${this.name}`);
  }
}

function Dog(name) {        // 定义一个Dog函数,它相当于Animal的子类
  Animal.call(this, name);  // 调用Animal的构造函数
}

Dog.prototype = Object.create(Animal.prototype); // Dog继承Animal类的方法和属性

const dog = new Dog("dog");  // 使用Dog函数创建一个对象dog

console.log(dog instanceof Dog);     // 输出true,因为dog是Dog类的实例
console.log(dog instanceof Animal);  // 输出true,因为dog是Animal类的实例
console.log(dog instanceof Object);  // 输出true,因为dog是Object类的实例

constructor

在 JavaScript 中,可以使用 constructor 属性来检查一个值的数据类型。每种数据类型都有其对应的构造函数。

console.log((2).constructor === Number); // true
console.log(true.constructor === Boolean); // true
console.log("str".constructor === String); // true
console.log([].constructor === Array); // true
console.log(function () {}.constructor === Function); // true
console.log({}.constructor === Object); // true

function Fn() {}

Fn.prototype = [];

const f = new Fn();

console.log(f.constructor === Fn); // false
console.log(f.constructor === Array); // true

不过这种方法也有缺点,因为 constructor 的指向可以被更改。

例如,可以通过更改构造函数的 prototype 属性来更改一个对象的 constructor 属性。如下所示:

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    const person = new Person("Tom", 20);
    console.log(person.constructor === Person); // 输出: true
    
    Person.prototype.constructor = Array;// 更改constructor的指向
    
    console.log(person.constructor === Person); // 输出: false
    console.log(person.constructor === Array); // 输出: true

在上面的代码中,首先创建了一个 Person 构造函数和一个 person 对象,并检查了 person 对象的 constructor 指向,其值是 Person。然后将 Person 的 prototype.constructor 指向更改为 Array,并再次检查 person 对象的 constructor 指向值,发现其值已经变成了 Array,而不再是 Person。

因此,通过 constructor 指向值来确定数据类型并不是一种可靠的方式,不能保证其一定正确。更加可靠的方式是使用 typeof 或 instanceof 运算符来检查数据类型。

Object.prototype.toString.call()

通过 Object.prototype.toString.call() 方法也可用于检查一个值的数据类型。该方法返回一个表示该值数据类型的字符串。

例如,以下代码使用了 Object.prototype.toString.call() 方法来检查对象、数组、字符串、数值、布尔和函数类型的数据:

const obj = { name: "Tom" };
console.log(Object.prototype.toString.call(obj)); // 输出: [object Object]

const arr = [1, 2, 3];
console.log(Object.prototype.toString.call(arr)); // 输出: [object Array]

const str = "hello";
console.log(Object.prototype.toString.call(str)); // 输出: [object String]

const num = 123;
console.log(Object.prototype.toString.call(num)); // 输出: [object Number]

const bool = true;
console.log(Object.prototype.toString.call(bool)); // 输出: [object Boolean]

function foo() {}
console.log(Object.prototype.toString.call(foo)); // 输出: [object Function]

上述代码中,将不同类型的数据作为参数传递给 Object.prototype.toString.call() 方法,并输出了它所返回的字符串。

需要注意的是,返回的字符串包含了 [object ...] 的格式,其中 ... 表示该值的数据类型。例如,[object Object] 表示该值是一个对象类型。

此外,使用 Object.prototype.toString.call() 方法检查数据类型的好处是不会受到 constructor 属性被更改的影响,因为该方法返回的字符串是根据值的数据类型来确定的,而不是根据对象的 constructor 属性来确定的。