博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【基础】JavaScript类型判断
阅读量:6721 次
发布时间:2019-06-25

本文共 6617 字,大约阅读时间需要 22 分钟。

本文主要讲解如何准确判断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、JSONconsole.log(Object.prototype.toString.call(Math)); // [object Math]console.log(Object.prototype.toString.call(JSON)); // [object JSON]// 还有一个argumentsfunction 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({})) // trueconsole.log($.isPlainObject(new Object)) // trueconsole.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"]

参考链接:

转载地址:http://ycjmo.baihongyu.com/

你可能感兴趣的文章
Linux命令(19):ln命令
查看>>
Python里的OS模块常用函数说明
查看>>
sql:拼接字符串、截取字符串、取字符串长度
查看>>
mysql 主从复制
查看>>
php动态扩展bcmath与sockets库模块
查看>>
记录quick cocos2d-x3.2升级至cocos2d-x3.8
查看>>
2012.5.22
查看>>
洛谷——P1265 公路修建
查看>>
Redhat 与Windows下的远程桌面
查看>>
10天学通Android开发(8)-多媒体
查看>>
Zabbix监控屏幕全屏显示多个监控项
查看>>
windows 实验报告
查看>>
$POST 、$HTTP_RAW_POST_DATA、php://input三者之间的区别
查看>>
SQL SERVER 2008 自动备份图解教程
查看>>
Docker分离部署LNMP
查看>>
Tomcat version 7.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 and 6 Web mod
查看>>
oracle忘记system密码修改方法
查看>>
RHEL7.x解决SSH登录慢
查看>>
linux下如何删除大量小文件
查看>>
对于背板带宽和包转发率的解释
查看>>