实现类型判断

实现类型判断

挑战介绍

本节我们来挑战一道大厂面试真题 —— 实现类型判断。

挑战准备

新建一个 getType.js 文件,在文件里写一个名为 getType 的函数,并导出这个函数,如下图所示:
在这里插入图片描述

这个文件在环境初始化时会自动生成,如果发现没有自动生成就按照上述图片自己创建文件和函数,函数代码如下:

function getType(target) {
  // 补充代码
}

module.exports = getType;

挑战内容

请封装一个函数,能够以字符串的形式精准地返回数据类型。

要求返回的类型全部由小写字母组成。

示例:

输入输出
true‘boolean’
100‘number’
‘abc’‘string’
100n‘bigint’
null‘null’
undefined‘undefined’
Symbol(‘a’)‘symbol’
[]‘array’
{}‘object’
function fn() {}‘function’
new Date()‘date’
/abc/‘regexp’
new Error()‘error’
new Map()‘map’
new Set()‘set’
new WeakMap()‘weakmap’
new WeakSet()‘weakset’

注意事项

  • 文件名、函数名不可随意更改。
  • 文件中编写的函数需要导出,否则将无法提交通过。

题目解答:

先贴一波答案

function getType(target) {
  const type = typeof target;
  if (type !== "object") {
    return type;
  }
  return Object.prototype.toString
    .call(target)
    .replace(/^\[object (\S+)\]$/, "$1")
    .toLocaleLowerCase();
}

首先我们要知道javascrip数据类型有两种:

  1. 基本类型:Undefined,Null,Boolean,Number,String

  2. 引用类型:

    • 第一类:原生对象:object,Array,Date,RegExp,Function以及有基本类型衍生出来的包装类型Boolean,Number,String;

    • 第二类内置对象,如Global,Math

    • 宿主对象,如IE中的window,WS中的WScript实例,以及任何用户创建的类

判断一个数据的类型,比较常用的有下面几种方式:

  • typeof
  • instanceof
  • Object.prototype.toString.call(xxx)

判断一个数据的类型,用得最多的就是 typeof 操作符, 但是使用 typeof 常常会遇到以下问题:

  • 无法判断 null
  • 无法判断除了 function 之外的引用类型。
// 可以判断除了 null 之外的基础类型。
console.log(typeof true);// boolean
console.log(typeof 100);// number
console.log(typeof "abc");// String
console.log(typeof 100n);// bigint
console.log(typeof undefined);// undefined
console.log(typeof Symbol("a"));// symbol

// 无法判断 null function 之外的引用类型。
console.log(typeof null);// object
console.log(typeof []);// object
console.log(typeof {});// object
const fn = function(){};
console.log(typeof fn);// function

typeof 无法精确地判断引用类型,这时,可以使用 instanceof 运算符,但是 instanceof 运算符一定要是判断对象实例的时候才是正确的

console.log([] instanceof Array);// true
const obj = {};
console.log(obj instanceof Object);// true
const fn = function(){};
console.log(fn instanceof Function);// true
const date = new Date();
console.log(date instanceof Date);// true
const re = /abc/;
console.log(re instanceof RegExp);// true

const str1 = "qwe";
const str2 = new String("qwe");
console.log(str1 instanceof String); // false,无法判断原始类型。
console.log(str2 instanceof String); // true

null比较特殊,可以直接判断

function getType(target) {
  // ...
  if (target === null) {
    return "null";
  }
  // ...
}

调用 Object.prototype.toString 方法,会统一返回格式为 [object Xxx] 的字符串,用来表示该对象(原始类型是包装对象)的类型。

// 引用类型 以此类推
console.log(Object.prototype.toString.call({})); // '[object Object]'
console.log(Object.prototype.toString.call(function () {})); // "[object Function]'
console.log(Object.prototype.toString.call(/123/g)); // '[object RegExp]'
console.log(Object.prototype.toString.call(new Date())); // '[object Date]'
console.log(Object.prototype.toString.call([])); // '[object Array]'
console.log(Object.prototype.toString.call(new WeakSet())); // '[object WeakSet]'

