资讯专栏INFORMATION COLUMN

【基础】JavaScript类型判断

YuboonaZhang / 1014人阅读

摘要:基本类型类对象纯对象类数组其中部分参考了的函数实现。比如说所以如果此时对象不是由内置构造函数生成的对象,这个为。判断对于类数组对象,只要该对象中存在属性并且为非负整数且在有限范围之内即可判断为类数组对象。

本文主要讲解如何准确判断JavaScript中出现的各种类型和对象。(基本类型、Object类、Window对象、纯对象plainObject、类数组)其中部分参考了jQuery的函数实现。
typeof

JavaScript定义的数据类型有UndefinedNullBooleanNumberStringObjectSymbol(ES6新增)。

其中typeof对大部分的数据类型都能够准确识别,如下:

typeof undefined // "undefined"
typeof null // "object"
typeof true // "boolean"
typeof 1 // "number"
typeof "s" // "string"
typeof {} // "object"
typeof function a() {} // "function"
typeof Symbol("2") // "symbol"

其中返回的字符串首字母都是小写的。

对于typeof null === "object"来说,这其实是一个bug

在JavaScript中,Object下还有很多细分的类型,比如说DateRegExpErrorArrayFunction

typeof除了能够准确的判断出Function之外,对于其他细分类型均返回object

Object.prototype.toString()

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

如果this值是undefined,就返回[object Undefined]

如果this的值是null,就返回[object Null]

O成为ToObject(this)的结果

class成为O的内部属性[[Class]]的值

最后返回由"[object "class"]"三个部分组成的字符串

该方法至少可以识别14种类型。

// 以下是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)

// 还有不常见的Math、JSON
console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]

// 还有一个arguments
function a() {
    console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}
a();
type API
结合上面我们可以写一个type函数,其中基本类型值走typeof,引用类型值走toString
var class2type = {};

// 生成class2type映射
"Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) {
    class2type["[object " + item + "]"] = item.toLowerCase();
})

function type(obj) {
    // 一箭双雕
    if (obj == null) {
        return obj + "";
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[Object.prototype.toString.call(obj)] || "object" :
        typeof obj;
}

通过toLowerCase()小写化和typeof的结果是小写一致。

注意IE6中toString()会把UndefinedNull都识别为[object Object],所以加了一个判断,直接调用+来隐式toString()-> "null"

这里之所以class2type[Object.prototype.toString.call(obj)] || "object"是考虑到ES6新增的SymbolMapSet在集合class2type中没有,直接把他们识别成object

这个type其实就是jQuery中的type

isFunction

之后可以直接封装:

function isFunction(obj) {
    return type(obj) === "function";
}
数组
var isArray = Array.isArray || function( obj ) {
    return type(obj) === "array";
}

jQuery3.0中已经完全使用Array.isArray()

plainObject

plainObject翻译为中文即为纯对象,所谓的纯对象,就是该对象是通过{}new Object()创建的。

判断是否为“纯对象”,是为了和其他对象区分开比如说null、数组以及宿主对象(所有的DOMBOM都是数组对象)等。

jQuery中有提供了该方法的实现,除了规定该对象是通过{}new Object()创建的,且对象含有零个或者多个键值对外,一个没有原型(__proto__)的对象也是一个纯对象。

console.log($.isPlainObject({})) // true

console.log($.isPlainObject(new Object)) // true

console.log($.isPlainObject(Object.create(null))); // true

jQuery3.0版本的plainObject实现如下:

var toString = Object.prototype.toString;

var hasOwn = Object.prototype.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 = hasOwn.call(proto, "constructor") && proto.constructor;

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

注意最后这一句非常的重要:

hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object)

hasOwn.toString调用的其实是Function.prototype.toString()而不是Object.prototype.toString(),因为hasOwnProperty是一个函数,它的原型是Function,于是Function.prototype.toString覆盖了Object.prototype.toString

Function.prototype.toString()会把整个函数体转换成一个字符串。如果该函数是内置函数的话,会返回一个表示函数源代码的字符串。比如说:

Function.prototype.toString(Object) === function Object() { [native code] }

所以如果此时对象不是由内置构造函数生成的对象,这个hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object)false

function Person(name) {
    this.name = name;
}
var person = new Person("Devin");
plainObject(person) === false; // true
// 其实就是`hasOwn.toString.call(Ctor) === "function Person(name) { this.name = name; }"
Window对象

Window对象有一个特性:Window.window指向自身。

Window.window === Window; //true
类数组对象

常见的类数组有函数的argumentsNodeList对象。

判断

对于类数组对象,只要该对象中存在length属性并且length为非负整数且在有限范围之内即可判断为类数组对象。

JavaScript权威指南中提供了方法:

function isArrayLike(o) {
    if (o && // o is not null, undefined, etc
        // o is an object
        typeof o === "object" &&
        // o.length is a finite number
        isFinite(o.length) &&
        // o.length is non-negative
        o.length >= 0 &&
        // o.length is an integer
        o.length === Math.floor(o.length) &&
        // o.length < 2^32
        o.length < 4294967296) //数组的上限值
          return true;
    else 
          return false;
}

