javascript中判断数据类型
<p>编写javascript代码的时候常常要判断变量,字面量的类型,可以用typeof,instanceof,Array.isArray(),等方法,究竟哪一种最方便,最实用,最省心呢?本问探讨这个问题。</p><h1><span style="color: rgba(255, 102, 0, 1)"><strong>1. typeof</strong></span></h1>
<h2><span style="color: rgba(255, 102, 0, 1)"><strong>1.1 语法</strong></span></h2>
<p>typeof返回一个字符串,表示未经计算的操作数的类型。</p>
<p>语法:typeof(operand) | typeof operand<br>参数:一个表示对象或原始值的表达式,其类型将被返回<br>描述:typeof可能返回的值如下:</p>
<table style="height: 246px; width: 378px" border="0" align="center">
<tbody>
<tr>
<td>类型</td>
<td>结果</td>
</tr>
<tr>
<td>Undefined</td>
<td>“undefined”</td>
</tr>
<tr>
<td>Null</td>
<td>“object”</td>
</tr>
<tr>
<td>Boolean</td>
<td>“boolean”</td>
</tr>
<tr>
<td>Number</td>
<td>“number”</td>
</tr>
<tr>
<td>Bigint</td>
<td>“bigint”</td>
</tr>
<tr>
<td>String</td>
<td>“string”</td>
</tr>
<tr>
<td>Symbol</td>
<td>“symbol”</td>
</tr>
<tr>
<td>宿主对象(由JS环境提供)</td>
<td>取决于具体实现</td>
</tr>
<tr>
<td>Function对象</td>
<td>“function”</td>
</tr>
<tr>
<td>其他任何对象</td>
<td>“object”</td>
</tr>
</tbody>
</table>
<p>从定义和描述上来看,这个语法可以判断出很多的数据类型,但是仔细观察,typeof null居然返回的是“object”,让人摸不着头脑,下面会具体介绍,先看看这个效果:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 数值</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> 37) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> 3.14) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(42)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> Math.LN2) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> Infinity) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> NaN) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number 尽管它是Not-A-Number的缩写,实际NaN是数字计算得到的结果,或者将其他类型变量转化成数字失败的结果</span>
console.log(Number(1)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">number Number(1)构造函数会把参数解析成字面量</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> 42n) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">bigint</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 字符串</span>
console.log(<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)">string</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> 'boo') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> `template literal`) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
console.log(<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)">string 内容为数字的字符串仍然是字符串</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</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)">string,typeof总是返回一个字符串</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> String(1)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string String将任意值转换成字符串</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 布尔值</span>
console.log(<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>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">false</span>) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> boolean</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> Boolean(1)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> boolean Boolean会基于参数是真值还是虚值进行转换</span>
console.log(<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)"> boolean 两次调用!!操作想短语Boolean()</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Undefined</span>
console.log(<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>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> declaredButUndefinedVariabl) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 未赋值的变量返回undefined</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> undeclaredVariable ) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 未定义的变量返回undefined</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> {a: 1}) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object</span>
console.log(<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>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> /s/) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 正则表达式返回object</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 下面的例子令人迷惑,非常危险,没有用处,应避免使用,new操作符返回的实例都是对象</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Boolean(<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)"> object</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Number(1)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> object</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">new</span> String('abc')) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> object</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 函数</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> <span style="color: rgba(0, 0, 255, 1)">function</span> () {}) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> function</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> class C { }) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> function</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> Math.sin) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> function</span> </pre>
</div>
<h2><span style="color: rgba(255, 102, 0, 1)"><strong>1.2 迷之null</strong></span></h2>
<p>javascript诞生以来,typeof null都是返回‘object’的,这个是因为javascript中的值由两部分组成,一部分是表示<strong>类型的标签</strong>,另一部分是表示<strong>实际的值</strong>。对象类型的值类型标签是0,不巧的是null表示空指针,它的类型标签也被设计成0,于是就有这个typeof null === ‘object’这个‘恶魔之子’。</p>
<p>曾经有ECMAScript提案让typeof null返回‘null’,但是该提案被拒绝了。</p>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">1.3 使用new操作符</span></strong></h2>
<p>除Function之外所有构造函数的类型都是‘object’,如下:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">var</span> str = <span style="color: rgba(0, 0, 255, 1)">new</span> String('String'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> num = <span style="color: rgba(0, 0, 255, 1)">new</span> Number(100<span style="color: rgba(0, 0, 0, 1)">)
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> str) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> object</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> num) <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)">var</span> func = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Function()
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> func) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> function</span> </pre>
</div>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">1.4 语法中的括号</span></strong></h2>
<p>typeof运算的优先级要高于“+”操作,但是低于圆括号</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">var</span> iData = 99<span style="color: rgba(0, 0, 0, 1)">
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> iData + ' Wisen') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> number Wisen</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> (iData + 'Wisen')) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span> </pre>
</div>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">1.5 判断正则表达式的兼容性问题</span></strong></h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">typeof</span> /s/ === 'function'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Chrome 1-12 , 不符合 ECMAScript 5.1</span>
<span style="color: rgba(0, 0, 255, 1)">typeof</span> /s/ === 'object'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Firefox 5+ , 符合 ECMAScript 5.1</span> </pre>
</div>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">1.6 错误</span></strong></h2>
<p>ECMAScript 2015之前,typeof总能保证对任何所给的操作数都返回一个字符串,即使是没有声明,没有赋值的标示符,typeof也能返回undefined,也就是说使用typeof永远不会报错。</p>
<p>但是ES6中加入了块级作用域以及let,const命令之后,在变量声明之前使用由let,const声明的变量都会抛出一个ReferenceError错误,块级作用域变量在块的头部到声明变量之间是“暂时性死区”,在这期间访问变量会抛出错误。如下:</p>
<div class="cnblogs_code">
<pre> console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> undeclaredVariable) <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, 0, 1)">
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> newLetVariable) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ReferenceError</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> newConstVariable) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ReferenceError</span>
console.log(<span style="color: rgba(0, 0, 255, 1)">typeof</span> newClass) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ReferenceError</span>
<span style="color: rgba(0, 0, 0, 1)">
let newLetVariable
const newConstVariable </span>= 'hello'<span style="color: rgba(0, 0, 0, 1)">
class newClass{}</span> </pre>
</div>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">1.7 例外</span></strong></h2>
<p>当前所有浏览器都暴露一个类型为undefined的非标准宿主对象document.all。typeof document.all === 'undefined'。景观规范允许为非标准的外来对象自定义类型标签,单要求这些类型标签与已有的不同,document.all的类型标签为undefined的例子在web领域被归类为对原ECMA javascript标准的“故意侵犯”,可能就是浏览器的恶作剧。</p>
<p><strong>总结</strong>:typeof返回变量或者值的类型标签,虽然对大部分类型都能返回正确结果,但是对null,构造函数实例,正则表达式这三种不太理想。 </p>
<h1><strong><span style="color: rgba(255, 102, 0, 1)">2. instanceof</span></strong></h1>
<h2><span style="color: rgba(255, 102, 0, 1)"><strong>2.1 语法</strong></span></h2>
<p><strong>instanceof运算符</strong>用于检测实例对象(参数)的原型链上是否出现构造函数的prototype。</p>
<p>语法:object instanceof constructor<br>参数:object 某个实例对象<br> constructor 某个构造函数<br>描述:instanceof运算符用来检测constructor.property是否存在于参数object的原型链上。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义构造函数</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> C() {
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> D() {
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> o = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> C()
console.log(o </span><span style="color: rgba(0, 0, 255, 1)">instanceof</span> C) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true,因为Object.getPrototypeOf(0) === C.prototype</span>
console.log(o <span style="color: rgba(0, 0, 255, 1)">instanceof</span> D) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">false,D.prototype不在o的原型链上</span>
console.log(o <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, 0, 1)">
C.prototype </span>=<span style="color: rgba(0, 0, 0, 1)"> {}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> o2 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> C()
console.log(o2 </span><span style="color: rgba(0, 0, 255, 1)">instanceof</span> C) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log(o <span style="color: rgba(0, 0, 255, 1)">instanceof</span> C) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false C.prototype指向了一个空对象,这个空对象不在o的原型链上</span>
D.prototype = <span style="color: rgba(0, 0, 255, 1)">new</span> C() <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 继承</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> o3 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> D()
console.log(o3 </span><span style="color: rgba(0, 0, 255, 1)">instanceof</span> D) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log(o3 <span style="color: rgba(0, 0, 255, 1)">instanceof</span> C) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true C.prototype现在在o3的原型链上</span></pre>
</div>
<p>需要注意的是,如果表达式obj instanceof Foo返回true,则并不意味着该表达式会永远返回true,应为Foo.prototype属性的值可能被修改,修改之后的值可能不在obj的原型链上,这时表达式的值就是false了。另外一种情况,改变obj的原型链的情况,虽然在当前ES规范中,只能读取对象的原型而不能修改它,但是借助非标准的__proto__伪属性,是可以修改的,比如执行obj.__proto__ = {}后,obj instanceof Foo就返回false了。此外ES6中Object.setPrototypeOf(),Reflect.setPrototypeOf()都可以修改对象的原型。</p>
<p><strong>instanceof和多全局对象(多个iframe或多个window之间的交互)</strong></p>
<p>浏览器中,javascript脚本可能需要在多个窗口之间交互。多个窗口意味着多个全局环境,不同全局环境拥有不同的全局对象,从而拥有不同的内置构造函数。这可能会引发一些问题。例如表达式[] instanceof window.frames.Array会返回false,因为Array.prototype !== window.frames.Array.prototype。</p>
<p>起初,这样可能没有意义,但是当在脚本中处理多个frame或多个window以及通过函数将对象从一个窗口传递到另一个窗口时,这就是一个非常有意义的话题。实际上,可以通过Array.isArray(myObj)或者Object.prototype.toString.call(myObj) = ""来安全的检测传过来的对象是否是一个数组。</p>
<h2><strong><span style="color: rgba(255, 102, 0, 1)">2.2 示例</span></strong></h2>
<p>String对象和Date对象都属于Object类型(它们都由Object派生出来)。</p>
<p>但是,使用对象文字符号创建的对象在这里是一个例外,虽然原型未定义,但是instanceof of Object返回true。</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">var</span> simpleStr = "This is a simple string"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> myString= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> String();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> newStr = <span style="color: rgba(0, 0, 255, 1)">new</span> String("String created with constructor"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> myDate = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> myObj =<span style="color: rgba(0, 0, 0, 1)"> {};
</span><span style="color: rgba(0, 0, 255, 1)">var</span> myNonObj= Object.create(<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
console.log(simpleStr </span><span style="color: rgba(0, 0, 255, 1)">instanceof</span> String); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回 false,虽然String.prototype在simpleStr的原型链上,但是后者是字面量,不是对象</span>
console.log(myString<span style="color: rgba(0, 0, 255, 1)">instanceof</span> String); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回 true</span>
console.log(newStr <span style="color: rgba(0, 0, 255, 1)">instanceof</span> String); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回 true</span>
console.log(myString<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, 0, 1)">
console.log(myObj </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>
console.log(({})<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>
console.log(myNonObj <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)"> 返回 false, 一种创建非 Object 实例的对象的方法</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(myString </span><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)">返回 false</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log( myDate </span><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>
console.log(myDate <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>
console.log(myDate <span style="color: rgba(0, 0, 255, 1)">instanceof</span> String); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回 false</span> </pre>
</div>
<p><strong>注意:</strong>instanceof运算符的左边必须是一个对象,像"string" instanceof String,true instanceof Boolean这样的字面量都会返回false。</p>
<p>下面代码创建了一个类型Car,以及该类型的对象实例mycar,instanceof运算符表明了这个myca对象既属于Car类型,又属于Object类型。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Car(make, model, year) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.make =<span style="color: rgba(0, 0, 0, 1)"> make;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.model =<span style="color: rgba(0, 0, 0, 1)"> model;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.year =<span style="color: rgba(0, 0, 0, 1)"> year;
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> mycar = <span style="color: rgba(0, 0, 255, 1)">new</span> Car("Honda", "Accord", 1998<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> a = mycar <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Car; <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)">var</span> b = mycar <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><strong>不是...的实例</strong></p>
<p>要检测对象不是某个构造函数的实例时,可以使用!运算符,例如if(!(mycar instanceof Car))</p>
<p>instanceof虽然能够判断出对象的类型,但是必须要求这个参数是一个对象,简单类型的变量,字面量就不行了,很显然,这在实际编码中也是不够实用。</p>
<p><strong>总结</strong>:obj instanceof constructor虽然能判断出对象的原型链上是否有构造函数的原型,但是只能判断出对象类型变量,字面量是判断不出的。</p>
<h1><span style="color: rgba(255, 102, 0, 1)"><strong>3. Object.prototype.toString()</strong></span></h1>
<h2><span style="color: rgba(255, 102, 0, 1)"><strong>3.1. 语法</strong></span></h2>
<p>toString()方法返回一个表示该对象的字符串。</p>
<p>语法:obj.toString()<br>返回值:一个表示该对象的字符串<br>描述:每个对象都有一个toString()方法,该对象被表示为一个文本字符串时,或一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()方法被每个Object对象继承,如果此方法在自定义对象中未被覆盖,toString()返回“”,其中type是对象的类型,看下面代码:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">var</span> o = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();
console.log(o.toString()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns </span> </pre>
</div>
<p>注意:如ECMAScript 5和随后的Errata中所定义,从javascript1.8.5开始,toString()调用null返回,undefined返回</p>
<h2><span style="color: rgba(255, 102, 0, 1)"><strong>3.2. 示例</strong></span></h2>
<p><strong>覆盖默认的toString()方法</strong></p>
<p>可以自定义一个方法,来覆盖默认的toString()方法,该toString()方法不能传入参数,并且必须返回一个字符串,自定义的toString()方法可以是任何我们需要的值,但如果带有相关的信息,将变得非常有用。</p>
<p>下面代码中定义Dog对象类型,并在构造函数原型上覆盖toString()方法,返回一个有实际意义的字符串,描述当前dog的姓名,颜色,性别,饲养员等信息。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Dog(name,breed,color,sex) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.breed =<span style="color: rgba(0, 0, 0, 1)"> breed;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.color =<span style="color: rgba(0, 0, 0, 1)"> color;
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex =<span style="color: rgba(0, 0, 0, 1)"> sex;
}
Dog.prototype.toString </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> dogToString() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "Dog " + <span style="color: rgba(0, 0, 255, 1)">this</span>.name + " is a " + <span style="color: rgba(0, 0, 255, 1)">this</span>.sex + " " + <span style="color: rgba(0, 0, 255, 1)">this</span>.color + " " + <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.breed
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> theDog = <span style="color: rgba(0, 0, 255, 1)">new</span> Dog("Gabby", "Lab", "chocolate", "female"<span style="color: rgba(0, 0, 0, 1)">);
console.log(theDog.toString()) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Dog Gabby is a female chocolate Lab</span> </pre>
</div>
<h1><span style="color: rgba(255, 102, 0, 1)"><strong>4. 使用toString()检测数据类型</strong></span></h1>
<p>目前来看toString()方法能够基本满足javascript数据类型的检测需求,可以通过toString()来检测每个对象的类型。为了每个对象都能通过Object.prototype.toString()来检测,需要以Function.prototype.call()或者Function.prototype.apply()的形式来检测,传入要检测的对象或变量作为第一个参数,返回一个字符串""。</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> null undefined</span>
console.log(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>
console.log(Object.prototype.toString.call(undefined)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 很给力</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Number</span>
console.log(Object.prototype.toString.call(Infinity)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
console.log(Object.prototype.toString.call(Number.MAX_SAFE_INTEGER)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
console.log(Object.prototype.toString.call(NaN)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">,NaN一般是数字运算得到的结果,返回Number还算可以接受</span>
console.log(Object.prototype.toString.call(1)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
<span style="color: rgba(0, 0, 255, 1)">var</span> n = 100<span style="color: rgba(0, 0, 0, 1)">
console.log(Object.prototype.toString.call(n)) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
console.log(Object.prototype.toString.call(0)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
console.log(Object.prototype.toString.call(Number(1))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 很给力</span>
console.log(Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Number(1))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 很给力</span>
console.log(Object.prototype.toString.call('1')) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
console.log(Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> String('2'))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Boolean</span>
console.log(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>
console.log(Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Boolean(1))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Array</span>
console.log(Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Array(1))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
console.log(Object.prototype.toString.call([])) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Object</span>
console.log(Object.prototype.toString.call(<span style="color: rgba(0, 0, 255, 1)">new</span> Object())) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> foo() {}
let a </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> foo()
console.log(Object.prototype.toString.call(a)) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> </span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Function</span>
console.log(Object.prototype.toString.call(Math.floor)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
console.log(Object.prototype.toString.call(foo)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Symbol</span>
console.log(Object.prototype.toString.call(Symbol('222'))) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> RegExp</span>
console.log(Object.prototype.toString.call(/sss/)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"></span> </pre>
</div>
<p>上面的结果,除了NaN返回Number稍微有点差池之外其他的都返回了意料之中的结果,都能满足实际开发的需求,于是我们可以写一个通用的函数来检测变量,字面量的类型。如下:</p>
<div class="cnblogs_code">
<pre> let Type = (<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
let type </span>=<span style="color: rgba(0, 0, 0, 1)"> {};
let typeArr </span>= ['String', 'Object', 'Number', 'Array', 'Undefined', 'Function', 'Null', 'Symbol', 'Boolean', 'RegExp', 'BigInt'<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < typeArr.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (name) {
type[</span>'is' + name] = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (obj) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> Object.prototype.toString.call(obj) === ''<span style="color: rgba(0, 0, 0, 1)">
}
})(typeArr)
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> type
})()
let s </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
console.log(Type.isBoolean(s)) </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log(Type.isRegExp(/22/)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span> </pre>
</div>
<p>除了能检测ECMAScript规定的八种数据类型(七种原始类型,<strong>Boolean</strong>,<strong>Null</strong>,<strong>Undefined</strong>,<strong>Number</strong>,<strong>BigInt</strong>,<strong>String</strong>,<strong>Symbol</strong>,一种复合类型<strong>Object</strong>)之外,还能检测出正则表达式<strong>RegExp</strong>,<strong>Function</strong>这两种类型,基本上能满足开发中的判断数据类型需求。</p>
<h1><span style="color: rgba(255, 102, 0, 1)"><strong>5. 判断相等</strong></span></h1>
<p>既然说道这里,不妨说一说另一个开发中常见的问题,判断一个变量是否等于一个值。ES5中比较两个值是否相等,可以使用相等运算符(==),严格相等运算符(===),但它们都有缺点,== 会将‘4’转换成4,后者NaN不等于自身,以及+0 !=== -0。ES6中提出”Same-value equality“(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法,它用来比较两个值是否严格相等,与严格比较运算(===)行为基本一致。</p>
<div class="cnblogs_code">
<pre> console.log(5 == '5') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log(NaN == NaN) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span>
console.log(+0 == -0) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log({} == {}) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(</span>5 === '5') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span>
console.log(NaN === NaN) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span>
console.log(+0 === -0) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log({} === {}) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span></pre>
</div>
<p>Object.js()不同之处有两处,一是+0不等于-0,而是NaN等于自身,如下:</p>
<div class="cnblogs_code">
<pre> let a =<span style="color: rgba(0, 0, 0, 1)"> {}
let b </span>=<span style="color: rgba(0, 0, 0, 1)"> {}
let c </span>=<span style="color: rgba(0, 0, 0, 1)"> b
console.log(a </span>=== b) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false</span>
console.log(b === c) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span>
console.log(Object.is(b, c)) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true</span> </pre>
</div>
<p>注意两个空对象不能判断相等,除非是将一个对象赋值给另外一个变量,对象类型的变量是一个指针,比较的也是这个指针,而不是对象内部属性,对象原型等。</p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<p style="background-position: 1% 50%; border-top: #e0e0e0 1px dashed; border-right: #e0e0e0 1px dashed; border-bottom: #e0e0e0 1px dashed; border-left: #e0e0e0 1px dashed; padding-top: 10px; padding-right: 10px; padding-bottom: 10px; padding-left: 60px; background: #969696 url("https://images.cnblogs.com/cnblogs_com/lloydsheng/239039/o_copyright.gif") no-repeat 1% 50%; font-family: 微软雅黑; font-size: 12px; color: #FFFFFF">
作者:<b><span style="font-size: 12px; color: red">Tyler Ning</span></b>
<br>
出处:http://www.cnblogs.com/tylerdonet/
<br>
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,请微信联系<strong >冬天里的一把火
</strong>
<div class="van-overlay" style="display: none;z-index: 1;position: fixed;top: 0;left: 0;z-index: 1;width: 100%;height: 100%;background-color: rgba(0, 0, 0, 0.7);"></div>
<imgid="pop-contect-wechat" style="display:none;width:20em;position: fixed;max-height: 100%;overflow-y: auto;transition: transform 0.3s;" src="https://files-cdn.cnblogs.com/files/tylerdonet/shouwangzhe059187.bmp"/>
</p><br><br>
来源:https://www.cnblogs.com/tylerdonet/p/11852391.html
頁:
[1]