# 类型检查

  • 值类型(基本类型):String、Number、Boolean、Null、Undefined、Symbol(Es6 新增)。
  • 引用数据类型:Object、Array、Function。

# typeof

  • 可以判断 undefined数值字符串布尔值function
  • 不能判断nullobjectarray

代码示例:





 







// 首先判断基本类型
typeof 1; // number
typeof "Hellow world !"; // string
typeof true; // boolean
typeof null; // object
typeof undefined; // undefined

let s = Symbol();
typeof s; // symbol

typeof NaN // number

👾

null 的判断出了错误

const _obj = Object.create(null);
function foo() {}
const _arr = [];
const _set = new Set();
const _weakset = new WeakSet();
const _map = new Map();
const _weakmap = new WeakMap();

typeof _obj; // object
typeof foo; // function
typeof _arr; // object
typeof _set; // object
typeof _weakset; // object
typeof _map; // object
typeof _weakmap; // object

typeof document.all // undefined

以上示例 typeof 在判断引用类型的时候并不能区分除了 function 以外其他类型的区别。这就要了解下面的原理啦!!!↩️

# typeof 原理

小提示 💁

先看看 js 如何存储数据类型的。

JavaScript 在底层储存变量时出于性能考虑会把数据的类型用前三位表示,typeof 就是通过前三位来判断类型

  • 000: object 对象
  • 001: integer 整数
  • 010: double 浮点数
  • 100: string 字符串
  • 110: boolean 布尔

两个特殊类型:

  • undefined: -2^30
  • null: 全是 0

因为 null 的机器码是全 0,它的类型标签自然就是 000,所以 typeof null 返回object

暂时性死区

// let and const
const fun = () => {
  typeof num;
  let num = 10;
}

fun()  // Cannot access 'num' before initialization

# constructor

原理:constructor指向创建实例对象的构造函数

DANGER

  • 1、null 和 undefined 无该构造函数
  • 2、constructor 可以被改写

// 不安全。 作为辅助判断手段

String.property.constructor = function a(){
  return {}
}

# instanceof

instanceof 是有局限性的,左操作数必须是一个对象右侧操作数必须是函数或者classinstanceof 的原理是判断只要右边的 prototype出现在左边的原型链上就返回 true。 所以说 instanceof 是判断一个实例是否是其父类型或者祖先类型的实例更为恰当。

代码的基本实现:

function instance_of(L, R) {    // L 表示左表达式,R 表示右表达式
 var O = R.prototype;           // 取 R 的显示原型
 L = L.__proto__;               // 取 L 的隐式原型
 while (true) {
   if (L === null)
     return false;
   if (O === L)                 // 当 O 严格等于 L 时,返回 true
     return true;
   L = L.__proto__;
 }
}

代码示例

const obj1 = Object.create(null);
const obj2 = {};

obj1 instanceof Object; // false
obj2 instanceof Object; // true

obj1 是通过Object.create(null)来创建的,它原型链上什么都没有:

而直接通过{}赋值生成的对象它的_proto_是指向 Object 的:

const obj = {};
// 等同于下面
const obj = Object.create(Object.prototype);

注意

<iframe id="ifr" src="./3. instanceOf2.html"></iframe>

<script>
  var frame = window.frames[0];
  var isInstanceOf = [] instanceof frame.Array;
  console.log("frame.Array", frame.Array); // f Array() {[native code]}
  console.log("isInstanceOf", isInstanceOf)  // false
</script>

# ===

可以判断只有唯一值的 undefined 和 null

var a ;
console.log(a === undefined)  // true;
a = null
console.log(a===null)  // true;

_.isUndefined = (val) => {
  return val === void 0; // void 0 靠谱的undefined
}

# Object.prototype.toString.call()

目前比较全面的类型判断方法

原理

通过函数的动态this特性返回其数据类型

Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call("Hellow world !"); // "[object String]"
Object.prototype.toString.call({ a: 123 }); // "[object Object]"
Object.prototype.toString.call(Symbol()); // "[object Symbol]"
Object.prototype.toString.call([1, 2, 3]); // "[object Array]"
Object.prototype.toString.call(function a() {}); // "[object Function]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call(Math); // "[object Math]"
Object.prototype.toString.call(new Set()); // "[object Set]"
Object.prototype.toString.call(new WeakSet()); // "[object WeakSet]"
Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(new WeakMap()); // "[object WeakMap]"

封装方法

function getClass(a) {
  const str = Object.prototype.toString.call(a);
  return /^\[object (.*)\]$/.exec(str)[1];
}

原理参考谈谈 Object.prototype.toString (opens new window)

Last Updated: 3/12/2023, 11:01:13 PM