实现一个类型判断函数

  1. 判断null
  2. 判断基础类型
  3. 使用Object.prototype.toString.call(target)来判断引用类型

[!NOTE] 注意: 一定是使用call来调用,不然是判断的Object.prototype的类型

之所以要先判断是否为基本类型是因为:虽然Object.prototype.toString.call()能判断出某值是:number/string/boolean,但是其实在包装的时候是把他们先转成了对象然后再判断类型的。 但是JS中包装类型和原始类型还是有差别的,因为对一个包装类型来说,typeof的值是object

/**
 * 类型判断
 */
function getType(target) {
  //先处理最特殊的Null
  if(target === null) {
    return 'null';
  }
  //判断是不是基础类型
  const typeOfT = typeof target
  if(typeOfT !== 'object') {
    return typeOfT;
  }
  //肯定是引用类型了
  const template = {
    "[object Object]": "object",
    "[object Array]" : "array",
    "[object Function]": "function",
    // 一些包装类型
    "[object String]": "object - string",
    "[object Number]": "object - number",
    "[object Boolean]": "object - boolean"
  };
  const typeStr = Object.prototype.toString.call(target);
  return template[typeStr];
}

升级版本

```js // typeof可以检测基本数据类型 // Undefined, Null, Boolean, Number, String, Objec // undefined, object, boolean, number, string, object

// 以下是11种: var number = 1; // [object Number] var string = '123'; // [object String] var boolean = true; // [object Boolean] var und = undefined; // [object Undefined] var nul = null; // [object Null] var obj = {a: 1} // [object Object] var array = [1, 2, 3]; // [object Array] var date = new Date(); // [object Date] var error = new Error(); // [object Error] var reg = /a/g; // [object RegExp] var func = function a(){}; // [object Function]

function checkType() { for (var i = 0; i < arguments.length; i++) { console.log(Object.prototype.toString.call(arguments[i])) } }

checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)

console.log(Object.prototype.toString.call(Math)); // [object Math] console.log(Object.prototype.toString.call(JSON)); // [object JSON]

function a() { console.log(Object.prototype.toString.call(arguments)); // [object Arguments] }

a();

// TODO:Object.toString()的理解? /*1. 如果 this 值是 undefined,就返回 [object Undefined]

  1. 如果 this 的值是 null,就返回 [object Null]
  2. 让 O 成为 ToObject(this) 的结果
  3. 让 class 成为 O 的内部属性 [[Class]] 的值
  4. 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串*/

// TODO:封装一个通用的type API? // v1: 基础版本 var class2type = {};

'Undefined Null String Number Boolean Object Function Array Date RegExp Error' .split(' ') .map(function (item) { // 开始建立映射关系 class2type[[object ${item}]] = item.toLowerCase(); })

function type(obj) { return typeof obj === 'object' || typeof obj === 'function' ? class2type[Object.prototype.toString.call(obj)] || 'object' : typeof obj; }

// v2:在 IE6 中,null 和 undefined 会被 Object.prototype.toString 识别成 [object Object]! // TODO: 解决IE6下的null和undefined 会被识别为[object Object]? var class2type = {}; 'Undefined Null String Number Boolean Object Function Array Date RegExp Error' .split(' ').map(function (item) { class2type[[object ${item}]] = item.toLowerCase(); })

/**

  • 查看type的基础类型
  • @param obj
  • @return {string|} / function type(obj) { // 开始解决ie下的兼容问题 if (obj == null) {
     return obj + '';
    
    } return typeof obj === 'object' || obj === 'function'
         //  ES6 新增的 Symbol、Map、Set 等类型,它们并不在 class2type 列表中,所以使用 type 函数,返回的结果会是 object
         ? class2type[Object.prototype.toString.call(obj)] || 'object'
         : typeof obj;
    
    }

/**

  • 查看obj是否为函数累类型
  • @param obj
  • @return {boolean} */ function isFunction(obj) { return type(obj) === 'function'; }

/**

  • 注意这里的isArray是一个函数,并不是一个函数执行的结果
  • @type {((arg: any) => arg is Array) | (function(=): boolean)} / var isArray = Array.isArray || function (obj) { return type(obj) === 'array'; }

// TODO: plainObject, 就是该对象是通过 "{}" 或 "new Object" 创建的,该对象含有零个或者多个键值对? // 存放toString的映射结果 var class2type = {}; // Object.prototype.toString var toString = class2type.toString(); // Object.prototype.hasOwnProperty var hasOwn = class2type.hasOwnProperty;

function isPlainObject(obj) { // 排除掉宿主对象 eg: toString.call(window) === '[objct window]' if (!obj || toString.call(obj) !== '[object Object]') { return false; }

/**
 * Object.getPrototypeOf() 方法返回指定对象的原型(即, 内部[[Prototype]]属性的值),如果没有继承属性,则返回 null 。
 * eg: obj.__proto__ === Object.protptype
 * @type {any}
 */
var proto = Object.getPrototypeOf(obj);
// 如果没有原型对象的话,eg:Object.create(null), 就是纯对象
if (!proto) {
    return true;
}

// 通过new Object方式创建的对象
// 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructor
var Constructor = hasOwn.call(proto, 'constructor') && proto.constructor;

// 判断Constructor是不是Object的构造函数
return typeof Constructor === 'function' && hasOwn.toString.call(Constructor) === hasOwn.toString.call(Object);

}

// TODO: EmptyObject如何判断? function isEmptyObject(obj) { var name; // 看一下当前的这个obj对象有没有属性,如果有的话就返回false for (name in obj) { // 遍历的不仅仅是obj自身的属性,而且也遍历了obj原型上的属性 return false; } return true; } // test console.log(isEmptyObject({})); // true console.log(isEmptyObject([])); // true console.log(isEmptyObject(null)); // true console.log(isEmptyObject(undefined)); // true console.log(isEmptyObject(1)); // true console.log(isEmptyObject('')); // true console.log(isEmptyObject(true)); // true

// TODO: 判断是否为window对象? // window对象的window属性指向其本身 function isWindow(obj) { return obj != null && obj == obj.window; }

// TODO: 判断是否为document对象? function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE; }

// TODO: 判断是不是DOM元素 function isDOMElement(obj) { // 这里需要强制把返回的结果转换为bool类型,eg:obj = undefined,!!undefined=r\true return !!(obj && obj.nodeType === 1); }

// TODO: isArrayLike如何实现?(可以判断数组和伪数组类型) function isArrayLike(obj) { // 1. 先看obj有没有length属性 var length = !!obj && ('length' in obj) && obj.length; var typeRes = type(obj);

// 2. 排除掉函数和window对象, window也是有length属性的
if (typeRes === 'function' || isWindow(obj)) {
    return false;
}

// 3. 开始处理结果
return typeRes === 'array'                  // 1. 是数组类型
        || length === 0                     // 2. 长度为0(函数中的arguments参数)
        || typeof length === 'number'
        && length > 0
        && (length - 1) in obj;             // 3. length 属性是大于 0 的数字类型,并且obj[length - 1]必须存在(符合条件的类数组对象是一定存在最后一个元素的)

}

// underscore 如何实现的? function isArrayLike(collection) { var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var length = getLength(collection); return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; } ```

results matching ""

    No results matching ""