JavaScript数据类型判断的四种方法
<h3 id="码文不易啊转载请带上本文链接呀感谢感谢-httpswwwcnblogscomechoyyap14416375html">码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14416375.html</h3><p>本文分享了JavaScript类型判断的四种方法:<code>typeof</code>、<code>instanceof</code>、<code>Object.prototype.toString.call()</code>、<code>constructor</code></p>
<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14416375.html</li><li>一、typeof</li><li>二、instanceof</li><li>三、constructor</li><li>四、Object.prototype.toString.call()</li></ul></div><p></p>
<p><strong>JavaScript数据类型</strong></p>
<p>JavaScript有八种内置类型,除对象外,其他统称为<code>基本类型</code></p>
<ul>
<li>
<p>空值(null)</p>
</li>
<li>
<p>未定义(undefined)</p>
</li>
<li>
<p>布尔值(boolean)</p>
</li>
<li>
<p>数字(number)</p>
</li>
<li>
<p>字符串(string)</p>
</li>
<li>
<p>对象 (object)</p>
</li>
<li>
<p>符号(symbol, ES6中新增)</p>
</li>
<li>
<p>大整数(BigInt, ES2020 引入)</p>
</li>
</ul>
<blockquote>
<p>Symbol: 是ES6中引入的一种原始数据类型,表示独一无二的值。</p>
<p>BigInt:是 ES2020 引入的一种新的数据类型,用来解决 JavaScript中数字只能到 53 个二进制位(JavaScript 所有数字都保存成 64 位浮点数,大于这个范围的整数,无法精确表示的问题。具体可查看:新数据类型 — BigInt</p>
</blockquote>
<h3 id="一typeof">一、typeof</h3>
<p>typeof是一个<code>操作符</code>而不是函数,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示</p>
<p>包括以下 8 种:<strong>string、number、boolean、undefined、function 、symbol、bigInt、object。</strong></p>
<p>对于数组,对象,null以及时间等数据,typeof只能返回object,而不能直接返回对应的类型,还需要通过其他法判断。</p>
<pre><code>console.log(typeof ""); // string
console.log(typeof 1 ); // number
console.log(typeof NaN ); // number
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof function(){});// function
console.log(typeof isNaN); // function
console.log(typeof Symbol()); // symbol
console.log(typeof 123n); // bigint
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof null); // object
console.log(typeof new Date()); // object
console.log(typeof new RegExp());// object
</code></pre>
<h3 id="二instanceof">二、instanceof</h3>
<p>instanceof 是用来判断 <code>A 是否为 B 的实例</code>,表达式为:<code>A instanceof B</code>,如果 A 是 B 的实例,则返回 true,否则返回 false。 需特别注意:<code>instanceof 检测的是原型</code></p>
<p>即instanceof 用来比较一个对象是否为某一个构造函数的实例。<strong>instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型</strong></p>
<pre><code>console.log(12 instanceof Number); // false
console.log('22' instanceof String); // false
console.log(true instanceof Boolean); // false
console.log(null instanceof Object); // false
console.log(undefined instanceof Object); // false
console.log(function a() {} instanceof Function);// true
console.log([] instanceof Array); // true
console.log({a: 1} instanceof Object); // true
console.log(new Date() instanceof Date); // true
</code></pre>
<p>2021/3/8 补充:<br>
<code>instanceof 的原理</code>:主要的实现原理就是只要右边变量的 <strong>prototype</strong>在左边变量的原型链上即可。<br>
因此,instanceof 在查找的过程中会<code>遍历左边变量的原型链</code>,直到找到右边变量的 prototype,如果存在返回true 否则返回false</p>
<pre><code>function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}
</code></pre>
<p><strong>注意:</strong>instanceof 运算时会递归查找<strong>leftVaule</strong>的原型链,即<code>leftVaule.__proto__.__proto__.__proto__.__proto__...</code> 直到找到了或者找到顶层为止。</p>
<p>一句话理解其运算规则:<code>instanceof</code> 检测左侧的 <code>__proto__</code> 原型链上,是否存在右侧的<code> prototype</code> 原型。</p>
<h3 id="三constructor">三、constructor</h3>
<ol>
<li>JavaScript中,每个对象都有一个constructor属性,可以得知某个实例对象,到底是哪一个构造函数产生的, constructor属性表示原型对象与构造函数之间的关联关系。</li>
</ol>
<ul>
<li>
<p>当一个函数F被定义时,JS引擎会为F添加prototype原型,然后在prototype上添加一个constructor属性,并让其指向F的引用,F利用原型对象的constructor属性引用了自身,当F作为构造函数创建对象时,原型上的constructor属性被遗传到了新创建的对象上,从原型链角度讲,构造函数F就是新对象的类型。这样做的意义是,让对象诞生以后,就具有可追溯的数据类型。</p>
</li>
<li>
<p>通过typeof运算符来判断它是原始的值还是对象。如果是对象,就可以使用constructor属性来判断其类型。</p>
</li>
<li>
<p>如判断数组的函数:</p>
</li>
</ul>
<pre><code>function isArray(data){
return typeof data == "object" && data.constructor == Array;
}
isArray([])// true
</code></pre>
<blockquote>
<p>注意:null 和 undefined 是没有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。</p>
</blockquote>
<pre><code>console.log('22'.constructor === String) // true
console.log(true.constructor === Boolean) // true
console.log([].constructor === Array) // true
console.log(document.constructor === HTMLDocument) // true
console.log(window.constructor === Window) // true
console.log(new Number(22).constructor === Number) // true
console.log(new Function().constructor === Function) // true
console.log(new Date().constructor === Date) // true
console.log(new RegExp().constructor === RegExp) // true
console.log(new Error().constructor === Error) // true
</code></pre>
<ol start="2">
<li>如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。所以,修改原型对象时,一般要同时修改constructor属性的指向。</li>
</ol>
<pre><code>function Rectangle(width, height){
this.width = width;
this.height = height;
this.getArea = function(){
return '矩形的面积为' + (width * height);
}
}
var rect1 = new Rectangle(40, 20);
var rect2 = new Rectangle(50, 20);
var rect3 = new Rectangle(60, 20);
console.log(rect1.getArea());
console.log(rect2.getArea());
console.log(rect3.getArea());
</code></pre>
<ul>
<li>
<p><strong>如上代码,每次实例化出一个对象,都会添加getArea方法,是三个对象共有且不变的,因此将getArea放在构造函数中就会在创建对象时被多次添加,浪费内存!</strong></p>
</li>
<li>
<p><strong>因此我们将getArea添加到原型对象上就减少了多次添加</strong>,<strong>实例化对象会沿着原型链查找到此属性</strong></p>
</li>
<li>
<p><strong>实现了共享属性:</strong></p>
</li>
</ul>
<pre><code>function Rectangle(width, height){
this.width = width;
this.height = height;
}
// 直接替换原型对象,但是要记得添加上构造函数属性
Rectangle.prototype = {
constructor: Rectangle,
getArea: function(){
return '矩形的面积为' + (this.width * this.height);
}
}
// 修改特性
Object.defineProperties(Rectangle.prototype, {
constructor: {
enumerable: false,
configurable: false,
writable: false
},
getArea: {
enumerable: false,
configurable: false,
writable: false
}
})
var rect1 = new Rectangle(40, 20);
var rect2 = new Rectangle(50, 20);
var rect3 = new Rectangle(60, 20);
console.log(rect1.getArea());
console.log(rect2.getArea());
console.log(rect3.getArea());
</code></pre>
<ol start="3">
<li>很多情况下,我们可以使用instanceof运算符或对象的constructor属性来检测对象是否为数组。如很多JS框架就是使用这两种方法来判断对象是否为数组类型。 但是检测在跨框架(cross-frame)页面中的数组时,会失败。原因就是在不同框架(iframe)中创建的数组不会相互共享其prototype属性。例如:</li>
</ol>
<pre><code> <script>
window.onload=function(){
var iframe_arr=new window.frames.Array;
console.log(iframe_arr instanceof Array); // false
console.log(iframe_arr.constructor == Array); // false
}
</script>
</code></pre>
<h3 id="四objectprototypetostringcall">四、Object.prototype.toString.call()</h3>
<ul>
<li>
<p><code>Object.prototype.toString(o)</code>是 Object 的原型方法,</p>
<ol>
<li>
<p>获取对象o的class属性。这是一个内部属性,</p>
</li>
<li>
<p>连接字符串:,格式为 ,其中 Xxx 就是对象的类型。</p>
</li>
</ol>
</li>
<li>
<p>对于 Object 对象,直接调用 toString() 就能返回 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。</p>
</li>
</ul>
<pre><code>console.log(Object.prototype.toString.call(1)) //
console.log(Object.prototype.toString.call(1n)) //
console.log(Object.prototype.toString.call('123')) //
console.log(Object.prototype.toString.call(true)) //
console.log(Object.prototype.toString.call(undefined))//
console.log(Object.prototype.toString.call(null)) //
console.log(Object.prototype.toString.call({})) //
console.log(Object.prototype.toString.call([])) //
console.log(Object.prototype.toString.call(function a() {}))//
console.log(Object.prototype.toString.call(Symbol())) //
console.log(Object.prototype.toString.call(Math)) //
console.log(Object.prototype.toString.call(JSON)) //
console.log(Object.prototype.toString.call(new Date())) //
console.log(Object.prototype.toString.call(new RegExp())) //
console.log(Object.prototype.toString.call(new Error)) //
console.log(Object.prototype.toString.call(window) //
console.log(Object.prototype.toString.call(document)) //
</code></pre>
<ul>
<li>封装一个准确判断数据类型的函数</li>
</ul>
<pre><code>function __getType(object){
return Object.prototype.toString.call(object).match(/^\$/);
};
</code></pre>
<ul>
<li>可以解决上面的跨框架问题。</li>
</ul>
<pre><code><script>
window.onload=function(){
var iframe_arr=new window.frames.Array;
console.log(Object.prototype.toString.call(iframe_arr)))// ""
}
</script>
</code></pre><br><br>
来源:https://www.cnblogs.com/echoyya/p/14416375.html
頁:
[1]