// 原始类型  以此类推
console.log(Object.prototype.toString.call(1)); // '[object Number]'
console.log(Object.prototype.toString.call("abc")); // '[object String]'

Object.prototype.toString 方法来获取数据具体的类型,然后把多余的字符去掉即可,只取 [object Xxx] 里的 Xxx

所以最终的代码实现为

function getType(target) {
  // 先进行 typeof 判断,如果是基础数据类型,直接返回。
  const type = typeof target;
  if (type !== "object") {
    return type;
  }

  // 如果是引用类型或者 null,再进行如下的判断,正则返回结果,注意最后返回的类型字符串要全小写。
  return Object.prototype.toString
    .call(target)
    .replace(/^\[object (\S+)\]$/, "$1")
    .toLocaleLowerCase();
}

或者返回

// ...
return Object.prototype.toString
  .call(target)
  .match(/\s([a-zA-Z]+)\]$/)[1] // 这种写法也可以。
  .toLocaleLowerCase();

不用正则表达式也可以哦

// ...
return Object.prototype.toString
  .call(target)
  .slice(8, -1) 
//slice(startIndex,endIndex),从0开始索引,其中8代表从第8位(包含)开始截取(本例中代表空格后面的位置,'['也是代表一位,不要看少了哦),-1代表截取到倒数第一位(不含),所以正好截取到[object String]中的String。
  .toLocaleLowerCase();

call 是函数的方法,是用来改变 this 指向的,用 apply 方法也可以。

如果不改变 this 指向为我们的目标变量 xxxthis 将永远指向调用的 Object.prototype,也就是原型对象,对原型对象调用 toString 方法,结果永远都是 [object Object]

console.log(Object.prototype.toString([]));
// 输出 '[object Object]'  不调用 call,this 指向 Object.prototype,判断类型为 Object。
console.log(Object.prototype.toString.call([]));
// 输出 '[object Array]'   调用 call,this 指向 [],判断类型为 Array

最后加几个学到的常见的js面试问题

1:JavaScript 有哪些数据类型

答: JavaScript 的数据类型分为原始类型和对象类型。

原始类型有 7 种,分别是:

对象类型(也称引用类型)是一个泛称,包括数组、对象、函数等一切对象。

常见面试题 2:typeof null 的结果是什么

答:

typeof null; // 'object'
常见面试题 3:原始类型和引用类型的区别是什么

答:

类型原始类型对象类型
不可改变可以改变
属性和方法不能添加能添加
存储值地址(指针)
比较值的比较地址的比较
常见面试题 4:typeof 和 instanceof 的区别是什么

答:

  • typeof 运算符用来判断数据的类型。
  • instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上,也可以用来判断数据的类型。
    • typeof 返回一个变量的类型字符串,instanceof 返回的是一个布尔值。
    • typeof 可以判断除了 null 以外的基础数据类型,但是判断引用类型时,除了 function 类型,其他的无法准确判断。
    • instanceof 可以准确地判断各种引用类型,但是不能正确判断原始数据类型。
常见面试题 5:Symbol 解决了什么问题

答:Symbol 是 ES6 时新增的特性,Symbol 是一个基本的数据类型,表示独一无二的值,主要用来防止对象属性名冲突问题。

const obj = {
  name: "song",
  age: 18,
};

obj.name = "xxx"; // 给 obj.name 赋值,把以前的 name 覆盖了
console.log(obj); // { name: 'xxx', age: 18 }
copy
const obj = {
  name: "song",
  age: 18,
};
const name = Symbol("name");

obj[name] = "xxx"; // 使用 Symbol,不会覆盖

console.log(obj); // { name: 'song', age: 18, Symbol(name): 'xxx' }
console.log(obj.name); // 'song'
console.log(obj[name]); // 'xxx'

挑战总结

  • 这个题之前几次测试都没过,因为还不是很理解原始类型和对象类型的类型判断的方法
  • Bigint和symbol也不熟悉,感觉第一次看到,不清楚他们是哪一种类型的数据
  • 对instanceof的使用也不够熟练
  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值