以上的判断无论是真的数组对象或是类数组对象都会返回true,那我们如何区分到底是真的数组对象还是类数组对象?

其实只需要先判断是否为数组对象即可。

function utilArray(o) {
    if (Array.isArray(o)) {
        return "array";
    }
    if (isArrayLike(o)) {
        return "arrayLike";
    } else {
        return "neither array nor arrayLike";
    }
}
类数组对象的特征

类数组对象并不关心除了数字索引和length以外的东西。

比如说:

var a = {"1": "a", "2": "b", "4": "c", "abc": "abc", length: 5};
Array.prototype.join.call(a, "+"); // +a+b++c

其中,"0""3"没有直接省略为两个undefined,同样的abc被忽略为undefined

如果length多出实际的位数会补undefined(空位也补充undefined),少位则截断后面的数组成员。

var a = {"1": "a", "2": "b", "4": "c", "abc": "abc", length: 6};
Array.from(a); // [undefined, "a", "b", undefined, "c", undefined]

var a = {"1": "a", "2": "b", "4": "c", "abc": "abc", length: 5};
Array.from(a); // [undefined, "a", "b", undefined, "c"]

var a = {"1": "a", "2": "b", "4": "c", "abc": "abc", length: 4};
Array.from(a); // [undefined, "a", "b", undefined]
类数组对象的转换

Array.from

该方法从一个类似数组或可迭代对象中创建一个新的数组实例。

Array.from("foo");
// ["f", "o", "o"]

Array.prototype.slice

该方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。

var a = {"0":"a", "1":"b", "2":"c", length: 3};
Array.prototype.slice.call(a, 0); // ["a", "b", "c"]

ES6扩展运算符

var a = "hello";
[...a]; //["h", "e", "l", "l", "o"]

参考链接:

https://github.com/mqyqingfen...

https://github.com/mqyqingfen...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107601.html

相关文章

  • javascript基础判断变量类型

    摘要:判断变量类型数据类型种操作符可能返回的值如下注意的能力有限,其对于类型返回的都是使用场景区分对象和原始类型要区分一种对象类型和另一种对象类型可以使用运算符或对象属性运算符用法左边的运算数是一个右边运算数是对象类的名字或者构造函数返回或如果是 判断变量类型 javaSctipt数据类型7种: Number, String, Boolean, Null, Undefined, Object...

    jsdt 评论0 收藏0
  • task0002(一)- JavaScript数据类型及语言基础

    摘要:不过让流行起来的原因应该是是目前所有主流浏览器上唯一支持的脚本语言。经过测试,数字字符串布尔日期可以直接赋值,修改不会产生影响。再考虑对象类型为或者的情况。对于结果声明其类型。判断对象的类型是还是,结果类型更改。 转载自我的个人博客 欢迎大家批评指正 1. 第一个页面交互 这里最需要学习的老师的代码中,每一部分功能都由函数控制,没有创建一个全部变量。且最后有一个函数来控制执行代码...

    elarity 评论0 收藏0
  • javascript基础细节

    摘要:语法部分属性默认的就是,所以不必显式指定为。不强制在每个语句结尾加,会自动加分号,但是在某些情况下会改变程序的语义,所以最好主动加。实际上,默认有一个全局对象。 语法部分: 1.type 属性: 默认的 type 就是 javascript, 所以不必显式指定 type 为 javascript。2.javascript 不强制在每个语句结尾加 ; , javascript 会自...

    wangxinarhat 评论0 收藏0
  • 【1】JavaScript 基础深入——数据类型深入理解与总结

    摘要:类型的实例首先要理解的含义是例子的意思,实际上是判断是否是的一个实例。 数据类型深入理解 数据类型分类 基本(值)类型(5种) String:任意字符串 Number:任意的数字 boolean:true/false null:null undefined:undefined 对象(引用)类型(3种) Object:任意对象 Array:一种特别的对象(数值下...

    since1986 评论0 收藏0
  • JavaScript数据类型及语言基础--ife

    摘要:判断是否为一个函数,返回一个值。使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝被复制的对象类型会被限制为数字字符串布尔日期数组对象。经过测试,数字字符串布尔日期可以直接赋值,修改不会产生影响。再考虑对象类型为或者的情况。 //判断arr是否为一个数组,返回一个bool值 首先javascript有5大基本数据类型:Undefined,Null,Boolean,Num...

    RayKr 评论0 收藏0
  • Js基础知识(一) - 变量

    摘要:内置函数和对象中内置了一些函数和对象,很多语言都会有内置的方法,直接可以调用开发。根据语法标准提供的内置函数包括和。注意基础语法提供的内置函数和方法只有这些,像那是浏览器提供给我们的。强制类型转换大家应该都知道。 js基础 - 变量 *大家对js一定不会陌生,入门很简单(普通入门),很多人通过网络资源、书籍、课堂等很多途径学习js,但是有些js基础的只是往往被大家遗漏,本章就从js变量...

    leone 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<