彦霖兄 發表於 2019-5-6 09:21:00

JavaScript中准确的判断数据类型

<p><span style="font-size: 16px">  在 ECMAScript 规范中,共定义了 7 种数据类型,分为<span style="color: rgba(255, 0, 255, 1)">基本类型</span>和<span style="color: rgba(255, 0, 255, 1)">引用类型</span>两大类。</span></p>
<p><span style="font-size: 16px">  其中:</span></p>
<p><strong> <span style="font-size: 16px"> 基本类型</span></strong><span style="font-size: 16px">:String、Number、Boolean、Symbol、Undefined、Null<strong>&nbsp;</strong></span></p>
<p><span style="font-size: 16px"><strong> &nbsp; &nbsp;引用类型</strong>:Object</span></p>
<p><span style="font-size: 16px">  <span style="color: rgba(255, 0, 255, 1)">基本类型</span>也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其<span style="color: rgba(255, 0, 255, 1)">存储在栈(stack)中</span>,即<span style="color: rgba(255, 0, 255, 1)">按值访问</span>。</span></p>
<p><span style="font-size: 16px">  <span style="color: rgba(255, 0, 255, 1)">引用类型</span>也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值<span style="color: rgba(255, 0, 255, 1)">存储在堆(heap)中</span>,而存储在变量处的值,是一个<span style="color: rgba(255, 0, 255, 1)">指针</span>,指向存储对象的内存处,即<span style="color: rgba(255, 0, 255, 1)">按址访问</span>。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。</span></p>
<p><span style="font-size: 16px">  下面介绍常用的4种判断数据类型的方法,并对各个方法存在的问题进行简单的分析。</span></p>
<p><span style="font-size: 14pt; color: rgba(255, 0, 0, 1)">一、typeof</span></p>
<p><span style="font-size: 16px">&nbsp;  typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。</span></p>
<p><span style="font-size: 16px">  返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:<span style="color: rgba(255, 0, 255, 1)">string、number、boolean、symbol、undefined、object、function</span> 等。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">typeof</span> 'a'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> 1; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">boolean 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> Symbol(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> symbol 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> undefined; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">undefined 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Function(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> function 有效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">null</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object 无效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object 无效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> RegExp(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object 无效</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Date(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object 无效</span></pre>
</div>
<p><span style="font-size: 16px">  <span style="color: rgba(255, 0, 255, 1)">总结:</span></span></p>
<ul>
<li><span style="font-size: 16px">对于基本类型,除 null 以外,均可以返回正确的结果。</span></li>
<li><span style="font-size: 16px">对于引用类型,除 function 以外,一律返回 object 类型。</span></li>
<li><span style="font-size: 16px">对于 null ,返回 object 类型。</span></li>
<li><span style="font-size: 16px">对于 function 返回 &nbsp;function 类型。</span></li>
</ul>
<p><span style="font-size: 16px">  其中,null 有属于自己的数据类型 Null ,引用类型中的数组、日期、正则 也都有属于自己的具体类型,而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型。</span></p>
<p><span style="color: rgba(255, 0, 0, 1); font-size: 14pt">二、instanceof</span></p>
<p><span style="color: rgba(0, 0, 0, 1); font-size: 16px">  <span style="color: rgba(255, 0, 255, 1)">instanceof 检测的是原型</span>,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。</span></p>
<div class="cnblogs_code">
<pre>[] <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Array; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
<span style="color: rgba(0, 0, 255, 1)">new</span> Date() <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Date;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>

<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person(){};
</span><span style="color: rgba(0, 0, 255, 1)">new</span> Person() <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Person;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true</span>
<span style="color: rgba(0, 0, 0, 1)">
[] </span><span style="color: rgba(0, 0, 255, 1)">instanceof</span> Object; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
<span style="color: rgba(0, 0, 255, 1)">new</span> Date() <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Object;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
<span style="color: rgba(0, 0, 255, 1)">new</span> Person <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Object;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span></pre>
</div>
<p>  <span style="font-size: 16px">虽然 instanceof 能够判断出 [ ] 是Array的实例,但它认为 [ ] 也是Object的实例,为什么呢?</span></p>
<p><span style="font-size: 16px"> &nbsp; 从 instanceof 能够判断出 [ ].__proto__ &nbsp;指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终 Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[ ]、Array、Object 就在内部形成了一条原型链,如下图所示:</span></p>
<p><span style="font-size: 16px"><img src="https://img2018.cnblogs.com/blog/1541422/201905/1541422-20190505162207307-2016328612.png"></span></p>
<p>&nbsp;</p>
<p>  &nbsp;<span style="font-size: 16px">从原型链可以看出,[] 的 __proto__ &nbsp;直接指向Array.prototype,间接指向 Object.prototype,所以按照&nbsp;instanceof&nbsp;的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。</span></p>
<p><span style="font-size: 16px">  因此,<span style="color: rgba(255, 0, 255, 1)"><strong>instanceof 只能用来判断两个对象是否属于实例关系</strong></span><strong><span style="color: rgba(255, 0, 255, 1)">, 而不能判断一个对象实例具体属于哪种类型</span>。</strong>&nbsp;</span></p>
<p><span style="font-size: 16px">&nbsp; &nbsp; <span class="fontstyle0"><span class="fontstyle2"><span class="fontstyle0"><span class="fontstyle2"><span class="fontstyle3">针对数组的这个问题,ES5&nbsp;<span class="fontstyle2">提供了<span style="color: rgba(255, 0, 255, 1)">&nbsp;</span><span class="fontstyle0"><span style="color: rgba(255, 0, 255, 1)">Array.isArray()&nbsp;</span><span class="fontstyle2"><span style="color: rgba(255, 0, 255, 1)">方法</span> 。该方法用以确认某个对象本身是否为 Array 类型<span class="fontstyle0"><span class="fontstyle2"><span class="fontstyle0"><span class="fontstyle2"><span class="fontstyle3"><span class="fontstyle2"><span class="fontstyle0"><span class="fontstyle2">,而不区分该对象在哪个环境中创建。</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (Array.isArray(value)){
   </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">对数组执行某些操作</span>
}</pre>
</div>
<p><span style="font-size: 16px">  Array.isArray() 本质上检测的是<span style="color: rgba(255, 0, 255, 1)">对象的 [] 值<span style="color: rgba(0, 0, 0, 1)">。</span></span></span></p>
<p><span style="font-size: 16px">  [] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 ,Xxx 就是对应的具体类型 。对于数组而言,[] 的值就是 。</span></p>
<p><span style="font-size: 14pt; background-color: rgba(255, 255, 255, 1); color: rgba(255, 0, 0, 1)">三、constructor</span></p>
<p><span style="font-size: 14pt; background-color: rgba(255, 255, 255, 1); color: rgba(255, 0, 0, 1)">  <span style="color: rgba(0, 0, 0, 1); font-size: 16px">当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下图所示:</span></span></p>
<p><img src="https://img2018.cnblogs.com/blog/1541422/201905/1541422-20190505162935973-140764779.png"></p>
<p><span style="font-size: 16px">&nbsp;  当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F</span></p>
<p><img src="https://img2018.cnblogs.com/blog/1541422/201905/1541422-20190505165136751-145842528.png"></p>
<p><span style="font-size: 16px">  可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,<span style="color: rgba(255, 0, 255, 1)">构造函数 F 就是新对象的类型</span>。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。&nbsp;</span></p>
<p><span style="font-size: 16px">  同样,JavaScript 中的内置对象在内部构建时也是这样做的,如下图所示。</span></p>
<p><span style="font-size: 16px"><img src="https://img2018.cnblogs.com/blog/1541422/201905/1541422-20190505170905439-795355374.png"></span></p>
<p><span style="font-size: 16px; color: rgba(255, 0, 255, 1)">  总结:</span></p>
<p><span style="font-size: 16px; color: rgba(255, 0, 255, 1)"> </span><span style="font-size: 16px"><span style="color: rgba(255, 0, 255, 1)"> </span>1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。</span></p>
<p><span style="font-size: 16px">  2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object。</span></p>
<p><span style="font-size: 14pt; color: rgba(255, 0, 0, 1)">四、toString</span></p>
<p><span style="font-size: 16px"><span style="color: rgba(0, 0, 0, 1)">  </span>toString() 是 Object 的原型方法,调用该方法,<span style="color: rgba(255, 0, 255, 1)">默认返回当前对象的 []</span> 。这是一个内部属性,其<span style="color: rgba(255, 0, 255, 1)">格式为 </span> ,其中 Xxx 就是对象的类型。</span></p>
<p><span style="font-size: 16px">  对于 Object 对象,直接调用 toString()&nbsp; 就能返回 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。</span></p>
<p><span style="font-size: 16px"> <span style="color: rgba(255, 0, 255, 1)"> 语法:Object.prototype.toString.call(value);</span></span></p>
<div class="cnblogs_code">
<pre>Object.prototype.toString.call('') ;   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(1) ;    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">true</span>) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(Symbol()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
Object.prototype.toString.call(undefined) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">null</span>) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Function()) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Date()) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call([]) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> RegExp()) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Error()) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(document) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
Object.prototype.toString.call(window) ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> window 是全局对象 global 的引用</span></pre>
</div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/gg-qq/p/10815109.html
頁: [1]
查看完整版本: JavaScript中准确的判断数据类型