基本数据类型

  1. 包括基础(原始)数据类型 和引用(复杂)数据类型

原始数据类型(基本数据类型):

  1. 数值类型(Number): 整数和浮点数
  2. 字符串类型(String): 用引号括起来的
  3. 布尔类型(Boolean):true和false
  4. undefined类型:确定一个已经声明但还没有赋值的变量
  5. null类型:表明某个变量的值为空 (空对象指针)
  6. Symbol 类似于一种标识唯一性的ID Symbol 是独一无二的所以可以保证对象属性的唯一
  7. Bigint 可以表示任意大的整数 BigInt(value); value: 创建对象的数值。可以是字符串或者整数

引用数据类型(对象数据类型):

  1. 对象 :Object
  2. 数值 :Array
  3. 函数 :function

所有的引用数据类型数据的创建都要开辟一个【堆内存】

检测数据类型

  1. typeof 用来检测数据类型的 【运算符】****【返回的结果是一个字符串】
  2. instanceof 用来检测当前实例是否属于某个类,【变相用来检测数据类型,看作是对typeof的补充
  3. constructor 基于构造函数检测数据类型,(也是基于类的方式)
  4. Object.prototype.toString.call([value]) 【检测数据类型的最好方法】

typeof

特点1:返回的结果是字符串,字符串中包含了对应的数据类型

  1. typeof typeof typeof [1,2,3] //面试题
  • 因为typeof检测的结果都是字符串,所以只要两个及以上同时检测,最后结果必然是”string”

特点2:按照计算机底层存储的二进制进行检测(实现原理)优点:性能好


  1. GetValue(val)[c++内部提供的方法], 按照值存储的二进制进行检测
  2. 对象 000 -> 实现call,则返回’function’ , 没实现call返回’object’
  3. null 000000 -> 肯定没实现call ,返回’object’
  4. undefined -2**30**
  5. 数字
  6. 整数 1
  7. 浮点数 010
  8. 字符串 100
  9. 布尔 110
  10. 由于是按照二进制来检测,速度很快,除了null 都很准确

    特点3:typeof null -> “object” null的结果是object 因为 null 是0000000

    特点4:typeof Object && typeof function(){} -> “function”

  • 验证是否是对象的判断
  • 缺点:不能细分出具体为什么类型的对象 ,因为只要是对象数据类型,返回的结果都是”object”
  • typeof 数组/正则/日期/对象 【只要是对象数据类型】=>’object’

    特点5:typeof 未被声明的变量 -> “undefined”

  1. //【对于基本数据类型】
  2. let a = NaN;
  3. typeof 1;//=>"number"
  4. typeof a;//=>"number"
  5. typeof NaN;;//=>"number"
  6. typeof 'string';//=>"string"
  7. typeof true;//=>"boolean"
  8. typeof undefined;//=>"undefined"
  9. typeof null;//"object"
  10. typeof typeof undefined;//=>"string"
  11. //【对于引用数据类型】
  12. typeof {};//=>"object"
  13. typeof [];//=>"object"
  14. typeof /^/;//=>"object"
  15. typeof function(){};//=>"function"
  16. typeof typeof typeof function(){};//=>"string"

typeof 能检测的:

  1. **function****string****number****boolean****undefined****symbol

    typeof 不能检测的:

  2. **null** **对象** 都会被检测为 **object** !!

  3. 除了可调用(实现call对象, 函数会返回’function’)
  4. 不论是箭头函数、还是构造函数、还是生成器函数、以及普通函数等,都返回function
  5. 其余的对象数据值(不实现call)返回都是’object’
  6. 检测一个未被声明的变量不会报错 报 undefined

    instanceof

instance运算符用于通过 查找** 原型链 来检测某个变量 是否 为某个类型数据的**实例。使用instanceof 运算符可以判断一个变量是数组还是对象。

A instanceof B 判断 A 是否为 B 的实例

