Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 的类型判断 #1

Open
xiaochengzi6 opened this issue May 19, 2022 · 0 comments
Open

JavaScript 的类型判断 #1

xiaochengzi6 opened this issue May 19, 2022 · 0 comments
Labels
JavaScript JavaScript 语言的学习

Comments

@xiaochengzi6
Copy link
Owner

xiaochengzi6 commented May 19, 2022

将目光放在 es6 之前 js 类型有六种 Undefined null String Number Boolean Object

Object 类型中包含着 函数 、日期 、正则 、数组、(数组和类数组) 错误类型; 如果再将 Object 细分一下还会有 planinObject 空对象 Window对象等

除此之外还有 Math Json 类型

常用的类型判断方法会使用 typeof

console.log(typeof 'abc') // string 

使用 typeof 会返回 undefined、object、boolean、number、string、object 和 function

在面对其他类型时 如 数组或者正则 typeof 只能返回 object 这时候要采取其他的方法来判断

Object.prototype.toString 当 toString 方法被调用的时候,下面的步骤会被执行:

  1. 如果 this 值是 undefined,就返回 [object Undefined]
  2. 如果 this 的值是 null,就返回 [object Null]
  3. 让 O 成为 ToObject(this) 的结果
  4. 让 class 成为 O 的内部属性 [[Class]] 的值
  5. 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串
// 最后返回的结果 "[object " 和 class 和 "]" 
console.log(Object.prototype.toString.call(date)) // [object Date]

使用 Object.prototype.toString 我们至少可以识别 14种类型

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]

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]
}
//甚至还有
Object.prototype.toString.call(window)
"[object Window]"
Object.prototype.toString.call(document);
"[object HTMLDocument]"

照抄一个判断类型

var class2type = {};
// 判断11种类型 生成一组映射
"Boolean Number String Function Array Date RegExp Object Error Null Undefined".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
})
function type(obj) {
    // IE6中 null 和 undefined 返回的时 [object object] 而且 null == undefined
    if(obj == null){
        return obj + '';
    }
    
    return typeof obj === 'object' || typeof obj === 'function' ? 
        class2type[Object.prototype.toString.call(obj)] || 'object': 
    typeof obj
}

// 判断数组 也可以使用 Array.isArray()
var isArray = Array.isArray || function(obj){
    return type(obj) === 'array';
}

判断数据类型的type函数的扩展性不太好类似像window location navigator document都会返回object

function type(obj) {
    if(typeof obj !== 'object' || typeof obj === 'function'){
        return typeof obj;
    }else{
        return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
    }
}

数字(Number)中 再一次的划分整数、NaN、-0、0 、浮点数、Infinity、-Infinity

// 判断 NaN 它不和自身相等
let isNaN = Number.isNaN || (obj) => (obj !== obj)


//有穷正数/infinity = 0
//有穷负数/infinity = -0
0 === -0 // true
-3/0 // -0

let is = Object.is || function(v1,v2){
    // 判断是否是 -0;
    if(v1 === 0 && v2 === 0) {
        return 1/v1 === 1/v2;
    }
    // 判断NaN
    if(v1 !== v1 ) {
        return v2 !== v2
    }
    return v1 === v2
}

关于类型判断我们还可以使用这些方法:

  1. typeof
  2. constructor
  3. instanceof
  4. Object.prototype.toString

plainObject

可以翻译成纯粹的对象,所谓"纯粹的对象",就是该对象是通过 "{}" 或 "new Object" 创建的,该对象含有零个或者多个键值对。除了 {} 和 new Object 创建的之外,jQuery 认为一个没有原型的对象也是一个纯粹的对象。

var class2type = {};

// 相当于 Object.prototype.toString
var toString = class2type.toString;

// 相当于 Object.prototype.hasOwnProperty
var hasOwn = class2type.hasOwnProperty;

function isPlainObject(obj) {
    var proto, Ctor;

    // 排除掉明显不是obj的以及一些宿主对象如Window
    if (!obj || toString.call(obj) !== "[object Object]") {
        return false;
    }

    /**
     * getPrototypeOf es5 方法,获取 obj 的原型
     * 以 new Object 创建的对象为例的话
     * obj.__proto__ === Object.prototype
     */
    proto = Object.getPrototypeOf(obj);

    // 没有原型的对象是纯粹的,Object.create(null) 就在这里返回 true
    if (!proto) {
        return true;
    }

    /**
     * 以下判断通过 new Object 方式创建的对象
     * 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructor
     * 如果是 Object 函数创建的对象,Ctor 在这里就等于 Object 构造函数
     */
    Ctor = Object.prototypr.hasownProperty.call(proto, "constructor") && proto.constructor;

    // 在这里判断 Ctor 构造函数是不是 Object 构造函数,用于区分自定义构造函数和 Object 构造函数
    return typeof Ctor === "function" && hasOwn.toString.call(Ctor) === obj.toString.call(Object);
}

注意:我们判断 Ctor 构造函数是不是 Object 构造函数,用的是 hasOwn.toString.call(Ctor),这个方法可不是 Object.prototype.toString,不信我们在函数里加上下面这两句话:

//举例子:
var p = function () {}
console.log(p.toString.call(Ctor)); // function Object() { [native code] }
console.log(Object.prototype.toString.call(p)); // [object Function]

发现返回的值并不一样,这是因为 hasOwn.toString 调用的其实是 Function.prototype.toString,毕竟 hasOwnProperty 可是一个函数!

hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object) 
//可以换成
Ctor.toString.call(Ctor) === class2type.constructor.toString.call(Object)

空对象

function isEmptyObject( obj ) {
        var name;
    //for 循环一旦执行,就说明有属性,有属性就会返回 false。
        for ( name in obj ) {
            return false;
        }
        return true;
}
isEmptyObject('') //true  还是存在点问题(这里默认你传进来的参数时对象并没有判断类型)

Window对象

function isWindow (obj){
    //Window 对象作为客户端 JavaScript 的全局对象,它有一个 window 属性指向自身
    return obj ! = null && obj === obj.window
}

判断是否是数组(数组和类数组)

function isArrayLike(obj) {

    // obj 必须有 length属性
    var length = !!obj && "length" in obj && obj.length;
    var typeRes = type(obj);

    // 排除掉函数和 Window 对象
    if (typeRes === "function" || isWindow(obj)) {
        return false;
    }

    return typeRes === "array" || length === 0 ||
        // 长度必须是数字 或者长度大于0 或者最后一个值必须存在
        typeof length === "number" && length > 0 && (length - 1) in obj;
}

//另外的版本
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;

var isArrayLike = function(collection) {
    var length = getLength(collection);
    // 长度必须是数字并且长度大于0并且长度小于最大长度
    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

es6 以后 类型又增加了 Symbol Set Map 还有ES2020中 BigInt

var symb = Symbol('test'); // [object Symbol]
var set = new Set();       // [object Set]
var map = new Map();       // [object Map]
var bigI = BigInt(1);      // [object BigInt]

参考

JavaScript 类型判断(上)

JavaScript 类型判断(下)

@xiaochengzi6 xiaochengzi6 added the JavaScript JavaScript 语言的学习 label May 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScript JavaScript 语言的学习
Projects
None yet
Development

No branches or pull requests

1 participant