是什么:instanceof 是用来判断实例对象 A 是否为构造函数 B 的实例 (返回 true / false)
基本原理:根据原型链检测,只要在原型链上就为 true,一直找到 object.prototype

【缺陷】:**

  • 不能用来处理基本数据类型(基本数据类型基于构造函数方式创建的实例是可以的)
  • 只要出现在实例的原型链上的类,该实例的检测结果都是true**(可以手动更改原型链的指向,这样导致检测结果不一定准确)
  1. let arr = [],
  2. reg = /^$/;
  3. const b = {name: 'xx'};
  4. console.log(arr instanceof Array);//=>true
  5. console.log(arr instanceof Object);//=>true
  6. console.log(b instanceof Array); // false
  7. console.log(b instanceof Object); // true
  8. console.log(reg instanceof Array);//=>false
  9. console.log(1 instanceof Number);//=>false
  10. console.log(new Number(1) instanceof Number);//=>true
  11. console.log(Symbol() instanceof Symbol);//=>false
  12. function fn(){}
  13. fn.prototype = Array.prototype;
  14. let f = new fn;
  15. console,log(f instanceof Array);//=>true

constructor: 基于构造函数检测数据类型

constructor主要是利用原型上的prototype.constructor指向实例的构造函数来进行判断的

null, undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

  • constructor 判断类型的限制过多且不准确,容易出错,少用,或者不用!
  1. const a = [0, 1, 2];
  2. console.log(a.constructor === Array); // true
  3. console.log(a.constructor === Object); // false
  4. const b = {name: 'xx'};
  5. console.log(b.constructor === Array); // false
  6. console.log(b.constructor === Object); // true
  7. console.log('1'.constructor === String); // true
  8. console.log(new Number(1).constructor === Number); // true
  9. console.log(true.constructor === Boolean); // true
  10. console.log(alert.constructor === Function); // true
  11. console.log([].constructor === Array); // true
  12. console.log(new Date().constructor === Date); // true

Object.prototype.toString.call():【检测数据类型的最好方法】准确的数据类型

最强大的检测数据类型的方法,(基本上没有弊端)

  • 对于 number 类型,结果是 [object Number]
  • 对于 boolean 类型,结果是 [object Boolean]
  • 对于 null:[object Null]
  • 对于 undefined:[object Undefined]
  • 对于数组:[object Array]
  • 对于对象:[object Object]
  • ……等(可自定义)\ ```javascript object.prototype.toString.call(null) //“[object Null]” object.prototype.toString.call(1)// “[object Number]” object.prototype.toString.call(new Number(1)) //“[object Number]” object.prototype.toString.call(Symbol()) //“[object Symbol]” object.prototype.toString.call(function(){}) //“[object Function]” object.prototype.toString.call(Object) //“[object Function]” object.prototype.toString.call({}) //“[object Object]” object.prototype.toString.call([]) //“[object Array]” object.prototype.toString.call(/^$/) //“[object RegExp]” object.prototype.toString.call(new Date()) //“[object Date]”

function fn(){} let f = new fn();

object.prototype.toString.call(f);//=>’[object object]’

  1. **原理:**<br />![](https://cdn.nlark.com/yuque/0/2021/png/1489212/1612144642671-75a8cfb5-32a8-4296-aca3-bb5b5edc5e7f.png#align=left&display=inline&height=192&margin=%5Bobject%20Object%5D&originHeight=384&originWidth=1027&status=done&style=none&width=513)<br />toString:
  2. 1. 对于Object:**检测数据类型**
  3. 1. 对于Object的实例:**转换为字符串**
  4. **为什么不直接用 obj.toString () 呢?**<br />非普通对象.toString :调取的都是自己所属类原型上的toString,并不是Object.prototype.toString,都是转换为字符串<br />普通对象.toString :调取Object.prototype.toString这个方法,所以是检测数据类型
  5. ```javascript
  6. console.log("jerry".toString()); // jerry
  7. console.log({name: "leo"}.toString()); // [object, object]
  8. console.log((1).toString()); // 1
  9. console.log([1,2].toString()); // 1,2
  10. console.log(new Date().toString()); // Wed Dec 21 2016 20:35:48 GMT+0800 (中国标准时间)
  11. console.log(function(){}.toString()); // function (){}
  12. console.log(null.toString()); // error
  13. console.log(undefined.toString()); // error

同样是检测对象 obj 调用 toString 方法,obj.toString () 的结果Object.prototype.toString.call (obj) 的结果不一样,这是为什么?

  1. console.log(Object.prototype.toString.call("jerry")); //[object String]
  2. console.log(Object.prototype.toString.call(12)); //[object Number]
  3. console.log(Object.prototype.toString.call(true)); //[object Boolean]
  4. console.log(Object.prototype.toString.call(undefined)); //[object Undefined]
  5. console.log(Object.prototype.toString.call(null)); //[object Null]
  6. console.log(Object.prototype.toString.call({name: "leo"})); //[object Object]
  7. console.log(Object.prototype.toString.call(function(){})); //[object Function]
  8. console.log(Object.prototype.toString.call([])); //[object Array]
  9. console.log(Object.prototype.toString.call(new Date)); //[object Date]
  10. console.log(Object.prototype.toString.call(/\d/)); //[object RegExp]
  11. function Person(){};
  12. console.log(Object.prototype.toString.call(new Person)); //[object Object]
  1. 这是因为 toString 为 Object 的原型方法,而 Array 、Function 等类型作为 Object 的实例,都重写了 toString 方法
  2. 不同的对象类型调用 toString 方法时,根据原型链的知识,调用的是对应的重写之后的 toString 方法(Function 类型返回内容为函数体的字符串,Array 类型返回元素组成的字符串…..),而不会去调用 Object 上原型 toString 方法(返回对象的具体类型),所以采用 obj.toString () 不能得到其对象类型,只能将 obj 转换为字符串类型;
  3. 因此,在想要得到对象的具体类型时,应该调用 Object 上原型 toString 方法
  4. 为了实现这个目的,就使用call来借用该方法

我们可以验证一下,将数组的 toString 方法删除,看看会是什么结果

  1. var arr=[1,2,3];
  2. console.log(Array.prototype.hasOwnProperty("toString"));//true
  3. console.log(arr.toString());//1,2,3
  4. delete Array.prototype.toString;//delete操作符可以删除实例属性
  5. console.log(Array.prototype.hasOwnProperty("toString"));//false
  6. console.log(arr.toString());//"[object Array]"

删除了 Array 的 toString 方法后,同样再采用 arr.toString () 方法调用时,不再有屏蔽 Object 原型方法的实例方法,因此沿着原型链,arr 最后调用了 Object 的 toString 方法,返回了和 Object.prototype.toString.call (arr) 相同的结果。

  1. 修改Symbol.toStringTag

Symbol.toStringTag 的例子。可以看出,属性值期望是一个字符串,否则会被忽略。

  1. var o1 = { [Symbol.toStringTag]: "A" };
  2. var o2 = { [Symbol.toStringTag]: null };
  3. Object.prototype.toString.call(o1); // => "[object A]"
  4. Object.prototype.toString.call(o2); // => "[object Object]"

最终方案:

这里我们来给它封装成一个方法,用于准确判断变量的类型。

  1. function judge(type) {
  2. var string = Object.prototype.toString.call(type);
  3. return string.substr(8, string.length - 9); 截取一下
  4. }
  5. 案例:
  6. let a = 4;
  7. let c = [];
  8. function judge(type) {
  9. var string = Object.prototype.toString.call(type);
  10. return string.substr(8, string.length - 9)
  11. }
  12. console.log(judge(c)) // Array
  13. console.log(judge(a)) // Number

**